Skip to content

Chapter 8: The Agent's Procedure

Orchestrating a Multi-Step Change


1. Why Sequences Break

The change touched five files: a schema migration, a deploy, a verification run, a cut-over and a cleanup. The agent planned all five in its head, ran them in one pass, and failed at the fourth. The error named a missing configuration key. It did not say whether the migration had applied, whether the deploy had taken the traffic, or whether the verification had ever run. There was one gate, at the end, and the end is where the information runs out.

That is the shape of the problem. A sequence that lives in prose is a sequence the agent re-derives every time, and re-derivation is where steps get skipped. Nothing in the repository knows which step the run is on, so the failure arrives with no step to blame and the resume starts at the top.

The three structures assume the work is repeatable. The workflow structure is the one this chapter makes concrete: it is where the prompt and the engineering are checked, in order, on the way to a change. A single edit needs no help. A change that touches five files and can fail in the middle needs a procedure: the ordered steps, each with a gate, written as a contract rather than a plan. A play is the file that states one procedure — the artefact, in the repository, reviewed like code.

Chapter 7 made one session's work resumable across tools. This chapter makes a multi-step procedure resumable inside that work: a procedure records which step it is on, so a resume starts at that step instead of at the top.

A procedure also carries approval points — steps that cannot proceed without a decision, by design. Those are not escalations. An approval point is planned and sits where the procedure put it; an escalation is a condition that stops a run wherever it appears. This chapter defines the first; the next defines the second.

💰 Cost Check: a procedure costs a review and a maintenance pass; the absence of one costs the re-derivation on every run, plus the failures that arrive at the end with no step to blame. Write procedures for work that repeats and fails in the middle — the two conditions where the arithmetic favours them — and delete the ones that ran once.

🎯 What You'll Learn

  • The anatomy of a step — action, gate, approval point, and where a resumed run continues
  • Why a procedure is a contract — the agent's, in the repository, not the Orchestrator's checklist
  • Play, engine and board — which of the three belongs in your repository, and which you adopt
  • When not to write one — the work that costs more with a procedure than without

The Five-File Change

Without a procedure With one
the agent plans five steps in its head each step states its action and its gate
a failure at the end names one symptom a failure names the step that failed
resumption starts from the top resumption starts from the recorded step
two agents do it two ways one way, reviewed
flowchart LR
  S["step"] --> A["action"]
  A --> G{"gate"}
  G -->|"passes"| N["next step"]
  G -->|"fails"| F["stop — the gate names the fix"]
  G -->|"needs a human"| P["approval point"]

What this shows: every step ends at a gate, and a gate has three outcomes — pass, fail, or escalate.

✅ What to Check

  • Take your longest repeated change. Can an agent name the step it is on, right now, from the repository?
  • Does the procedure have a gate per step, or one gate at the end?

2. Procedure Anatomy

Three words do most of the work in this chapter, and each means one thing:

Word What it means here What it is not
sequence ordered work, however it is written — including in someone's head not a procedure until every step has a gate
procedure a sequence written down, with a gate on every step not the tool that runs it
play the file that states one procedure not the engine, and not the board

A procedure is a list of steps, and a step has four parts:

Part What it states Example
action the one operation apply the migration to staging
gate what proves it worked the schema validator passes
approval point when a human decides before production
resume where to continue step 4 if the gate passed

Names are invariants, not tasks. A step named "check the migration" describes an activity; a step named "the migration applies cleanly to a copy of production" describes a state that is either true or false. The second can fail; the first can only be "done".

The Skeleton

# plays/<name>.yaml — the play, as the agent's contract
name: <what the procedure delivers>
trigger: <when this play is the right one>
steps:
  - id: 1
    invariant: <the state that must be true after this step>
    action: <the one operation>
    gate: <the check, with its command>
    approval: none | human:<who>
    on_fail: stop | run:<step-id>
stop: <the observation that aborts the run>
rollback: <how to return to the last known-good state>

A play is more than its steps. The three fields around them are what separate a play from a to-do list:

Field What it answers Why it is not optional
trigger when this play is the right one a play applied to the wrong task is a sequence of plausible mistakes
stop what observation aborts the run without it, the run improvises at the moment improvisation is most expensive. This adds a stop for this play; the estate-wide conditions in the next chapter apply to every step and cannot be removed
rollback how to return to the last known-good state the point of gates is that the cheap failures stay cheap

This is the same anatomy the Playbook states in prose — trigger, steps with gates and approvals, stop condition, rollback. The YAML is the machine-readable form of one play; the Playbook is where the plays are collected and reviewed.

The Five-File Change, as a Play

The scenario from §1, written as a procedure. Three rehearsal steps that can fail cheaply, one production step behind an approval:

# plays/migration-to-production.yaml — the five-file change from §1
name: the new schema is live and the old path is still draining
trigger: a migration that changes the schema under a running service
steps:
  - id: 1
    invariant: the migration applies cleanly to a copy of production
    action: restore last night's snapshot into the rehearsal database, then apply the migration
    gate: scripts/check-schema.sh --rehearsal
    approval: none
    on_fail: stop
  - id: 2
    invariant: the old and the new schema both accept writes
    action: deploy the dual-write build to staging
    gate: scripts/check-dual-write.sh --staging
    approval: none
    on_fail: stop
  - id: 3
    invariant: the rehearsal cut-over completes with no reads left on the old path
    action: run the cut-over against the rehearsal database
    gate: scripts/check-cutover.sh --rehearsal
    approval: none
    on_fail: stop
  - id: 4
    invariant: production serves the new schema with the old path still draining
    action: apply the migration to production and enable dual-write
    gate: scripts/check-production.sh --window=30m
    approval: human:the-orchestrator
    on_fail: stop
stop: the rehearsal database cannot be restored, or the cut-over leaves reads on the old path
rollback: keep dual-write on and re-point the service at the old schema; the migration has a tested down path

Read it top to bottom and the argument is visible: the three steps that can be ruined for free come first, the one that cannot waits behind an approval, and every step states the state it leaves behind. The failure in §1 named a configuration key; the same failure here names step 2, its gate, and the command that fixes it.

One run, recorded. The play above, run twice — the second time after a failed cut-over:

run 1   step 1  green   schema applies to the rehearsal copy
        step 2  green   dual-write accepts on both schemas
        step 3  red     the cut-over leaves four reads on the old path
        step 4  —       not attempted; the approval was never requested
        verdict: failed at step 3 — fix the leaking reader, resume at step 3

run 2   step 3  green   no reads on the old path
        step 4  human:the-orchestrator approved, window 30m
        step 4  green   production serves the new schema, old path draining
        verdict: passed

The second run does not re-read the plan, re-run steps 1 and 2, or ask whether the migration applies. It starts at the first gate that is not green — which is the whole return on writing the play down.

Resumability comes from the id and the recorded gate status: a resumed run starts at the first step whose gate is not green. Idempotency comes from the action being repeatable — a step that cannot be run twice is a step that cannot be resumed.

✅ What to Check

  • Is each step's name a state that can be false?
  • Can each action run twice without harm?

3. When Not to Write a Procedure

A procedure is a maintenance liability: it must be kept true, and a stale one is worse than none because it is trusted.

Do not write one for:

  • a single edit — one file, one gate, no sequence to lose;
  • exploratory work — the destination is unknown, so the steps would be fiction;
  • a one-off migration — the procedure outlives its purpose and becomes archaeology.

Do write one when: the change repeats, it touches more than a handful of files, a gate can fail mid-way, or a human must approve something before it continues.

✅ What to Check

  • Take your procedures. Which ran once and never again? Delete them.
  • Which repeated change still has none? That is the next procedure.

4. The Play, the Engine and the Board

  • The play is the file that states the contract: the steps, the gates, the approvals. It lives in the repository, reviewed like code.
  • The engine is a mechanism: it runs the steps and records the outcome. Adopt it; never rebuild it.
  • The board is a view: what is in flight, what is blocked. Adopt it; never let it become the only place state exists.

A play that lives in the engine's configuration is a play that cannot be reviewed, diffed or tested — and disappears when the engine changes. This is the same rule as the Map: the rule lives where it is reviewed.

Gates that cannot pass are reported blocked. A gate that fails for a reason outside the run's control is not a failed step; it is a step that cannot proceed. Saying "blocked" with the exact command and the reason is the honest outcome. The state is this chapter's; the report and the decision are the next chapter's.

A Procedure Is Not a Pipeline

This is the question every engineer asks at this point, because a play looks like a CI workflow and is not one.

A CI workflow — Actions, GitLab, Jenkins A procedure
who runs it a runner, on a trigger, with no one watching an agent or a person, watched or not
what its steps are commands states that must become true, each with a check
approval not in the pipeline's vocabulary, or bolted on as a manual job a first-class field, at the step where it belongs
memory none — each run starts clean the run record, so a resume starts where the failure was
rollback a second workflow nobody wrote a field, tested before it is needed
when it is wrong the pipeline is red the step says which invariant is false

The two compose rather than compete. A procedure's gate is often a CI workflow: step 2's gate may be the integration workflow on the branch is green. The workflow is a mechanism inside a step; the procedure is the contract over the whole change, including the part no runner can do — deciding, approving, rolling back.

The paths make it obvious. The play lives in plays/, the pipeline in .github/workflows/ or .gitlab-ci.yml — if a play ever needs to sit in the pipeline's own directory to work, the engine has become the contract.

What would go wrong if you used the pipeline as the procedure? The run would begin at the first job and end at the last, with no line for the human decision that matters, no record of which step failed first, and no rollback that anyone rehearsed.

✅ What to Check

  • Is the play in the repository, or in the tool?
  • Can a blocked step be distinguished from a failed one?

5. Build the Play

Artefacts

Artefact What it is for Where it lives
play file the procedure, as the agent's contract plays/<name>.yaml — never a CI workflow directory
gate annotations the check per step, with its command inside the play
resume rule where a resumed run continues the play, or the Playbook
run record one procedure run, with its gates the execution log

Decisions

Choice Default What changes if you choose otherwise
where the play lives the repository tool configuration: unreviewable, unportable
step naming invariants activity names that cannot fail
approval points before anything irreversible a human asked at the end, when the choice is gone
blocked vs failed separate states one word for two situations, and a decision nobody makes

✅ Checks

  • Every step has a gate with a command; a step with no gate is a narration.
  • A resumed run starts at the first step whose gate is not green.
  • A blocked step names the command and the reason, and is never reported as passing.

Sequence

  1. Write the play for one repeated change. Checkpoint: each step names an invariant.
  2. Add a gate per step. Checkpoint: every gate can fail and name its fix.
  3. Mark the approval points. Checkpoint: no irreversible action runs before one.
  4. Run it once and record the gates. Checkpoint: the run record matches the play's steps.

Done When

  • One repeated change has a play whose steps are invariants.
  • A resumed run continues at the right step without re-reading the whole plan.
  • A blocked step is reported as blocked, with the command that would unblock it.

6. 🔑 Chapter Summary

A procedure is how a sequence becomes repeatable — and how a failure becomes legible.

  1. Sequences break when they live in prose: one gate at the end names the symptom, not the step.
  2. A step is action, gate, approval, resume — and its name is a state that can be false.
  3. Not every change needs a play — single edits, exploration and one-offs cost more than they save.
  4. The play is the file that states the contract; the engine is a mechanism and the board a view, and only the play belongs in your repository.
  5. Blocked is a state, not a failure — and never a pass.