PlansThe visible checklist — stable step ids, children attached to steps, and settlement the runtime derives.

The plan verb maintains a thread's visible checklist: the structure the user watches while an agent works. A plan is not decoration — its steps organize the run tree, and leaving it unfinished is a debt the system accounts for (Obligations).

Steps

Each step is {id, label, status} with status pending | running | done | failed | skipped. Ids are stable; labels are not — models rewrite them freely as understanding improves, so everything that matters joins on the id.

The checklist is stored on the session (plan_cbor) and rendered fresh into each turn's replay as a <plan_state> block rather than being stored as a Log event. That matters: after children have run and changed the world, the agent sees the current state of the checklist it published, not a stale copy from when it wrote it. The block ends with a standing instruction — update statuses with the plan verb before you finish your reply.

Because step ids and labels are model-authored text handed back to the model inside a frame the model trusts, they get the same escaping treatment as user-action payloads: a label crafted to be the closing tag is neutralized, not censored (Security).

Attachment: steps own their children

A child spawned while a step is running belongs to that step, joined by planStepId. The step row in the UI is the way into its children — expand the step, find the work. A batch step owns an entire parallel fan-out, rendered as uniform peers under one running step.

The join prefers the stable id and falls back to the label only for runs spawned before that field existed — a small compatibility detail that exists precisely because labels drift.

Runtime-derived settlement

A step whose attached children all succeeded is closed by the runtime, stamped resolvedBy: 'runtime', and that settlement is carried forward across later plan edits. Only success is ever derived this way: the runtime never writes a step off, never marks failure on the model's behalf, and never ticks a box the evidence doesn't support.

When a checklist first goes fully terminal, settledAt records the moment — which is when the pinned card leaves its slot and freezes into the log as history (Desktop).

Plans and endings

A run that wants to end while steps sit neither finished nor written off has plan debt. The obligations contract asks it to settle honestly — finish, or explicitly write off — and if the ask budget runs out, the run ends owing the debt visibly rather than having it silently forgiven.

Scripts have plans too

A script child publishes a checklist with ctx.plan(...) and marks units of work with ctx.step(label, fn), which journals a start and end phase around the function. The two surfaces render as one merged checklist on the run card.

Related

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime