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 one or more subagents and return immediately, listing each one's name, run_id and answer file |
message_subagent | Send a running subagent a correction or extra context, by its worker name |
stop_subagent | Stop one running subagent by name; its work in progress is discarded |
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 and keeps working. Each subagent's answer arrives in a note the moment it finishes, so there is nothing to wait on.
Steering a running subagent
A subagent that misread its task doesn't have to run to the end. message_subagent queues a message
and returns straight away. The subagent reads it at its next step, after any tool call in flight has
finished, as an ordinary user message: to a subagent, the agent that dispatched it is its user.
Several messages are delivered together, in order.
- A subagent still waiting for a free slot can be messaged too; the message is waiting when it starts.
- A subagent that already finished is reported as such: dispatch a follow-up instead.
- A message is only text. It cannot widen the subagent's tools, answer a permission prompt, or change its sandbox or model.
- Workers are named after their agent, numbered on repeat (
explore,explore-2), and a name is never handed out twice in a session, so each name addresses one worker.
stop_subagent ends one subagent without touching the others. Esc still stops all of them along
with the turn.
You can do both yourself from /agents: select a subagent and press m to message it or x to stop
it.
Watching subagents
Subagents read the same way everywhere the console shows them: the name, then a stats line, then a status.
- Stats:
4 tools · 4 req · 50% ctx · 75% cached- tool calls made, requests sent, how full the subagent's context window is, and its prompt-cache hit rate. A part is left out until it is known, and a0% cachedrate is drawn in the warning colour. The panel docked above the input uses the short form4t · 4r · 50% ctx · 75% cached. - Status:
Running,Queued (N),Waiting (phase N),Completed - <first line of its reply>,Interrupted, orError - <reason>. - Activity: what a running subagent is doing, worded like a conversation row (
Read kv.rs,Running cargo test). The same call repeated shows a count (Read kv.rs ×2); repeated 4 times in a row with the same arguments it turns into⚠ looping ×4, since that usually means it is stuck.
In the conversation, a dispatch is one row naming every subagent with each brief under it
(• Dispatched explore, general), and each subagent that ends leaves a row such as
• Finished explore · 3 tools with its status under it.
Watching a subagent with /agents
/agents lists the subagents running now (green bullet), with their stats, status and current
activity, followed by the ones that have finished this session (dim bullet). Press Enter on one to
open its run.
The run is drawn the same way as your own conversation: its answers, its reasoning folded to a
Thought row, its tool calls as bulleted rows (reads and searches grouped under Explored, shell
output, edit diffs), and any message you sent it with m as your own message. A header above it
shows the subagent's name, run id, stats, status and brief.
The view follows the subagent as it works. PgUp/PgDn scroll back through the run, Home jumps to its start and End returns to following it. Esc goes back to the list.
A finished subagent stays readable. Its summary row in the conversation (Finished NAME)
expands with Ctrl-O to the same run, and /agents still opens it. The console keeps the most recent
400 rows of each subagent's run.
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 gets a run_id immediately, and its answer arrives in a note once a slot frees
and it completes - no deadlock, no premature promotion. Esc cancels queued runs too.
In the console, a queued subagent shows as Queued (N) 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.
Built-in subagents
Jan ships five subagents, ready to dispatch with no setup:
| Name | Model | What it does |
|---|---|---|
explore | smol | Codebase exploration: finds where things are and reports path:line evidence. Told to only read |
research | smol | Answers a question from current web sources, with citations |
review | inherit | Reviews a change for correctness, risk and missing tests, and reports instead of editing |
debug | inherit | Reproduces a failure, finds the root cause, makes the smallest fix and verifies it |
general | inherit | Any task no other agent fits |
Every built-in has the session's full toolset; its role is its prompt and model. explore is
read-only by instruction, not by construction: on the cheap smol model under an auto-approving
policy it could still write or run commands. To hold it to reading, give it a definition of your own
(see below) with allowed_tools = ["read", "ls", "find", "grep"].
Each dispatch entry names an agent, one of the predefined agents, and the task. Workers are named
after their agent, numbered when one agent runs more than once (explore, explore-2); the
dispatch result lists each name, which is what message_subagent, stop_subagent and the answer
file blackboard/<name>.md use:
{ "subagents": [ { "agent": "explore", "task": "Where is request auth checked?" }, { "agent": "explore", "task": "Which tables does the migration touch?" }] }
The main agent sees each agent with its model and purpose in its system prompt, so it can send
lookups to explore and keep your main model for the work that needs it. An agent that is not one
of the predefined agents is refused, with the valid ones listed.
A saved subagent with the same name replaces a built-in one (see below), and the model of any of them can be changed per project.
Choosing a subagent's model
A subagent definition's model is one of:
smol: the cheap model set assmol_modelin~/.jan/config.toml. Whensmol_modelis unset, the session's model is used.inherit(or nomodel): the session's model.- A model id, such as
gpt-5-mini. This ties the definition to one provider's naming, so prefer a role.
To change it without editing the definition, set an override in the project's agent.toml:
[subagents.review]model = "smol"
Or do it from the console. /settings has two rows for this:
smol_modelopens the model picker and sets the cheap model for everysmolsubagent (and for/goalchecks).subagentslists every subagent with the model it runs on. Enter opens the model picker, with thesmolandinheritroles at the top.xclears the override, so the definition's own model applies again.
The model is read each time a subagent is dispatched, so a change applies to the next one without a restart. A cost ceiling is enforced at the subagent's own model's prices; a model with no published price is refused under a ceiling rather than metered at the wrong rate.
The agent cannot pick a model itself: create_subagent saves a new definition without one, so it
runs on the session's model until you choose otherwise. When the agent overwrites an existing
definition (to change its prompt, say), the model you set on it is kept.
Reusable subagents
Definitions are TOML files, merged from two scopes:
~/.jan/agent/subagents/<name>.toml # user scope, available everywhere~/.jan/projects/<slug>/subagents/<name>.toml # project scope, this project only
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. Either scope also shadows a built-in subagent of the same name.
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:
model: haikuruns the agent on thesmolrole and any othermodelon the session's model,coloris ignored, 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, an optional default tool
allowlist, and an optional model (see above). 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 applies only in this project. Ask for the user scope to use it everywhere.
Once saved, it is dispatched with agent set to its name and picks up its stored prompt,
permissions and model. Names are at most 64 characters of letters, digits, - and _.
Tool permissions
A subagent gets the session's full toolset unless something narrows it, and it is never widened:
- A definition's own
allowed_toolsrestricts every dispatch of it. - A dispatch entry's
allowed_toolsrestricts that one worker further. Its values are limited to the tools the session can actually hand a subagent.
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.