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.
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: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. Acompacted 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
cancelled, recording who stopped it.