> ## Documentation Index
> Fetch the complete documentation index at: https://nativeharness.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Controlling the turn

> Subagents, plan mode, compaction and the ceilings that stop a turn that is stuck rather than expensive.

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.

```ts theme={null}
new Harness({
  model,
  agent: {
    maxDepth: 1,        // children do not spawn children. 0 forbids subagents entirely
    maxChildSteps: 12,  // hops a child may take — lower than a root's; a child has one job
  },
});
```

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:

```ts theme={null}
await harness.agent.acceptPlan({ workspaceId, sessionId, by: "user-42" });
```

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.

```ts theme={null}
new Harness({ model, agent: { compaction: false } });   // never fold
```

## Ceilings

A turn that hits one of these is not expensive, it is **stuck**, and it stops and says so
rather than looping:

| Option              | Default     | Stops a turn that…                      |
| ------------------- | ----------- | --------------------------------------- |
| `maxSteps`          | `40`        | keeps taking hops without converging    |
| `maxTurnTokens`     | `1,500,000` | burns tokens across the whole turn      |
| `maxDecisionTokens` | `8,000`     | asks for an unbounded single completion |
| `maxPlanNudges`     | `2`         | will not finish the plan it accepted    |

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

```ts theme={null}
await workspace.cancel();
```

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.
