Docs
Jan Agent
Subagents

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

ToolPurpose
dispatch_subagentStart one or more subagents and return immediately, listing each one's name, run_id and answer file
message_subagentSend a running subagent a correction or extra context, by its worker name
stop_subagentStop one running subagent by name; its work in progress is discarded
create_subagentSave a reusable subagent definition
list_subagentsList 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 a 0% cached rate is drawn in the warning colour. The panel docked above the input uses the short form 4t · 4r · 50% ctx · 75% cached.
  • Status: Running, Queued (N), Waiting (phase N), Completed - <first line of its reply>, Interrupted, or Error - <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:

NameModelWhat it does
exploresmolCodebase exploration: finds where things are and reports path:line evidence. Told to only read
researchsmolAnswers a question from current web sources, with citations
reviewinheritReviews a change for correctness, risk and missing tests, and reports instead of editing
debuginheritReproduces a failure, finds the root cause, makes the smallest fix and verifies it
generalinheritAny 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 as smol_model in ~/.jan/config.toml. When smol_model is unset, the session's model is used.
  • inherit (or no model): 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_model opens the model picker and sets the cheap model for every smol subagent (and for /goal checks).
  • subagents lists every subagent with the model it runs on. Enter opens the model picker, with the smol and inherit roles at the top. x clears 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: haiku runs the agent on the smol role and any other model on the session's model, color is ignored, and tools is 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 correctness
and 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_tools restricts every dispatch of it.
  • A dispatch entry's allowed_tools restricts 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.