# Subagent Delegation

HooCode delegates focused work to specialized **subagents** that run in isolated
child processes. Delegation is **description-driven**: the parent agent decides
when to delegate and which agent to use, based on each agent's `description`.
There is no deterministic keyword router and no blocking dispatch gate.

## How Delegation Works

The parent agent has a `Task` tool whose description lists the available agents
(see the registry below). The model chooses an agent via `subagent_type` and
passes a self-contained `prompt`. The subagent runs in a fresh context and only
its final answer is returned to the parent.

Guidance baked into the parent prompt:

- Delegate self-contained units where you only need the final result.
- Prefer handling small, quick, or single-file work inline.
- The subagent cannot see the parent conversation — pass all needed context in
  `prompt`.

The `DispatchEvaluator` no longer routes. It survives only to:

1. **Enforce the nesting cap** — a process may delegate only while its
   `HOOCODE_SUBAGENT_DEPTH` is below the tree-wide cap `HOOCODE_SUBAGENT_MAX_DEPTH`
   (seeded from the `maxSubagentDepth` setting, default `1`). At the default cap a
   subagent cannot spawn further subagents.
2. **Record a complexity estimate** in `.hoocode/dispatch/<task_id>/dispatch-log.json`
   for diagnostics. This is a cheap heuristic, not a routing decision.

## Available Agents

Agents are defined by frontmatter `.md` files loaded from a registry with
precedence **project > user > built-in**:

- Built-in: `templates/agents/*.md` (`explore`, `plan`, `general-purpose`) — matching
  Claude Code's built-in roster. `explore` and `plan` are strictly read-only;
  `general-purpose` is the delegating agent (`delegate: true`). Ship task-specialized
  agents (edit, review, etc.) yourself under `.hoocode/agents/` or `.claude/agents/`.
- Project: `.hoocode/agents/`, and `.claude/agents/` (Claude Code compatible)
- User: `~/.hoocode/agents/`, and `~/.claude/agents/`

Each definition supplies `name`, `description`, and optional `tools`, `model`,
`maxTurns`, `background`, and `delegate`. When a definition omits `tools`, the
subagent inherits all parent tools (Claude Code behavior).

## Forcing a Subagent with `/subagent`

In interactive mode you can dispatch a subagent directly, bypassing the model's
decision (the mode is still validated against the registry):

```
/subagent explore "How does the auth middleware work?"
/subagent general-purpose "Add a --json flag to the export command and update its tests"
```

## Execution Model

Subagents run as isolated `hoocode` **child processes**, managed by `SubagentPool`.
Each delegation:

1. Spawns `hoocode --mode json --session <file> --task-id <id> [--system-prompt <prompt>] [--tools <allowlist>] --max-turns <n> <prompt>` (re-running the current runtime/entry, so it works from `dist/`, from source via tsx, or as a packaged binary).
2. Runs under a hard turn cap (`--max-turns`, default 50). Near the cap the agent is asked to wrap up; at the cap it stops and returns a `partial` result instead of failing.
3. Emits a periodic `{"ping":true}` heartbeat on stdout; the lifeguard SIGKILLs a child that goes silent for 60s and enforces a per-mode hard timeout.
4. On exit, writes `.hoocode/dispatch/<task_id>/result.json` (summary, files_changed, confidence, status, usage), which the parent verifies before accepting the result.

The tool returns only the subagent's `summary` to the calling agent.

## Background and Resume

- An agent definition can set `background: true`. The `Task` tool then dispatches it detached and returns a `task_id` immediately. The `TaskOutput` tool polls by `task_id` and collects the final answer once finished.
- Subagents persist their session to `.hoocode/dispatch/<task_id>/session.jsonl`. Pass `resume_task_id` to the `Task` tool to continue a previous run with a follow-up `prompt` (full prior transcript intact). Partial results surface their resume handle.

Concurrency is bounded (default 5). Parallelism happens when the model issues
multiple `Task` calls; there is no batch-dispatch API.

## Guardrails

- **Token budget is advisory.** It emits `budget_warning` (80%) and `budget_exceeded` (100%) for telemetry but never kills or fails a subagent; the turn cap is the guaranteed hard stop.
- **Bounded nesting (default: none).** Nesting is capped by `maxSubagentDepth` (default `1`). The root seeds the cap into `HOOCODE_SUBAGENT_MAX_DEPTH`; each spawned child is stamped with its depth (`HOOCODE_SUBAGENT_DEPTH` = parent + 1). The `Task`/`TaskOutput` tools are registered only while a process's depth is below the cap, and the `DispatchEvaluator` enforces the same bound as defense in depth — so at the default cap subagents cannot recursively dispatch. When the cap is raised, nested pools (depth ≥ 1) run with a reduced concurrency so the worst-case live process count stays a fixed function of depth (e.g. `5 + 5×2 = 15` at depth 2), with no shared state to leak on crash.
- **Delegation is opt-in per agent.** A subagent only receives the `Task` tool when its agent definition sets `delegate` *and* it is spawned below the cap (`childDepth < maxSubagentDepth`). On spawn, such an agent has `Task`/`TaskOutput` added to its tool allowlist and `--enable-subagents` propagated, so it can dispatch one further level. Every other agent keeps its declared sandbox and cannot delegate, preserving the deliberate "Task is not a normal tool" boundary. `delegate: true` permits any subagent type; `delegate: explore, plan` scopes it to those types (forwarded as `--delegate-allow`; the Task tool rejects out-of-scope dispatches). See `examples/agents/orchestrator.md` for a ready-to-use delegating agent.

  To exercise depth-2 end to end: drop the orchestrator into a discovered agents dir (e.g. `.hoocode/agents/`), then run with `--enable-subagents --max-subagent-depth 2` and delegate to it. A `[DISPATCH] … depth=2 …` line confirms a subagent delegated. That line is written to stderr only when no TUI owns the terminal (`--print`, RPC, CI) — in an interactive session it would corrupt the differential render, so check `.hoocode/dispatch/<task_id>/dispatch-log.json` (which carries the same `depth`) or set `HOOCODE_DEBUG_AGENT_LOG=1` to tee it to `hoocode-debug.log`.
- The pool prioritizes `explore` and `review` tasks over `doc` tasks because they often block downstream work.
- On completion, the subagent writes `.hoocode/dispatch/<task_id>/result.json` (verified by the parent) and the pool writes `.hoocode/dispatch/<task_id>/output.json` (raw process outcome).
