Delegate independent tasks to subagents while keeping the main conversation focused on coordination and results. Kit supports Kit, Claude Code, Codex, Cursor, and other compatible harnesses through the Agent Client Protocol (ACP).
A subagent is a reusable Runlet value, not a detached background task: start it with subagent, continue the same session with prompt, branch its completed context with fork, list retained handles with subagents({}), or terminate one with close.
The prompt argument to subagent, prompt, and fork accepts either a string or an ordered array of ACP content blocks:
child = subagent({
prompt: [
{ type: "text", text: "Review this interface against the requirements." },
{ type: "resource_link", uri: "file:///project/src/interface.rs", name: "interface.rs", mimeType: "text/x-rust" },
{ type: "resource", resource: { uri: "file:///project/requirements.txt", mimeType: "text/plain", text: "Keep existing callers compatible." } }
]
})
return child.output
textandresource_linkrequire no optional child capability. A resource link refers to a URI the child can access; Kit does not read the URI or copy the file automatically. A local file must be accessible to the child in its own filesystem.- Embedded
resourceblocks contain aresourceobject withuri, optionalmimeType, and eithertextor base64blob. They require the child'spromptCapabilities.embeddedContextcapability. imageblocks contain base64data,mimeType, and an optionaluri. They require the child'spromptCapabilities.imagecapability. These are ACP blocks, not Kit managed File references; the parent's session-authorized File references are not transferred to the child.
Kit rejects unsupported content rather than silently converting it to text or dropping it. The array must be nonempty. Block order and metadata are preserved.
Keep Kit as the orchestrator and route only a bounded task to a specialist. The parent can start independent specialists concurrently, give each child explicit context, require structured output, continue a useful session, or fork an alternative. This makes the specialist's result composable with shell commands, edits, tests, MCP calls, and other agents in the same Runlet program.
An external harness remains a separate program with its own configuration, tools, account, and usage limits. Kit does not turn a Claude subscription into provider credentials for the built-in acp.kit harness. The @agentclientprotocol/claude-agent-acp package includes the Claude Agent SDK CLI, so it does not require a separate Claude Code installation. Authenticate that adapter out of band with either a Claude subscription or Anthropic Console. With --claudeai, work counts against subscription limits instead of metered Console API billing; whether that costs less depends on the workload and plan. This also lets you choose a model for work where it is particularly effective—for example, Claude Opus for visual and graphic design—without moving the whole coding session out of Kit.
Configure a descriptive alias for that route:
[acp.claude]
command = "npx"
args = ["-y", "@agentclientprotocol/claude-agent-acp@0.69.0"]
permissions = "allow"
[subagent.harnesses."acp.claude".models]
designer = "opus"Then ask for the configured specialist explicitly:
design = subagent({
name: "Visual Designer",
harness: "acp.claude",
model: "designer",
prompt: "Review the existing dashboard and propose a coherent visual direction for the new analytics view. Return design guidance, not code."
})
return design.output
designer is a Kit-side alias for the model ID advertised by that ACP adapter. The external harness must accept the configured ID. Before starting the first Claude subagent, authenticate the adapter outside Kit:
npx -y @agentclientprotocol/claude-agent-acp@0.69.0 --cli auth login --claudeai # Claude subscription
# Use --console instead for Anthropic Console API billing.When a child reports auth_required, Kit reports the advertised authentication methodId values (and a methodId supplied by the error), so you can identify the login method. Log in to that harness outside Kit, then retry the subagent call. Kit does not execute advertised terminal authentication commands or forward authentication error messages and arbitrary data, which may contain secrets.
Kit does not perform this login. You can start Kit before authenticating the adapter; authentication only needs to finish before the subagent starts.
Use the object form of the hidden tools inside compose:
first = subagent({
name: "Implementer",
cwd: "../parser-worktree",
prompt: "Inspect the parser and identify the smallest risk."
})
second = prompt({
subagent: first,
prompt: "Now propose a minimal fix."
})
branch = fork({
subagent: second,
name: "Alternative Reviewer",
prompt: "Explore an alternative without changing the original session."
})
return { main: second.output, alternative: branch.output }
Each successful turn returns a session value with id, name, output, and generation. subagent creates an ID at generation 1. prompt keeps that ID and name while incrementing its generation. fork creates a different ID and uses its own preferred or fallback name; its generation is one greater than the supplied source value, and it does not advance the source session. Close a session with either close(value) or close({ id: value.id }); the latter is useful when only an ID is available. Closing an unknown ID fails with unknown subagent session. Kit sends ACP session/close when the harness advertises it. Explicit close also sends session/delete when advertised, removing the discarded branch’s persistent history after closing it. Delete failures are reported rather than silently ignored. Process shutdown and internal cleanup do not delete persistent history; this preserves completed child sessions for restart recovery. A standalone process without that capability is terminated when its handle is dropped. If native-fork siblings share a process and the harness cannot close one logical session, close fails rather than claiming success or disrupting the siblings.
prompt accepts { id }, the subagent's ID string, or any value returned for it, and always targets the session's current state. fork copies a completed turn, so pass it the latest completed value; an older value fails with stale subagent generation N; current generation is M. Prompt and fork calls on an individual ACP session are serialized, while separate forked sessions can be prompted concurrently.
The optional name argument is preferred on subagent and fork; prompt has no naming input and preserves the session name. The optional harness, model, and cwd arguments belong only on subagent. harness overrides the user's configured harness preference. model selects an exact model value ID advertised by that harness through its ACP session configuration, or a model alias configured for that harness. cwd selects the new subagent's working directory; relative paths resolve from Kit's working directory, and missing paths or non-directories fail before startup. Omit an argument to retain its configured default. prompt and fork retain the original session's harness, model, and working directory. An explicit model fails before the first prompt if the harness does not advertise a selectable model option or rejects the value.
prompt({ subagent, prompt }) delivers a message however the subagent's current state allows, and returns the subagent's value once the turn that handled the message ends:
- An idle subagent, including one whose last turn failed, starts a new turn.
- A working subagent receives the message within its current turn when its harness supports ACP v2
steerinjection. The call then returns that turn's value. - A working subagent without steering support, or one that is still starting or being forked, receives the message in a new turn after its current work ends.
An output_schema applies to a new turn only, so a prompt with one always waits for the current turn to end. While the originating compose is backgrounded, subagents({}) lists the IDs and statuses of working children:
return prompt({
subagent: { id: "s-…" },
prompt: "Keep the change limited to the parser; do not modify the public API."
})
The prompt accepts text or ACP content blocks. Unknown and retired IDs fail. Cancelling the call stops waiting, but does not revoke a message already injected into a working turn.
The calling model should give each new subagent and fork a concise role-oriented display name based on its task, such as Round 2 Implementer or Reviewer. The name is display metadata and never changes the prompt sent to the child. Omitting name, or supplying an invalid name, uses the lowest available Agent N label.
Kit trims preferred names and accepts 1–32 bytes of printable ASCII. Names compare case-insensitively among one parent's direct live children; clashes receive the lowest available numeric suffix, with the base shortened as needed to stay within 32 bytes. The immutable s-… ID remains authoritative; names never select handles.
Names remain assigned while a child is reusable. Separate descendant branches can have duplicate display names, so use the session ID to select a child.
Use subagents({}) to inspect live direct children. Each row contains id, name, status, generation, and the bounded current task summary. Closed and terminally retired children are omitted.
The terminal client's agent roster shows subagent status, current activity, and elapsed time. Activity may describe a running tool, plan, or task, depending on what the harness reports. Use it to monitor progress; an idle child can be continued with prompt. For navigation and inspection, see Monitor subagents in the agent roster.
When a harness reports context usage over ACP, the row shows the same percent used/size readout as the header on a separate line below the activity excerpt. Kit's own ACP server always reports it, so nested Kit subagents show usage without configuration.
When every subagent runs on acp.kit, rows carry no harness mark. Once the roster mixes harnesses, each row gains a one-cell mark next to its name: a blue k for Kit, ✱ for Claude, ◎ for Codex, ◇ for OpenCode, ◈ for Copilot, ▸ for Cursor, π for Pi, ◭ for Antigravity, and · when the launch line names none of them. Kit infers the mark from the configured profile's command and arguments, matching whole tokens such as claude-agent-acp or codex-acp; the [acp.<name>] label itself is not consulted.
Pass a JSON Schema object or boolean to any turn-producing call:
review = subagent({
prompt: "Review the proposed change.",
output_schema: {
type: "object",
properties: {
approved: { type: "boolean" },
reason: { type: "string" }
},
required: ["approved", "reason"],
additionalProperties: false
}
})
return { approved: review.output.approved, reason: review.output.reason }
Kit validates output_schema before dispatch and appends instructions asking the child for one bare JSON value. If the response parses and validates, output is that JSON value. If a completed response is malformed, wrapped in Markdown, or does not match the schema, output falls back to the raw response text. The turn still succeeds and its generation advances, so a later prompt can request a repair. A later prompt or fork may use a different schema. Runlet treats output dynamically; it does not statically derive field types from the schema. An explicit null schema is invalid and reports output_schema must be a JSON Schema object or boolean.
Without output_schema, output is text. A turn that emits selected non-text agent-message content, tool calls, tool-call updates, or plans also returns a sibling field:
{
id: "...",
output: "Completed review",
generation: 1,
updates: { items: [...], truncated: false }
}
Text-only turns omit updates. Capture is limited to 64 update objects and 64 KiB of serialized update data per turn. Excess or oversized updates are omitted and set updates.truncated to true. When an ACP tool update's rendered content is only a JSON copy of its structured rawOutput, Kit retains rawOutput and replaces the duplicate content with an empty array. This preserves the update's explicit replacement of earlier rich content. Kit also captures usage (including reported cumulative session cost), session info, available commands, notices, compaction lifecycle updates, and compaction summary chunks. These remain separate from the final answer text. Usage values describe context occupancy, not billable token deltas; cumulative costs must not be summed across updates. Kit does not add child costs to parent billing totals. Child thoughts, user-message echoes, modes, and configuration are not exposed through this value. Session titles and context usage also feed the live agent roster independently of these capture limits; thoughts are not forwarded as activity text.
After a successful child turn, ACP clients receive the child's final diff and terminal content on the existing subagent, prompt, or fork tool card. Content updates replace earlier snapshots; content chunks append. V1 file snapshots also map to v2 file changes. Native v2 diffs without complete before/after text remain v2-only, as do agent-owned terminals. Child terminal output is replayed at completion, not streamed live; terminal IDs are scoped to the parent invocation. Kit does not execute captured terminal commands. Missing exit information remains unknown, and incomplete terminal captures carry kit/outputIncomplete metadata. Display is limited to 64 rich content items, with the same metadata marking additional display truncation. Raw child output and captured terminal IDs are not rewritten by this display projection. Failed or cancelled child turns do not publish a completion snapshot.
acp.kit is always available and is the default when [subagent].harness is not configured. By default Kit launches the installed kit executable as kit acp, whose default stdio protocol is ACP v1. A built-in child uses subagent.cwd when provided and otherwise inherits Kit's working directory; it also inherits the provider, model, MCP configuration and credential storage, cancellation, and nesting depth. An explicit subagent.model selection overrides the inherited model for that ACP session. It does not start an A2A listener.
You can override only the executable and base arguments while preserving built-in Kit behavior:
[acp.kit]
command = "kit"
args = ["acp"]Kit supplies the child’s runtime settings automatically. Use kit --help and kit acp --help to check the installed command interface when configuring an executable override.
Kit's ACP server also advertises a separate reasoning-effort session selector with Default, Low, Medium, and High values. Changes take effect on the next turn without changing the selected model. Default leaves the effort unset, preserving provider defaults and OPENROUTER_REASONING_EFFORT when OpenRouter supplies one. Set the startup default with top-level reasoning_effort or --reasoning-effort; the bundled TUI exposes the same selector through /effort. Built-in acp.kit children inherit the startup value resolved from CLI and TOML, while generic ACP harnesses keep their own behavior.
Reopen the same parent session to recover its completed child handles:
kit tui --root /path/to/project --resume <parent-session-id>Ask the parent to list its children with subagents({}), then continue the selected child by ID:
return prompt({
subagent: { id: "s-…" },
prompt: "Check the current project state, then continue the review."
})
Kit reconnects when you prompt or natively fork a restored child, using the current harness configuration. Recovery continues the same mutable child session; it does not create a snapshot or a replacement branch. Closing the parent releases child processes without deleting their history.
Recovery has these limits:
- Only persistent parents can recover completed child handles after restart. Older transcripts without saved child handles cannot reconstruct them, and a parent never adopts unrelated sessions.
- Interrupted turns are not automatically retried. Inspect project state before repeating work because edits or other side effects may already have occurred.
- Explicitly closed children are not restored, even if deleting their remote history failed.
- Child recovery requires retained history and a harness that supports session loading or resuming. If the harness was removed, cannot restore sessions, or lost its history, reconnect fails instead of silently creating a replacement. Restore the harness configuration or explicitly close the obsolete handle.
- Storage must be available before mutable child prompts or explicit deletion can proceed. If storage is full, follow storage recovery.
- If closing a child reports that reconnect is still starting, retry after startup completes or is cancelled.
- Use a Kit version that understands the saved transcript schema; older readers may reject child-state records.
Kit offers ACP v2 with its client name and version during initialization, uses the version selected by the child, and falls back to ACP v1 when selected. Unsupported versions fail before a session is opened. Generic external child harnesses must speak newline-delimited JSON-RPC over stdio and support initialize, session/new, and session/prompt. session/fork is optional. session/close is optional in v1 and baseline for v2 sessions. Kit does not advertise filesystem or terminal services to children. Keep stdout protocol-only; the agent may log to stderr. Kit runs the executable directly from the subagent's selected working directory, which defaults to Kit's working directory, and inherits the parent environment. It does not invoke a shell, so pipes, environment assignments, compound commands, and shell quoting in command or args do not work.
Configure trusted argv profiles in ~/.kit/config.toml:
[acp.review]
command = "review-agent"
args = ["acp"]
permissions = "allow"
[subagent]
harness = "acp.review"References use the fully qualified acp.<name> form. Profile names must be non-empty and contain neither whitespace nor dots. command must be non-empty; use an executable on PATH or an absolute path. Kit does not perform a generic agent's login or ACP authentication flow, so authenticate and configure that agent before starting Kit. Generic session persistence beyond the parent process is agent-defined. Per-subagent model selection works for generic agents such as Codex, Claude, or Cursor only when their ACP adapter advertises and implements the selectable model session option.
An unknown selection fails with unknown ACP harness "acp.name" or unknown subagent ACP harness "acp.name". Invalid references may report ACP harness references must use acp.<name>.
Set trusted initial options per harness in the subagent profile:
[subagent.harnesses."acp.review".config_options]
thought_level = "high"
mode = "code"
auto_compact = trueValues must be strings for ACP select options or booleans for ACP boolean options.
Use the child's advertised option ID. If no ID matches, Kit accepts an unambiguous
advertised category such as thought_level (which may map to reasoning_effort).
Missing, ambiguous, or incompatible options fail startup; a child rejection also
fails startup rather than silently using its default. Option names and accepted
values depend on the harness. Model selection continues to use the dedicated
model argument and alias/allowlist policy, not config_options.
Kit applies an explicit model first, then profile options in key order, using the updated option list returned after each selection. Native forks inherit the child's current configuration; they do not reset it to profile defaults. A model explicitly selected for the source is reapplied to its forks. Fallback forks start a new child and apply the profile again.
Returned updates.items includes the latest complete config_option_update
snapshot advertised by the child, including changes received between prompts.
Snapshots replace earlier state rather than merging option lists. They share the
existing bounded update budget: Kit prioritizes the latest snapshot over earlier
activity updates and sets updates.truncated when content cannot fit. A single
oversized snapshot is omitted. This is child-reported state, not an assertion
that the child accepted an unrequested or unsupported setting.
Model namespaces differ between ACP harnesses. Configure aliases and explicit-override policy under the fully qualified harness reference:
[subagent]
harness = "acp.review"
[subagent.harnesses."acp.review"]
allow_model_overrides = ["provider:model-a", "provider:model-b"]
[subagent.harnesses."acp.review".models]
review = "provider:model-a"
fast = "provider:model-b"A call may use either a configured alias or an exact model ID. Aliases are scoped to one harness, resolve before ACP startup, and are then checked against that harness's allow_model_overrides. Kit rejects configuration when an alias resolves outside its harness's allowlist.
Omitting allow_model_overrides allows all explicit model selections accepted by the harness. An empty list disables all explicit model overrides for that harness. The allowlist applies only when subagent.model is present; it does not inspect or restrict the harness's inherited or default model. Configured aliases indicate available routing choices, not recommendations. Agents should omit harness and model unless the user or active workflow explicitly requests an exact override or configured alias.
Kit reads fork capability from the child's ACP initialize response at runtime. The built-in Kit ACP server advertises native session/fork, so current Kit children fork in-process. If a child does not advertise it:
acp.kitclones a sanitized completed transcript and starts an isolated Kit process for the branch. This compatibility fallback applies to older Kit executables and to[acp.kit]overrides whose executable/base arguments do not expose native fork.- A generic profile fails with
ACP harness "acp.name" does not advertise session/fork; transcript fallback is only available for Kit. Its existing session still supports ordinarypromptcalls.
Do not infer support from the agent name or an old compatibility table; ACP capabilities can change between agent releases.
Nested agents run unattended and cannot ask the user interactively. Kit selects allow_always when offered, otherwise allow_once. If the child offers no allow option, Kit cancels the request; it never selects a rejection option.
permissions = "allow" is the default. The legacy values "deny" and "cancel" remain accepted for existing configuration files, but now also allow requests. Remove these old settings to avoid implying a restriction that Kit no longer enforces.
Only configure executables and fixed arguments you trust. Child edits and shell commands can run without approval; restrict access through the child's configuration and process privileges, as when running that executable directly.
Nested agents cannot collect interactive input. Kit answers child ACP elicitation/create requests with cancel, for both form and URL modes, rather than a method-not-found error. Kit does not supply form values, open URLs, or forward these requests to the parent model. This is independent of the child's permission policy; the child decides how to continue after cancellation.
Cancelling an outer turn propagates to nested work. For a dispatched prompt, Kit sends ACP session/cancel and allows up to five seconds for the child to settle; a child that does not settle is terminated. Cancellation while starting, waiting for the session lock, prompting, or forking returns a cancelled tool result. A cancelled fork or a fork that exceeds its 30-second deadline sends $/cancel_request for the in-flight request. Kit still waits for a late fork response to clean up any created session before releasing source-session serialization. A session/close request that exceeds its five-second deadline also sends $/cancel_request before its response is discarded. Protocol cancellation is advisory; it does not guarantee that the child stopped or rolled back the operation.
end_turn and max_tokens are successful completed turns. In particular, a max-token response returns its partial output and remains reusable. cancelled, refusal (nested agent refused the prompt), max_turn_requests (nested agent reached its turn-request limit), protocol errors, and unknown stop reasons are failures. A failed turn, including the first turn of a new subagent or fork, leaves a live child idle with its conversation and edits intact. The error names the subagent's ID, the cause recorded in its fatal error log, and how to continue it with prompt. Kit retires a session only when its child process is no longer running; reuse then reports unknown subagent session, subagent session is retired, or nested agent process is no longer running.
Subagents may nest to any depth. At most 120 subagent sessions may be live at once per parent and across a whole delegation tree; exceeding either reports live subagent session limit (120) reached or subagent limit for this delegation tree (120) reached. Use subagents({}) to inspect retained sessions and close to release sessions that are no longer needed. Closed, failed, or explicitly closed children no longer consume capacity.
ACP startup must complete within 30 seconds. Native session/fork must also answer within 30 seconds. Common diagnostics include:
ACP harness spawn failure: verifycommand,args, executable installation, andPATH.ACP harness handshake timeoutorACP harness protocol handshake failure: verify ACP v1 or v2 support, required methods, and that stdout contains only protocol messages. Check stderr for lines prefixedACP harness <name>:.ACP harness did not answer session/fork within 30 seconds: update or repair the agent, or avoidfork; onlyacp.kithas the transcript fallback.nested agent exited during startupornested agent process exited without a response: run the configured installed executable directly enough to verify installation and login, then inspect its stderr.- Structured output remains text: ask for bare JSON, inspect the raw
output, and use a repairpromptwith an appropriateoutput_schema.
For current top-level and subcommand options, run kit --help or kit <command> --help.
Child sessions inherit the owning ACP session’s additional project directories on
session/new and native session/fork, including the Kit fork fallback. These
directories are project context, not filesystem access boundaries. An explicit
subagent.cwd changes the primary working directory without discarding the
additional directories. Each parent session has its own directory list.
If the parent has additional directories, a child harness must advertise ACP
additional-directory support; otherwise Kit rejects startup with an explicit
error instead of silently dropping project context.