# Subagents (/agent/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 [#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 [#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 [#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 [#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` [#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 [#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.

<Callout type="info">
A queue is not an error signal. The main agent keeps dispatching; runs just wait their turn.
</Callout>

## Isolation [#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.

<Callout type="info">
Because a subagent's context is separate, a long research task that would have crowded your session
costs you only its final answer.
</Callout>

## Built-in subagents [#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:

```json
{ "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 [#choosing-a-subagents-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`:

```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 [#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](/agent/plugins#plugin-agents) 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 [#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](/agent/permissions#project-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 [#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.
