Skip to main content
Subagents let the agent split large work and process it in parallel rather than grinding through it serially in one context. Each subagent is an independent Agent instance: own context, own toolset, own ledger.
What a subagent can reach is decided by five capability dimensions (tools, skills, MCP, knowledge sources, memory), declared one by one. See Subagent capabilities.

The four dispatch tools

1

Task

Dispatch a subagent with its own context and toolset, and return immediately.
2

TaskWait

Wait for a subagent to finish and collect its result.
3

TaskList

List live subagents and their status.
4

TaskStop

Terminate a running subagent.
The parallel rule is plain: several Task calls in one assistant message run in parallel. Mix a Task with any other tool in the same message and they degrade to one at a time. The concurrency cap is 8. And you never have to wait idle — keep working or keep talking; reports land back in the conversation when they finish.

The main agent can author definitions itself

Beyond the settings page, the main agent holds three management tools:
1

subagents_list

List every definition (tools, turns, model, switch, source file, per-layer storage dirs).
2

subagents_save

Create or update a system-level / workspace-level definition.
3

subagents_delete

Delete a custom definition.
They share the exact same semantics as the settings page: schema validation, layer directory resolution, rejecting names that collide with a built-in, cross-layer duplicate checks, cleaning up the old file on rename. A definition the agent writes is indistinguishable from one you wrote by hand. This group hangs beside the Task group and is not in the base toolset: a subagent picking tools from its definition structurally cannot reach them. A delegate can neither delegate further nor edit definitions — a second gate behind the grantable-tool allowlist. After a save the protocol layer regroups tools, so it takes effect on the next turn, with no app restart.

Four-layer discovery

A definition is a plain YAML file, loaded across four layers:

Built-in

Shipped with the app: Explorer, Code-reviewer, Test-runner, Fixer. Read-only in settings — switchable and copyable to system level, never written back.

System

subagents/*.yml in the app data directory; active everywhere. This is where your own personal definitions live.

Workspace

<workspace>/.kova/subagents/*.yml, travels with git, active for that workspace only.

Plugin

Contributed by the subagents directory in a plugin manifest; the switch and model override are namespaced by pluginId.
On a name clash the later layer shadows the earlier one. A broken file degrades into a single diagnostic — it never takes down the rest of the list, and certainly not a turn. The switch and the model override never go into the definition file. Definition files land in git and built-ins are read-only constants, so “is it enabled” and “which model” are this machine’s business, stored as one package in SQLite. The model override is therefore the only tunable on a built-in definition. Precedence: Task argument > local override > definition's own > session model

What it can reach is what the definition says

A subagent definition may declare five orthogonal dimensions. Undeclared means unreachable — what you did not write shows up neither in its toolset nor in its prompt. Details and the trade-offs behind each: See Subagent capabilities.

Why the activity trail must be persisted

The most practical lesson in the subagent system. The problem before: what a subagent did while working — its thinking, tool calls, and written text — lived only in memory, capped at 400 entries, and when full the buffer preferentially dropped thinking and text deltas. Restart the app and the “Subagents” panel showed a single line: “record expired” — only the final report survived, in the main conversation. The design is three things:

Where

One file per subagent: sessions/subagents/<its id>.jsonl, one record per line, append-only.

How

Written as it runs, but batched (250ms) — fast, disk-friendly, and it never blocks the agent’s main loop.

After a crash

Read back from the file on restart; the panel renders normally, with zero changes to the frontend store.

Crash loss rate

Define it before promising anything — loss rate = records lost at crash / records that delegation had produced.
  • A crash loses at most the current unflushed batch (≤250ms of increments);
  • Terminal states (the report) are force-flushed synchronously, so the result is never lost;
  • Corollary: the longer the delegation runs, the lower the boundary loss. Short tasks are exempt — they produce few records anyway, and their trail is worth little; accepted deliberately.

Recovery and “interrupted”

Reads are lazy: the disk is consulted only on a memory miss, with no startup warm-up. A delegation that was running when it was persisted comes back marked interrupted — the process is gone so it cannot still be running, but its complete trail (thinking, tool calls, text, report) survives.

Retention guards

  • A file over 5MB is trimmed to keep the last 1MB, so long jobs cannot fill the disk;
  • File count is governed by scanning the directory (not memory — after a restart memory is empty, only a scan knows what exists), deleting the oldest when over the cap;
  • Cleanup only runs while no delegation is active, and running files are never evicted.

Token settlement: subagents keep their own books

A subagent is an independent Agent; its usage never lands in the parent transcript. Read only the parent transcript and “the subagents did most of the work” will badly under-count. So subagents keep their own ledger (SubagentRun.tokens) and settle into the parent run, with a status guard that blocks double-settlement of the same amount.
This is one of the reasons goal mode moved its token ledger from “read the transcript” to “accrue deltas”: a ledger that cannot see subagents makes the objective’s burn counter wrong.

Explicitly out of scope

The design states its boundaries; these are deliberate trade-offs:
  • No resumption: after a restart the execution chain is not restored; an unfinished delegation is “replayable history”, not something that auto-continues;
  • Nothing written into the parent transcript: the parent transcript is read whole, and writing into it would pollute it;
  • No new storage engine: the existing JSONL pipeline and its write discipline are reused;
  • No nested delegation: a subagent gets neither the Task group nor the subagent management group, so it cannot delegate any further;
  • Subagents do not decide the main memory: they may write straight into the shared workspace memory by choosing that mode, but there is no “import this subagent’s private memory into the main memory” action.

Next

How a definition reaches a knowledge base, skills and memory — the capability model.