| 1 | # Sub-Agents |
| 2 | |
| 3 | Sub-agents are background instances of the agent loop. The parent |
| 4 | agent spawns one with a focused task, gets back an `agent_id` |
| 5 | immediately, and continues working while the sub-agent runs to |
| 6 | completion. Sub-agents inherit the parent's tool registry by default |
| 7 | and run with `CancellationToken::child_token()`, so cancelling the |
| 8 | parent cancels every descendant. |
| 9 | |
| 10 | This doc covers the role taxonomy. For the orchestration tool surface |
| 11 | (`agent_spawn` / `agent_wait` / `agent_result` / `agent_cancel` / |
| 12 | `agent_list` / `agent_send_input` / `agent_resume` / `agent_assign`) |
| 13 | see `prompts/base.md` "Sub-Agent Strategy" and the in-line tool |
| 14 | descriptions. |
| 15 | |
| 16 | ## Role taxonomy |
| 17 | |
| 18 | The `agent_type` field on `agent_spawn` selects a system-prompt |
| 19 | posture for the child. Each role is a distinct stance toward the |
| 20 | work — not just a different label. |
| 21 | |
| 22 | | Role | Stance | Writes? | Runs shell? | Typical use | |
| 23 | |---------------|----------------------------------------|---------|-------------|----------------------------------------------| |
| 24 | | `general` | flexible; do whatever the parent says | yes | yes | the default; multi-step tasks | |
| 25 | | `explore` | read-only; map the relevant code fast | no | yes (read) | "find every call site of `Foo`" | |
| 26 | | `plan` | analyse and produce a strategy | minimal | minimal | "design the migration; don't execute" | |
| 27 | | `review` | read-and-grade with severity scores | no | no | "audit this PR for bugs" | |
| 28 | | `implementer` | land a specific change with min edit | yes | yes | "rewrite `bar.rs::Foo::bar` to do X" | |
| 29 | | `verifier` | run tests / validation, report outcome | no | yes (test) | "run cargo test --workspace, report" | |
| 30 | | `custom` | explicit narrow tool allowlist | depends | depends | locked-down dispatch with hand-picked tools | |
| 31 | |
| 32 | Each role's full system prompt lives in |
| 33 | `crates/tui/src/tools/subagent/mod.rs` (search for |
| 34 | `*_AGENT_PROMPT`). The prompt prefix loads automatically when the |
| 35 | child agent boots; the parent's spawn prompt becomes the first |
| 36 | turn's user message. |
| 37 | |
| 38 | ### When to pick which role |
| 39 | |
| 40 | - **`general`** — when the task is "do this whole thing", not "go |
| 41 | look", "design", or "verify". This is the right default; reach for |
| 42 | a more specific role only when the posture matters. |
| 43 | - **`explore`** — when the parent needs evidence before deciding what |
| 44 | to do next. Explorers are cheap and fast; spawn 2–3 in parallel |
| 45 | for independent regions. |
| 46 | - **`plan`** — when the parent has an objective but no executable |
| 47 | decomposition. Planners write artifacts (`update_plan` rows, |
| 48 | `checklist_write` entries) but don't carry them out. |
| 49 | - **`review`** — when there's already a change and the parent wants |
| 50 | it graded. Reviewers don't patch — they describe the fix in the |
| 51 | finding so the parent can dispatch an Implementer if the verdict |
| 52 | is "fix it". |
| 53 | - **`implementer`** — when the change is already specified and just |
| 54 | needs to land. Implementers stay tightly scoped: minimum edit, no |
| 55 | drive-by refactoring, run a quick verification before handing back. |
| 56 | - **`verifier`** — when the parent needs an authoritative pass/fail |
| 57 | on the test suite or other validation. Verifiers don't fix |
| 58 | failures; they capture the failing assertion + stack and put fix |
| 59 | candidates under RISKS. |
| 60 | - **`custom`** — only when the parent needs to constrain the tool |
| 61 | set explicitly. Pass the allowlist via the `allowed_tools` field |
| 62 | on `agent_spawn`. |
| 63 | |
| 64 | ### Aliases |
| 65 | |
| 66 | The model can spell each role multiple ways: |
| 67 | |
| 68 | | Canonical | Aliases | |
| 69 | |---------------|------------------------------------------------------------------| |
| 70 | | `general` | `worker`, `default`, `general-purpose` | |
| 71 | | `explore` | `explorer`, `exploration` | |
| 72 | | `plan` | `planning`, `awaiter` | |
| 73 | | `review` | `reviewer`, `code-review` | |
| 74 | | `implementer` | `implement`, `implementation`, `builder` | |
| 75 | | `verifier` | `verify`, `verification`, `validator`, `tester` | |
| 76 | | `custom` | (none; explicit `allowed_tools` array required) | |
| 77 | |
| 78 | All matching is case-insensitive. Unknown values produce a typed |
| 79 | error listing the accepted set, so the model can self-correct on |
| 80 | the next turn. |
| 81 | |
| 82 | ## Concurrency cap |
| 83 | |
| 84 | The dispatcher caps concurrent sub-agents at 10 by default |
| 85 | (configurable via `[subagents].max_concurrent` in `~/.deepseek/config.toml`, |
| 86 | hard ceiling 20). When the parent hits the cap, `agent_spawn` returns |
| 87 | an error with the cap value; the parent should `agent_wait` for |
| 88 | completion or `agent_cancel` to free a slot before retrying. |
| 89 | |
| 90 | The cap counts only **running** agents — completed / failed / |
| 91 | cancelled records persist for inspection but don't occupy a slot. |
| 92 | Agents that lost their `task_handle` (e.g. across a process |
| 93 | restart) also don't count against the cap. |
| 94 | |
| 95 | ## Lifecycle |
| 96 | |
| 97 | Each spawn produces a record that progresses through: |
| 98 | |
| 99 | ``` |
| 100 | Pending → Running → (Completed | Failed(reason) | Cancelled | Interrupted(reason)) |
| 101 | ``` |
| 102 | |
| 103 | `Interrupted` fires when the manager detects a `Running` agent |
| 104 | whose task handle is gone — typically after a process restart that |
| 105 | loaded the agent from `~/.deepseek/subagents.v1.json`. The parent |
| 106 | can `agent_resume` to attempt continuation or treat it as a |
| 107 | terminal state. |
| 108 | |
| 109 | ### Session boundaries (#405) |
| 110 | |
| 111 | Each `SubAgentManager` instance assigns itself a fresh |
| 112 | `session_boot_id` on construction. Every spawn stamps the agent |
| 113 | with that id; the persisted state file carries it across restarts. |
| 114 | |
| 115 | `agent_list` defaults to **current-session only**: prior-session |
| 116 | agents that aren't still running are filtered out. Pass |
| 117 | `include_archived=true` to surface every record, with the |
| 118 | `from_prior_session: true` flag so the model can tell archived |
| 119 | records apart from live ones. |
| 120 | |
| 121 | Records that loaded from a pre-#405 persisted state file (no |
| 122 | `session_boot_id` field) classify as prior-session because the |
| 123 | manager can't match them to the current boot. |
| 124 | |
| 125 | ## Output contract |
| 126 | |
| 127 | Every sub-agent produces a final result string with five sections, |
| 128 | in order: |
| 129 | |
| 130 | ``` |
| 131 | SUMMARY: one paragraph; what you did and what happened |
| 132 | CHANGES: files modified, with one-line descriptions; "None." if read-only |
| 133 | EVIDENCE: path:line-range citations and key findings; one bullet each |
| 134 | RISKS: what could go wrong / what the parent should double-check |
| 135 | BLOCKERS: what stopped you; "None." if you finished cleanly |
| 136 | ``` |
| 137 | |
| 138 | The exact format lives in `crates/tui/src/prompts/subagent_output_format.md`. |
| 139 | The parent reads `EVIDENCE` as a working set for the next turn, so |
| 140 | explorers and reviewers should be precise here. |
| 141 | |
| 142 | ## Memory and the `remember` tool (#489) |
| 143 | |
| 144 | Sub-agents inherit the parent's memory file when memory is enabled |
| 145 | (`[memory] enabled = true` or `DEEPSEEK_MEMORY=on`). They can |
| 146 | append durable notes via the `remember` tool — handy for an |
| 147 | explorer that discovers a project convention worth carrying across |
| 148 | sessions, or a verifier that learns "this test is flaky". |
| 149 | |
| 150 | Memory writes are scoped to the user's own `memory.md` file; they |
| 151 | don't go through the standard write-approval flow. |
| 152 | |
| 153 | ## Implementation notes |
| 154 | |
| 155 | - Source: `crates/tui/src/tools/subagent/mod.rs` (about 3500 LOC). |
| 156 | - Persisted state: `~/.deepseek/subagents.v1.json`. Schema version |
| 157 | `1` (forward-compatible — new optional fields use |
| 158 | `#[serde(default)]`). |
| 159 | - The `is_running` check ignores agents whose `task_handle` is |
| 160 | `None`; this avoids counting persisted-but-detached records |
| 161 | toward the concurrency cap (#509). |
| 162 | - `SharedSubAgentManager` is `Arc<RwLock<...>>` — read paths use |
| 163 | read locks so `/agents` and the sidebar projection don't block |
| 164 | the main loop during multi-agent fan-out (#510). |
| 165 |