Helpers and jobs

Two tools do work off the main path: subagent runs one helper session, and shell with background: true starts a background job that job manages. One helper session runs at a time per call; several calls in one reply run in parallel.

The helper session#

Use the subagent tool to run one helper session. The call blocks until the helper finishes, and returns the last assistant text. Long text is cut at 4000 characters and marked. The result names the helper session id. The helper starts with a blank history; the first input is the task text, so tell it what to do and what to report.

Field Required What it does
task yes The helper's first input.
agent no explore for read-only work, general for full work. Omit it (or pass "") to run general. Unknown values fail the call.

The explore helper mounts only read, glob and grep. The general helper mounts the parent tools minus subagent: a helper never mounts subagent, so helpers never nest. An explore child also skips the project MCP sources. explore fails when the session has no workspace: it needs the read tools rooted at one. A parent in automatic mode approves helper questions at once; a parent outside automatic mode denies them, and the denial is noted in the helper result.

The helper inherits the parent tier and can only narrow it. A general child runs the parent's live route, including a switch made after startup. An explore child runs [model.smol] when the config sets a full cheap route, else it follows the parent route. A half-set cheap route warns and is ignored.

A worked helper example#

Ask the model to fan out two read-only searches in one reply:

{"agent": "explore", "task": "List every file that defines a slash command, with one line each on what it registers."}
{"agent": "explore", "task": "List every file that defines a key binding, with one line each on what it binds."}

Each call returns its own conclusion. The model then compares the two lists. For a write task, use one general call with an explicit scope and an explicit report shape:

{"agent": "general", "task": "Add the `usage` row to the commands table in docs/user/commands.md. Report the lines you changed."}

Background jobs#

Use the shell tool to run commands. A foreground command never moves to the background on its own: only an explicit background: true starts one, and the call returns at once with a job id. The foreground default timeout is 300 seconds and the maximum is 600. Use background: true for servers, watchers and commands expected to run longer than 600 seconds. Run tests and builds in the foreground with timeout_secs.

Use the job tool to manage background commands. The same registry holds retained foreground output, so a capped foreground result stays readable through its id. Old entries leave when the registry fills.

Operation What it does
op: read Read output. Returns the increment since the last read plus the settle state when done. The read window is 64 KiB per job; the file keeps the full history for the host.
op: wait Wait for completion, default 30 seconds, at most 600. Returns the increment and the settle.
op: kill Stop the process group.

At most 4 background jobs run at once in one session. A fifth start fails with an error naming the limit. One approval covers a job's whole life.

Type /jobs to open the jobs page. It lists the running background jobs in registry order. Type /jobs kill <id> to stop one job, /jobs kill all to stop every job. The kill sends SIGTERM to the process group, then SIGKILL after 2 seconds. A settle the model has not seen arrives as a system message: on a busy lane it joins the running turn, on an idle lane it opens a follow-up turn that wakes it. After three wake-started turns with no user input, a settle is injected only.

Run !<command> to run a command in the tier shell, under the sandbox when one is enforced. Run !!<command> to keep its output out of model context; the block draws dimmer so the exclusion reads. A second ! while one runs is refused, and esc cancels the running command.

A worked job example#

Start a watcher in the background, then poll it:

{"command": "make watch", "background": true}

The call returns a job id at once. Read the increment:

{"op": "read", "id": "job-1"}

Wait for it to settle, or stop it:

{"op": "wait", "id": "job-1"}
{"op": "kill", "id": "job-1"}

Ask the model through ask_user when you own the trade-off between waiting and killing. The question tool only appears when a human can answer.