Skip to main content
A turn runs until the model answers without a tool call. Four things shape what it may do on the way, and all four are options on Agent — pass them through new Harness({ … }) or construct the agent yourself.

Subagents

A model can send out a child session to go and do one thing: read a large tree, check a hypothesis, summarise something, without spending the parent’s context on it. Two tools appear when they are allowed — spawn_agent and wait_agent — and the parent sees child_started and child_done events. A child runs in the same workspace, on purpose. One that could not see the files would be useless, and one with its own workspace would be a different agent. What is narrowed is the actor: its path scope and its mode.

The rule that matters

A child’s permission must be no wider than its parent’s. Spawning is the obvious way to escalate — an actor confined to /groups/7 in discard asks for a child that is owner at / in commit, and if nobody checks, it has promoted itself. That is checked before the child exists, and the default child is the parent’s own actor forced to discard: the safe shape for the common case, which is sending someone to go and look at something. There is no second permission system for children. Scope and mode are already what bash and the connector gateway enforce.
A tree that can branch at every level is a bill nobody agreed to, and the useful case — one agent sending out several readers — needs exactly one level.

Plan mode

For work a person should agree to before it happens, the model drafts a plan and the turn stops. Your app shows it; a person accepts it; the agent then carries it out:
The actor’s permission is a ceiling here too: someone whose permission is discard may agree with a plan and still not be allowed to carry it out, and saying so is better than a session that silently discards everything it does. If an accepted plan still has unfinished steps, the agent is sent back a small number of times — maxPlanNudges, default 2 — and then the turn ends blocked, naming what is outstanding. A model told twice what is left and answering anyway will not be persuaded by a third telling.

Compaction

Long conversations are folded against the adapter’s real context window — the number the model reports, not a guess — leaving a summary hop in place of the folded range. A compacted event says what was folded.

Ceilings

A turn that hits one of these is not expensive, it is stuck, and it stops and says so rather than looping: The turn ends blocked, with a stop_reason naming which ceiling it was, so your UI can say something truthful rather than showing a spinner.

Cancellation

Durable. The cancellation is written where the loop checks it between hops, so it survives a process restart — a turn cannot outlive a cancel by being on a server that got redeployed. The turn ends cancelled, recording who stopped it.