dsh-hogwarts-loop
DiscoveredHogwarts-loop as a DeepSeek Harness plugin: per-role subagents on configurable models, with a client settings page.
dsh-hogwarts-loop
Plan → build → review → commit, as a DeepSeek Harness plugin. One subagent per cast member, each dispatched on its own configurable model.
@dyikai/dsh-hogwarts-loop packages the hogwarts-loop discipline: take a large engineering effort from a plan to reviewed, committed code in small, independently verified checkpoints. The methodology ships as a skill, every cast member is a managed subagent started through one tool, and the model behind each role is set in the client instead of being baked into the prompt.
What it adds
| Capability | Form | Where it lives |
|---|---|---|
| The loop methodology and each role's detailed duties | the hogwarts-loop skill (also triggerable as /hogwarts-loop) | skill/SKILL.md, skill/references/*.md |
| Start one cast member on that role's configured model | the hogwarts_dispatch tool | registered by index.js |
| Edit provider / model / effort / output cap per role | Settings → Hogwarts Loop, plus the Plugins page row for this plugin | client.js (browser half) |
// one call = one role = that role's configured model
hogwarts_dispatch({ role: "harry", description: "checkpoint 3 build", prompt: "<full brief>" })
hogwarts_dispatch({ role: "severus", description: "review checkpoint 3", prompt: "<full brief>" })
hogwarts_dispatch returns a child id immediately and does not wait. The child's result arrives later as a completion notice in the main session.
Install
Requires Node.js ≥ 20 and a DeepSeek Harness profile.
From the Add plugin wizard
Type @dyikai/dsh-hogwarts-loop into the Add plugin wizard's search box and click Install.
With the dsh CLI
dsh plugin --profile web add @dyikai/dsh-hogwarts-loop
dsh web
No build step and no restart, but see the reload note below.
From a local checkout
plugin_manager -> { action: "install_bundle", target: "<path-to-this-repo>" }
To uninstall:
plugin_manager -> { action: "remove_bundle", target: "@dyikai/dsh-hogwarts-loop" }
After installing — or after changing client.js — reload the page once so the browser half loads and the settings section appears. The host half reassembles together with the plugin row.
Use it
The plugin is not a task and has no start button. Once installed it is always present, providing three things: the hogwarts_dispatch tool, the hogwarts-loop skill, and the settings page. "Making it work" means triggering the skill, which in turn directs the main agent to dispatch. The plugin stays loaded even when nobody triggers it.
Three ways in:
- Call the skill directly — type
/hogwarts-loopand its content is injected into the current session. - Say what you want — "plan this milestone with the hogwarts loop, then implement, review and commit each checkpoint". The skill carries a description, so the model also loads it by itself when a task matches.
- Dispatch once by hand — "use
hogwarts_dispatchto send harry to do X". This uses the plugin directly and skips the checkpoint / review discipline in the skill.
How to tell it is really working:
- a
hogwarts_dispatchtool call shows up in the session; list_agentslists the cast member you dispatched;- the child's session log records
agentModelandconfig.modelequal to that role's configured route (for exampleharryondeepseek-flash,severusondeepseek-v4-pro), not the main session's model.
Configure the cast
Settings → Hogwarts Loop (the settings entry at the bottom of the sidebar) is the main entry. It registers as a settings.section with order 60.
The same form has a second entry point: Plugins → Installed plugins → @dyikai/dsh-hogwarts-loop → the hogwarts-loop row → Configure (plugins.row.config).
The page lists every cast member, one row each: provider and model are dropdowns fed by the host's model catalog (remote.session.modelCatalog(), grouped per provider); switching the provider switches the model to that provider's first entry. Reasoning effort is a dropdown built from the levels the selected model actually supports (blank = the model default), and the max output tokens field may be left empty. Below them, Dispatch settings holds the subagent backend and the delegation depth cap.
Save writes every change as a single atomic, version-fenced mutate to this plugin's row in the current profile. The next dispatch uses it immediately — no reinstall and no restart.
Defaults (the behaviour when nothing is overridden):
| Role | Seat | Default model |
|---|---|---|
harry | implementer (writes the code, runs the gates) | deepseek-flash |
severus | reviewer (correctness lead; read-only) | deepseek-v4-pro |
alastor | security specialist | deepseek-v4-pro |
filius | performance specialist | deepseek-flash |
minerva | concurrency specialist | deepseek-flash |
argus | closeout UI walkthrough | deepseek-flash |
voldemort | escalation implementer (one escalated problem only) | deepseek-v4-pro |
Escalation: Voldemort
Harry gets at most three attempts at a problem (one attempt = one build → gate → review round). If all three fail — the gate is still red, or Severus keeps raising the same root cause as P1 — the problem is escalated once to voldemort. The escalation brief must carry the checkpoint acceptance criteria, what each of the three attempts changed, the exact failure evidence for each, and the possibilities already ruled out.
Voldemort is exactly the same implementer as Harry: same checkpoint scope, same gates, same "green tree plus raw evidence", and he does not commit either. The only differences are a stronger model and the history of three failed attempts. His mandate is one specific problem, not the whole checklist: he changes what that problem needs, he does not take over the remaining checkpoints, he does not "clean up while he is here", and once the problem is fixed and has passed Severus, control returns to Harry. He gets at most two attempts, and his work must also pass Severus before it is committed. If both fail, the loop stops: report the problem, the five attempts (3 + 2), the evidence, what was ruled out, and the options — no fourth Harry, no third Voldemort, and no quietly widening the scope to turn the gates green.
These two numbers live in the Escalation section of skill/SKILL.md — the skill text is the rule. The cast itself is defined by DEFAULT_ROLES in index.js.
The form writes this plugin's profile row (the
hogwarts-loopentry incordis.patch.yml). Editing that row'sconfigby hand or in bulk works too; the field definitions are theConfigexport inindex.js.
Albus is you — the main session. Its model is chosen by the session's model picker and is not controlled by this plugin; the plugin only decides the route of every subagent it dispatches.
Why the form looks like this
- The form registers twice — in the settings panel's
settings.sectionand in the Plugins page'splugins.row.config(key@dyikai/dsh-hogwarts-loop#hogwarts-loop) — and both render the sameFormBody. - The settings-panel entry resolves this plugin's namespace through the shared
settings.describemirror (matching thehogwarts-loopsuffix, so aninclude:prefix still works) and then gets a version-fenced write handle viactx.configForms.get(ns). The Plugins entry receives the boundformdirectly from the page, so it never has to guess a namespace. - On the host side,
Configmarks the two top-level objectsdelegationandrolesas.volatile()(schemastery cannot nest volatile, so the reference has to sit on the object). That is both what makes the settings service treat the entry as editable and serve the settings panel, and what guarantees dispatch reads the current value rather than a snapshot taken when the plugin activated. - When the model catalog cannot be read (expired login, failed catalog request), the same fields fall back to text inputs instead of breaking the page.
- A wrong model is never a silent failure:
hogwarts_dispatchvalidates the route before dispatching, and returns the error as a tool error with the list of currently registered providers.
Verify the routing
After dispatching a role, the child's session log records the real route. Session directories live under ~/.dsh/sessions/<encoded-cwd>/<childId>/, where <encoded-cwd> is the project path with separators turned into dashes:
node -e '
const fs = require("node:fs"), zlib = require("node:zlib");
const base = `${process.env.HOME}/.dsh/sessions/<encoded-cwd>/<childId>`;
const f = fs.readdirSync(base).find((n) => n.endsWith(".zstd"));
const ev = zlib.zstdDecompressSync(fs.readFileSync(`${base}/${f}`))
.toString("utf8").split("\n").filter(Boolean).map(JSON.parse);
console.log(ev.find((e) => e.type === "subagent/descriptor")?.data);
console.log(ev.find((e) => e.type === "request/header")?.data.header.config);
'
Expect agentModel / config.model to equal that role's configured model.
Repository layout
.
├── package.json # @dyikai/dsh-hogwarts-loop; dsh.bundle.patch + dsh.client
├── cordis.patch.yml # inserts the hogwarts-loop row
├── index.js # host half: Config schema, skill registration, hogwarts_dispatch
├── client.js # browser half: per-role config form in Settings and on the Plugins page
├── locale/{en,zh}.json # plugin name and description in the Plugin Manager
├── icon.svg # plugin icon
└── skill/
├── SKILL.md # the loop overview + "dispatch with hogwarts_dispatch"
├── references/*.md # planner / implementer / reviewer / loop / example
└── assets/plan-template.md
Known limits
- The settings entry is a page the plugin registers itself (
settings.section), not a form the host auto-generates fromConfig— that renderer does not exist in this client version yet (autoGenerateis not consumed by any built-in client). hogwarts_dispatchdispatches withspawn(a fresh subagent).fork-style backends inherit the parent session's route to reuse the KV cache and therefore cannot retarget the model, so this plugin does not supportfork.delegation.maxDepthdefaults to1: a child cannot dispatch further down.- Children join the parent session's current agent preset and use its tools.
- The plugin is profile-level: install it once and every session in this profile sees
hogwarts_dispatchand thehogwarts-loopskill.
License
Comments
Loading…
Similar plugins
by 0lidaxiang
DeepSeek Harness is a plugin-based system for building AI agents. Everything, from tools and models to the web UI, can be added or replaced as a plugin.
★ 4
↓ 62/wk
MIT
JavaScript
Oct 7, 2026
dsh plugin --profile web add dsh-plugin-greetby CypherNaught-0x
Deepseek Harness plugin that allows automatic delegation of subtasks to different models based on user preferences
★ 8
MIT
JavaScript
Sep 17, 2026
dsh plugin --profile web add dsh-subagent-model-routerby bpc-oss
DeepSeek Harness plugin: subagent_routed — run a one-shot subagent fully mounted on ANY agent preset from ANY session, with per-call model/provider override and a model-availability pre-check.
★ 3
MIT
JavaScript
Sep 12, 2026
dsh plugin --profile web add dsh-routed-subagentby euuuuuuzer
A loop dock for DeepSeek Harness: one harness, multiple agent loops.
★ 6
MIT
JavaScript
Aug 16, 2026
dsh plugin --profile web add dsh-loop-dockby exoticknight
One sentence to an AI agent: create, release and list a DeepSeek Harness plugin. DSH 插件模板与 AI 操作手册
★ 3
Apache-2.0
JavaScript
Oct 16, 2026
dsh plugin --profile web add dsh-plugin-templateby SnowAmberX
Role-based model routing plugin for DeepSeek Harness: planner/subagent roles plus a settings card and composer summary
★ 4
↓ 194/wk
BSD-3-Clause
TypeScript
Sep 19, 2026
dsh plugin --profile web add @snowamberx/dsh-role-router