Skip to content

Subagents

A subagent is a separate agent the model starts to handle one self-contained task, such as a piece of research, a large read, or a delimited bit of work. The subagent does the task in its own context, and only a short result returns to the main conversation. You do not start subagents yourself; the model does, when a task is bounded enough to hand off.

A subagent is worth spawning for one or more of these reasons:

  • Context protection. The subagent’s work, including the false starts, the long tool output, and the dead ends, stays in its own context. Only the result reaches the main conversation, so your context stays clear for the work you care about.
  • Context freshness. A subagent starts with no history, so it reads the task without the assumptions the main conversation has already built up. Even the same model, run fresh, often takes a different approach.
  • Restricted permissions. A subagent can run with a narrower permission set than the main agent, which limits what it may do. See Permissions.

A subagent’s context is managed the same way the main conversation’s is. When the subagent’s work grows toward its model’s context limit, Polytoken compacts it: the work so far is summarized, and the subagent continues from the summary with its recorded progress carried through. If compaction cannot make the context fit, the subagent ends with an error saying its context grew too large.

  • researcher: investigates a question against your codebase, the web, or both. Use it when the task is to go find something out.
  • general-purpose and general-purpose-mini: use these for a bounded task when no specialized subagent fits. The two are the same agent on different models: general-purpose runs on your full model, general-purpose-mini on your smaller one.

general-purpose uses your full model. general-purpose-mini uses your smaller model for bounded tasks that need less capacity.

Subagents run asynchronously, alongside the main conversation, and appear as jobs. Watch them in the async jobs pane or with /jobs, each under a handle like researcher:curie. See Managing Work.

When a subagent finishes, Polytoken sends a notification and returns a short result to the model, not the subagent’s whole conversation. By default these notifications auto-drain: as soon as the result arrives, Polytoken starts a turn so the model can act on it, even if the main conversation was idle and waiting for you to type. To have the model wait for your next prompt instead, turn auto-drain off; see the configuration reference. Turning auto-drain back on immediately processes any notifications that queued while it was off.

The model can request several independent copies with the count input to the subagent tool. Polytoken prepares every copy in the batch before launching any of them, so a preparation or capacity failure starts no partial batch. Omit count for the default of 1. Polytoken returns one handle per launched copy in clone order, and each handle has independent status, cancellation, results, and notifications.

Every subagent launch receives subagent_batch.ordinal (one-based) and subagent_batch.count in its templates, including a single-copy launch where ordinal is 1 and count is 1.

A subagent can finish while a turn is still running. When Polytoken compacts that turn before the result notification reaches the model, the compacted context names the finished subagent, the outcome, and a short summary of the result, so the model can act on the finished work instead of waiting. Polytoken still delivers the queued notification after the turn ends.

Set daemon.max_concurrent_subagents to limit how many subagents Polytoken runs at once. When the limit is reached, later subagents remain queued in reservation order instead of failing to start. The job status reports queued, and the subagent starts when an earlier subagent reaches a terminal state. Clients older than the queued-status feature cannot parse the queued job status. Update the CLI before connecting it to a newer daemon. Omit the key, or set it to 0, to allow unlimited concurrent subagents.

Polytoken applies the limit when the daemon starts. Restart the daemon after changing daemon.max_concurrent_subagents. A queued subagent remains cancellable and remains subject to the existing 24-hour hard deadline, even while it waits for a slot.

If a subagent reports failure, the failure notification identifies the failure and tells the model to re-dispatch the task when appropriate. A subagent that cannot produce a usable result after bounded recovery reports a harness failure, not a successful apology. The notification includes the available result text when one exists and suggests trying a different model or reasoning effort when re-dispatching.

If the harness detects persistent history corruption, it reports the subagent as failed, with the recurring tool-call IDs when available. Start a fresh subagent for that task: do not refork the corrupted history. This recovery instruction is part of the failure notification so the model does not mistake an interrupted run for a successful result.

If Polytoken cannot launch a subagent, the launch error preserves the specific cause and includes the same retry and escalation guidance.

A subagent run is exactly the kind of wait cache warming covers: the main conversation sits idle while background work runs, so its prompt prefix can drop out of the provider’s cache. When your config enables warming, Polytoken refreshes the main conversation’s prefix while the subagent works, and a subagent’s conversation warms the same way while the subagent waits on its own background jobs. A refresh request never reads or changes the subagent’s work; it repeats only the waiting conversation’s own prefix.

Warming follows the daemon.cache_warming policy and each model’s cache_warming_interval_secs interval; see Sessions for both. Each refresh draws on your API spend or subscription quota. Each subagent conversation allows one successful refresh by default during an idle stretch. The daemon.cache_warming_max_refreshes_subagent key changes that user/global budget, and a new successful ordinary provider attempt resets it. A completed refresh that reports zero cached tokens pauses warming for that subagent; cache usage that is unavailable does not count as a miss. The daemon.cache_warming_refresh_limit_enabled key disables this budget and miss-stop behavior when set to false. Every attempt shows a compact card in the conversation, naming the model and, for a subagent’s refresh, the subagent. The card belongs to the interface alone, not to the session, so it disappears when the conversation reloads, clears, or rewinds.

A subagent definition can select a model group (an ordered failover list of models; see Model groups and failover) instead of a single model. Reference the group in the definition frontmatter with a prefixed name:

---
name: plan-checker
description: Review a plan against the codebase and return findings.
polytoken:
model: "@mg:polytoken:plan_reviewer"
tools: [file_read, grep, glob]
---
Review the plan sections against the actual source files and
report any gaps.

Each counted clone starts at a different group candidate: the first clone at the first candidate, the second at the second, wrapping around the group. Polytoken retries the current provider before moving to the next candidate. A successful candidate stays current until you or the model explicitly selects a group again or the provider fails and the route advances.

Templates record launch-time values that never change afterward: model_group.name, model_group.ordinal, and model_group.count identify the group and the candidate selected at launch. Provider failover or a configuration reload can change the current route without changing these recorded values or the rendered text.

A group-valued polytoken.model cannot be combined with polytoken.fallback_models; Polytoken rejects the definition at load time. Put the fallback order in the group itself.

A subagent starts in the working directory the main conversation is using. If the model has pushed into a subdirectory with the pushd tool, the subagent starts there; otherwise it starts at the project root.

The model can also start a subagent in a specific directory by passing cwd when it spawns the subagent. The directory has to exist, and a relative path resolves against the main conversation’s working directory. Directories outside the project ask for chdir permission approval, and approving one also grants read access so the subagent can use file tools there without a second prompt. Once a subagent starts, it cannot popd above its start directory, though it can still pushd deeper if it has that tool.

When the model does not pass cwd, the subagent starts in the main conversation’s working directory, exactly as before.

The model can send a text message to a subagent that is still running using the message_subagent tool. Polytoken queues the message and delivers it before the subagent’s next step, never mid-response. The tool returns immediately after queuing. If the subagent has already completed, Polytoken drops the message. The model can check whether a subagent is still running with job_status before sending.

Messages appear in the subagent’s conversation as new input. The subagent responds to them as part of its normal work.

Only the main conversation can use message_subagent.

A subagent’s work does not have to end when the subagent completes. The model can fork a completed subagent’s conversation into a new subagent, letting the same context carry forward into a new task. This is how the model takes a research subagent’s findings and turns them into an implementation subagent without re-explaining everything it already discovered.

The model passes resume_from with the prior subagent’s job handle, and the new prompt becomes a directive appended after the prior conversation. The fork creates a new subagent with its own job handle, so the source subagent is never modified. The fork uses the subagent type and model chosen for it, not the source’s.

Multiple forks from the same source are possible. Each fork gets a new handle and its own independent context from that point forward. The prior subagent’s history is carried as conversation history, so the forked subagent sees everything the source saw, including tool results and earlier reasoning.