Subagents
A subagent is a separate agent run that the main agent starts, hands a task to, and collects an answer from. Each one gets its own context window and its own tool allowlist.
Two reasons to use them:
- Context. A subagent that reads twenty files to answer one question spends its own context doing it, not yours. Only the answer comes back.
- Parallelism. Independent pieces of work can run at the same time instead of one after another.
How it works
The main agent decides when to delegate. You don't call these tools yourself - you describe the work and the agent splits it up.
Write four variants of this game, each in a different visual style.Spawn them in parallel.
≡ Task 4 agents • flappy-2d 3 tools · 3 req · 11.9%/128K Create variant 1: 2D Canvas - classic mechanics write flappy-2d.html • flappy-3d 4 tools · 4 req · 13.0%/128K Create variant 2: 3D - same mechanics in 3D ⠋ write flappy-3d.html
Each row shows the agent's name, how many tools it has called, how many model requests it has made, and how much of its context window it has used. The line under it is the task it was given, followed by what it's doing right now.
Context share is the one to watch: an agent climbing toward 100% is about to run out of room.
The tools
| Tool | Purpose |
|---|---|
dispatch_subagent | Start a subagent on a task and return immediately with a run_id |
await_subagent | Block until a dispatched run finishes and return its answer |
create_subagent | Save a reusable subagent definition |
list_subagents | List the subagents available here |
Dispatch is non-blocking, which is what makes parallel fan-out possible: the main agent dispatches
several, then awaits each one. Each run_id can be awaited once.
Parallelism and queueing
Up to max_parallel_subagents subagents run at the same time (default 10, minimum 1, set in
agent.toml under [agent] - or from the console with /settings max_parallel_subagents N).
Dispatches beyond the cap are queued FIFO and start as a running child finishes.
A queued run still returns a run_id immediately, and await_subagent on it simply blocks until a
slot frees and the run completes - no deadlock, no premature promotion. abort_all cancels queued
runs too.
In the console, a queued subagent shows as queued (N waiting) in its panel, where N is its
position in line (1 = next to start). The panel turns into a normal running row once its slot
opens.
The cap is snapshotted when a run starts, so changing it mid-run takes effect on the next run.
A queue is not an error signal. The main agent keeps dispatching; runs just wait their turn.
Isolation
A subagent does not see your conversation. It gets only the task it was handed, so that description has to be self-contained - the main agent is responsible for writing a brief that stands alone.
Subagents also cannot:
- dispatch subagents of their own (no recursion)
- read or change the main agent's todo list
- ask you an interactive question
They can request permission for a write or a command. Those prompts surface in your console, labelled with which subagent asked.
Because a subagent's context is separate, a long research task that would have crowded your session costs you only its final answer.
Reusable subagents
Definitions are TOML files, merged from two scopes:
~/.jan/agent/subagents/<name>.toml # user scope, available everywhere<project>/.jan/agent/subagents/<name>.toml # project scope, shareable via git
The two are merged, and the project scope shadows the user scope by name - so a project can override one of your personal subagents without renaming it.
Plugins can also ship subagents as markdown agent files (agents/*.md in an installed plugin, the
Claude Code convention). They load as a third, read-only scope:
- The plugin scope loads first, so a user or project TOML definition shadows a plugin agent of the same name.
- Plugin agents cannot be created or edited through
create_subagent- they are managed by installing or removing the plugin. - Claude-runtime frontmatter is translated:
modelandcolorare ignored (the agent runs on the session's model), andtoolsis mapped onto Jan's tool names (Read->read,Glob->glob,Grep->grep,WebSearch->web_search,WebFetch->web_fetch,TodoWrite->todo). Names with no Jan equivalent are dropped; an agent listing only unknown tools inherits the parent's full tool policy.
See Plugins for how plugin agents are discovered.
Each definition carries a name, a one-line description, a system prompt, and an optional default tool allowlist. The agent can write one for you:
Create a subagent called "reviewer" that reviews diffs for correctnessand never edits files.
That writes to the project scope by default, so it can be committed and shared. Ask for the user scope to keep it to yourself.
Once saved, refer to it by name and it picks up its stored prompt and permissions.
One-off subagents
A subagent doesn't need a saved definition. The agent can invent one for a single task by supplying a name and a system prompt together in the same call. Useful for a fan-out where each worker differs only slightly.
Tool permissions
A subagent's tools are narrowed, never widened:
- For a saved subagent, the allowlist further restricts its own stored allowlist.
- For a one-off, the allowlist is its toolset.
Either way it can only ever reach a subset of what the parent could reach, so delegation cannot be used to escape your project's tool policy.
One exception: skill_list and skill_read are always available to a subagent, whatever its
allowlist says. Skills are how a subagent executes its procedure, and plugin agents/*.md files
never list them, so a narrowed toolset keeps the read side - a subagent can always load the skills
it was told to follow. A policy that explicitly denies a skill tool still wins.
When not to delegate
Subagents cost a model call to brief and another to summarize. For a small task, doing it inline is faster and cheaper. They earn their keep when the work is genuinely independent, or when it would otherwise flood your context with material you don't need to keep.