# task > Launch subagents for parallel, optionally isolated work. ## Source - Entry: `packages/coding-agent/src/task/index.ts` - Model-facing prompt: `packages/coding-agent/src/prompts/tools/task.md` - Key collaborators: - `packages/coding-agent/src/task/types.ts` — dynamic schema, progress/result types, output caps. - `packages/coding-agent/src/task/discovery.ts` — discover project/user/plugin/bundled agents. - `packages/coding-agent/src/task/agents.ts` — bundled agent definitions and frontmatter parsing. - `packages/coding-agent/src/task/executor.ts` — create child sessions, run subagents, collect output. - `packages/coding-agent/src/task/parallel.ts` — concurrency-limited scheduling and async semaphore. - `packages/coding-agent/src/task/isolation-backend.ts` — isolation backend resolution and platform fallback. - `packages/coding-agent/src/task/worktree.ts` — worktree / FUSE / ProjFS setup, patch capture, branch merge. - `packages/coding-agent/src/task/output-manager.ts` — session-scoped `agent://` id allocation. - `packages/coding-agent/src/task/simple-mode.ts` — `default` / `schema-free` / `independent` field gating. - `packages/coding-agent/src/internal-urls/agent-protocol.ts` — resolve `agent://` to saved subagent output. - `packages/coding-agent/src/tools/index.ts` — tool registration and recursion-depth gating. - `packages/coding-agent/src/sdk.ts` — child-session router/tool wiring and per-subagent `AgentOutputManager`. - `docs/task-agent-discovery.md` — deeper discovery and precedence notes. - `docs/handoff-generation-pipeline.md` — session artifact/handoff persistence patterns used by the wider session layer. ## Inputs ### Default mode (`task.simple = "default"`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `agent` | `string` | Yes | Exact agent name for every task item. Resolved at execution time through `discoverAgents(...)`. | | `tasks` | `Array<{ id: string; description: string; assignment: string }>` | Yes | Batch of small, self-contained task items. `id` max length 48 in schema; duplicate ids are rejected case-insensitively at runtime. | | `context` | `string` | No | Shared background prepended to every subagent system prompt. Trimmed before use. | | `schema` | `string` | No | JSON-encoded JTD schema. Overrides agent/session output schema when this mode allows task-level schemas. | | `isolated` | `boolean` | No | Only present when the tool is created with isolation enabled. Requests isolated execution for the whole batch. | `tasks[].description` is UI-only. `tasks[].assignment` is the actual per-task instruction. ### Schema-free mode (`task.simple = "schema-free"`) Same as default, except `schema` is rejected by `validateTaskModeParams(...)` in `packages/coding-agent/src/task/index.ts`. ### Independent mode (`task.simple = "independent"`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `agent` | `string` | Yes | Exact agent name. | | `tasks` | `Array<{ id: string; description: string; assignment: string }>` | Yes | Same item shape, but each `assignment` must carry all required background because shared `context` is disabled. | | `isolated` | `boolean` | No | Same conditional field as above. | In this mode both `context` and `schema` are rejected. ## Outputs The tool returns one text block plus `details: TaskToolDetails`. `details` fields: - `projectAgentsDir: string | null` — nearest discovered project `agents/` dir. - `results: SingleResult[]` — one entry per task in input order for synchronous execution; empty for async-launch responses. - `totalDurationMs: number` - `usage?: Usage` — sum of per-subagent assistant-message usage. - `outputPaths?: string[]` — written `.md` artifact paths for completed subagent outputs. - `progress?: AgentProgress[]` — live or final per-task progress snapshots. - `async?: { state: "running" | "completed" | "failed"; jobId: string; type: "task" }` — present for background execution updates/results. `SingleResult` includes: - identity: `index`, `id`, `agent`, `agentSource`, `description`, optional `assignment` - status: `exitCode`, optional `error`, optional `aborted`, optional `abortReason` - output: `output`, `stderr`, `truncated`, `durationMs`, `tokens` - artifact metadata: `outputPath?`, `patchPath?`, `branchName?`, `nestedPatches?`, `outputMeta?` - extracted tool data: `extractedToolData?` from registered subprocess tool handlers such as `yield` and `report_finding` Artifacts and side channels: - Every subagent with an artifacts dir writes `.md`; `agent://` resolves to that file. - If the output file is JSON, `agent:///` and `agent://?q=` perform JSON extraction in `packages/coding-agent/src/internal-urls/agent-protocol.ts`. - When the parent session persists artifacts, each subagent also gets `.jsonl` session history. - Isolated patch mode writes `.patch` per successful task before merge. - Async mode returns immediately after job registration, then emits `onUpdate(...)` progress snapshots and later hands completion to the session async-job pipeline. ## Flow 1. `TaskTool.create(...)` in `packages/coding-agent/src/task/index.ts` calls `discoverAgents(session.cwd)` once to build the dynamic prompt description from current agents and `task.simple` capabilities. 2. `execute(...)` validates mode-gated fields with `validateTaskModeParams(...)`. 3. It decides async vs sync: - sync when `async.enabled` is false - sync when the selected cached agent has `blocking === true` - sync when `tasks.length === 0` - otherwise async job scheduling 4. Async path: - allocate unique output ids with `AgentOutputManager.allocateBatch(...)` - create one async job per task through `session.asyncJobManager.register(...)` - limit concurrent job bodies with `Semaphore(task.maxConcurrency)` from `packages/coding-agent/src/task/parallel.ts` - each job body calls `#executeSync(...)` with a one-task batch and the preallocated id - `onUpdate(...)` emits aggregate `progress` snapshots and `details.async` 5. Sync path (`#executeSync(...)`) rediscovers agents from disk via `discoverAgents(...)`, so runtime resolution can differ from the earlier prompt description. 6. It resolves the requested agent with `getAgent(...)`, rejects unknown or disabled agents, and enforces parent spawn policy plus `PI_BLOCKED_AGENT` self-recursion prevention. 7. It derives the effective output schema in priority order: task call `schema` (if allowed) → agent frontmatter `output` → inherited parent session schema. 8. It validates task ids: missing ids and case-insensitive duplicates are immediate errors. 9. If `isolated` was requested, it requires a git repo (`getRepoRoot(...)` / `captureBaseline(...)`) and resolves the actual backend through `resolveIsolationBackendForTaskExecution(...)`. 10. It chooses an artifacts dir from the parent session when available, otherwise a temp dir, and writes `context.md` there when `session.getCompactContext?.()` returns content. 11. It allocates unique ids again if the caller did not preallocate them, then builds `tasksWithUniqueIds`. 12. For each task, it seeds an `AgentProgress` entry and runs `runTask(...)` through `mapWithConcurrencyLimit(...)` using `task.maxConcurrency`. 13. Non-isolated `runTask(...)` calls `runSubprocess(...)` directly with parent cwd. 14. Isolated `runTask(...)`: - creates an isolation workspace (`ensureWorktree(...)`, `ensureFuseOverlay(...)`, or `ensureProjfsOverlay(...)`) - applies the captured baseline for worktrees - runs `runSubprocess(...)` inside that workspace - on success, either commits to a per-task branch (`mergeMode === "branch"`) or captures a patch with `captureDeltaPatch(...)` - always cleans up the isolation workspace/backend 15. `runSubprocess(...)` in `packages/coding-agent/src/task/executor.ts` creates a child agent session with: - isolated settings snapshot via `Settings.isolated(...)`, forcing `async.enabled = false` and `bash.autoBackground.enabled = false` - child `agentId` / `parentTaskPrefix` equal to the allocated task id - child internal URL router and `AgentOutputManager` from `packages/coding-agent/src/sdk.ts` - the shared `context`, optional `context.md` reference, optional isolation worktree path, output schema, and IRC peer roster in the system prompt template 16. Child tool availability is derived from the agent definition plus runtime guards: - explicit `agent.tools` if provided - auto-add `task` when the agent has `spawns` and recursion depth allows it - remove `task` at or past `task.maxRecursionDepth` - expand `exec` to `eval` and `bash` - strip parent-owned `todo` after session creation 17. `runSubprocess(...)` subscribes to child agent events, coalesces progress updates every 150 ms, forwards lifecycle/progress events on the parent event bus, and extracts tool data through `subprocessToolRegistry`. 18. The child must finish through the hidden `yield` tool. If it does not, `runSubprocess(...)` sends up to 3 reminder prompts; the last reminder forces `toolChoice = yield` when supported. 19. Finalization uses `finalizeSubprocessOutput(...)` to reconcile raw assistant text, `yield` payloads, structured schemas, `report_finding` data, and abort states. Output is truncated with `MAX_OUTPUT_BYTES` / `MAX_OUTPUT_LINES` before returning to the parent, but the full raw output is still written to `.md`. 20. After all sync tasks finish, `#executeSync(...)` aggregates usage, collects artifact paths, and if isolation was used merges results back: - branch mode: cherry-pick per-task branches with `mergeTaskBranches(...)`, then delete merged branches with `cleanupTaskBranches(...)` - patch mode: combine non-empty patch artifacts, dry-check with `git.patch.canApplyText(...)`, then apply or leave manual artifacts - nested repo patches are applied separately with `applyNestedPatches(...)` 21. The final text summary is rendered from `packages/coding-agent/src/prompts/tools/task-summary.md` and includes `agent://` handles for outputs that exist. ## Modes / Variants - Execution mode - Sync inline execution — default path. - Async background execution — one async job per task item when `async.enabled` is on and the chosen agent is not marked `blocking`. - Simple mode - `default` — accepts shared `context` and per-call `schema`. - `schema-free` — accepts `context`, rejects `schema`. - `independent` — rejects `context` and `schema`; each assignment stands alone. - Isolation backend - `none` — no isolation. - `worktree` — detached git worktree plus baseline replay. - `fuse-overlay` — Unix FUSE overlay mount. - `fuse-projfs` — Windows ProjFS overlay. - Isolation merge strategy - Patch mode — capture/apply root patches, keep patch artifacts when application fails. - Branch mode — commit each task onto `omp/task/` branch, cherry-pick into parent, preserve failed branches for manual resolution. - Agent source - Project custom agents — nearest project config/plugin agent directories, first by source-family precedence. - User custom agents — user config/plugin agent directories after project dirs of the same source family. - Bundled agents — appended last from `packages/coding-agent/src/task/agents.ts`. - Bundled agent types - `explore` — read-only scout with structured handoff output. - `plan` — architecture/planning agent; may spawn `explore`. - `designer` — UI/UX specialist. - `reviewer` — review agent with `report_finding` extraction. - `task` — general-purpose worker with full capabilities. - `quick_task` — low-reasoning mechanical worker using the same task prompt body. - `librarian` — source-grounded external API/library researcher. - `oracle` — senior-engineer implementation/debugging/general consultation agent. ## Side Effects - Filesystem - Writes `context.md`, `.jsonl`, and `.md` under the session artifacts dir or a temp task dir. - In isolated patch mode writes `.patch` artifacts. - Creates/removes worktrees or overlay mount directories. - In branch mode creates temporary worktrees and task branches. - Network - Child sessions may use whichever networked tools/models their active tool set permits. - MCP proxy tools can call existing parent MCP connections with a 60_000 ms timeout. - Subprocesses / native bindings - `fuse-overlayfs` and `fusermount`/`fusermount3` for FUSE isolation. - ProjFS native bindings via `@oh-my-pi/pi-natives` on Windows. - Git operations for baseline capture, patch apply, worktrees, branches, stash, cherry-pick, commits. - Session state (transcript, memory, jobs, checkpoints, registries) - Creates child `AgentSession` instances with isolated settings snapshots. - Registers async jobs in `session.asyncJobManager` for background task mode. - Emits `task:subagent:event`, `task:subagent:progress`, and `task:subagent:lifecycle` on the parent event bus. - Allocates session-scoped output ids through `AgentOutputManager` so `agent://` remains unique across invocations and resumes. - Shares the parent `local://` root with subagents by passing `localProtocolOptions` through `createAgentSession(...)`. - User-visible prompts / interactive UI - Async mode streams aggregate progress updates. - Missing-`yield` recovery sends up to three internal reminder prompts to the child session. - Final summaries include `` blocks for isolation fallbacks or merge failures. - Background work / cancellation - Parent abort stops scheduling new work, aborts active child sessions, and marks unscheduled tasks as skipped. - Async jobs keep their own cancellation via `AsyncJobManager`. ## Limits & Caps - Per-subagent output truncation: `MAX_OUTPUT_BYTES = 500_000` and `MAX_OUTPUT_LINES = 5000` in `packages/coding-agent/src/task/types.ts`. Full raw output is still written to `.md` before truncation is returned to the caller. - Progress coalescing in child execution: `PROGRESS_COALESCE_MS = 150` in `packages/coding-agent/src/task/executor.ts`. - Recent output tail for progress: `RECENT_OUTPUT_TAIL_BYTES = 8 * 1024` and `recentOutput` keeps the last 8 non-empty lines in `packages/coding-agent/src/task/executor.ts`. - Missing-`yield` reminder retries: `MAX_YIELD_RETRIES = 3` in `packages/coding-agent/src/task/executor.ts`. - MCP proxy timeout: `MCP_CALL_TIMEOUT_MS = 60_000` in `packages/coding-agent/src/task/executor.ts`. - Task id schema cap: `tasks[].id` `maxLength: 48` in `packages/coding-agent/src/task/types.ts`. - Prompt text says ids should be `≤32` chars, but the runtime schema allows 48; this mismatch is real. - Async/full sync parallelism both use `task.maxConcurrency` from settings: - sync path: `mapWithConcurrencyLimit(...)` - async path: `Semaphore(...)` around job bodies - Recursion depth gate: `task.maxRecursionDepth` from settings; `packages/coding-agent/src/tools/index.ts` hides the `task` tool at or beyond the limit, and `runSubprocess(...)` also strips child `task` access at max depth. - Final inline summary preview per task uses `fullOutputThreshold = 5000` chars in `packages/coding-agent/src/task/index.ts`; longer outputs are summarized while `agent://` points to the full artifact. ## Errors - Most validation failures are returned as normal tool text with empty `results`, not thrown: - invalid simple-mode fields - unknown/disabled agent - missing tasks - missing/duplicate task ids - spawn-policy denial - requesting `isolated` while isolation mode is `none` - Isolated execution without a git repo returns `Isolated task execution requires a git repository. ...`. - Backend resolution can return a hard error (`ProjFS isolation initialization failed...`) or a non-fatal warning with fallback to `worktree`. - `mapWithConcurrencyLimit(...)` fails fast on non-abort worker exceptions; already completed results are preserved only in the thrown path’s local state, not surfaced unless the caller catches and converts them. - Child-session failures surface as `SingleResult.exitCode = 1` with `stderr`/`error` populated. - If the child omits `yield`, `finalizeSubprocessOutput(...)` injects warnings such as `SYSTEM WARNING: Subagent exited without calling yield tool after 3 reminders.` - Async scheduling failures are accumulated per task; if no jobs start, the tool returns `Failed to start background task jobs: ...`. - `agent://` resolution errors are model-visible when another tool reads them: no session, no artifacts dir, missing id, conflicting extraction syntax, or invalid JSON for extraction. ## Notes - Agent discovery precedence is first-wins by exact name: project dirs before user dirs within a source family, plugin agent dirs after config dirs, bundled agents last. See `packages/coding-agent/src/task/discovery.ts` and `docs/task-agent-discovery.md`. - `TaskTool.create(...)` caches discovered agents only for description rendering and the async blocking-agent decision. `#executeSync(...)` rediscovers agents each call. - Custom agent frontmatter can override bundled agents by name. Bundled definitions are embedded at build time in `packages/coding-agent/src/task/agents.ts`. - Child sessions do not inherit conversation history automatically. The only built-in carry-over is shared `context`, optional `context.md`, workspace tree/skills/context files, and shared `local://` root. - `Settings.isolated(...)` gives each child a session-isolated settings snapshot; tool enablement is recomputed inside the child session rather than sharing mutable parent tool state. - When the parent passes `mcpManager`, child sessions disable standalone MCP discovery and instead get proxy tools that reuse the parent connections. - Plan mode mutates an `effectiveAgent` with a read-only tool subset and plan-mode prompt text, but `runSubprocess(...)` is still invoked with `agent` rather than `effectiveAgent`. Model/thinking/schema overrides use the effective agent; prompt/tool/spawn restrictions do not fully flow through this call path. - Branch-mode merge temporarily stashes the parent repo before cherry-picking task branches. A stash-pop conflict is treated as merge failure and leaves recovery state behind. - Patch-mode only applies combined root patches if every successful task produced a patch and `git.patch.canApplyText(...)` succeeds. - Nested git repos are handled separately from the root repo. They are copied into isolated worktrees, diffed independently, and merged later with `applyNestedPatches(...)` because parent git cannot track their file-level changes. - `agent://` ids are name-based (`Task` first, `Task-2`/`Task-3` only when the name repeats, nested like `Parent.Child`) by `AgentOutputManager`; this is what prevents artifact collisions across repeated or nested task invocations.