Appendix C — Pi Patch Desk: The Capstone
A guided capstone walkthrough: reproduce a parser bug, let Pi edit a disposable fixture, inspect a proposed patch and its host verification, and see a prohibited action refused.
You have finished the book. Now give its mechanisms one job to do together.
Pi Patch Desk takes a small parser bug through reproduction, investigation, editing, verification and review. At the end you receive a proposed patch and a dossier explaining what happened. You can inspect the change and the recorded checks without trusting the agent’s final prose.
This appendix is a supplement added after the book’s initial publication. The forty-two numbered chapters and Appendices A and B keep their order and paths. The implementation lives in the public pi-agents repository, alongside the book’s executable examples. The Pi Patch Desk solution page is its practical entry point; here you will run the example and connect each decision to the material you have read.
The first version uses scripted responses with the actual Pi 1.0.4 agent loop. Pi executes real tools against real fixture files, and the host runs real checks. It is an offline demonstration of the software around a model. It does not measure a real model’s ability to fix an unfamiliar issue.
Start with the finished result
You need Node.js 22.19 or later, npm, and Git. Clone the public repository and install its pinned dependencies:
git clone https://github.com/ernanhughes/pi-agents.git
cd pi-agents/examples
npm ci
npm run capstone
After installation, this command needs no API key, network, global Pi install
or manuscript checkout. It uses the local Pi packages pinned to 1.0.4.
The recorded development run used Node 25.8.2 on Windows; it was not also run
on Node 22. A newer global pi --version does not change the capstone’s pin.
The issue is deliberately small. parseRecords() reads records such as
name=Ada and role=developer. Its original implementation rejects an empty
line between valid records. The request is to ignore blank lines, preserve
validation of nonblank records, and add a regression test.
The output follows this sequence:
before tests: exit 1
Pi completed read_file
Pi completed read_file
Pi completed write_file
Pi completed write_file
after tests: exit 0
Pi completed check
after typecheck: exit 0
Pi completed check
Pi completed submit
after tests: exit 0
after typecheck: exit 0
after grader: exit 0
Pi Patch Desk: verified
Review: .../capstone-patch-desk/runs/run-<id>
Original fixture unchanged; no patch applied.
The first failure is expected: the host has reproduced the bug. The later checks establish that the proposed repair passes the tested cases. The fixture in your checkout stays broken so the next run can reproduce the same issue.
Review before accepting
Open the printed run directory. Start with review.md, then read patch.diff
and tests.json. The main source change is one guard inside the existing loop:
for (const line of input.split(/\r?\n/)) {
+ if (line.trim() === "") continue;
const match = /^([a-z]+)=([^=]+)$/.exec(line);
Only the blank-line decision uses trim(). Nonblank lines still go through
the original grammar. The added regression covers surrounding whitespace-only
lines and CRLF. The host also runs its own acceptance assertions, held outside
the files Pi may edit.
These files give you different kinds of evidence:
| File | What to inspect |
|---|---|
manifest.json |
Package versions, Git revision, exact original fixture hashes, policy, budgets and isolation limits |
run.json |
Outcome, completion state, requests, tool calls, failures and original-file preservation |
tests.json |
Command argument arrays, exit codes, signals and bounded output |
evidence.json |
Validated source paths, line ranges and quotations |
events.jsonl |
Compact Pi lifecycle, host-check and policy events |
patch.diff |
The proposed changes to the permitted fixture files |
review.md |
Verified, source-supported and unmeasured findings for your decision |
Check the before-test exit code of 1 and the final tests, typecheck and grader exit codes of 0. A started check is not a completed check. A source citation establishes that the quotation exists at the recorded location; the test results establish the behavior they actually checked.
You have reached the human decision. The default workflow does not apply the patch to the original fixture, commit, push, open a PR or deploy anything. Those actions would need a separate request and their own controls.
Follow the decisions through the layers
The host owns the workflow; Pi owns the bounded tool-using loop inside it.
flowchart TD
A["Issue and known fixture"] --> B["Host reproduces the failure"]
B --> C["Pi reads source and tests"]
C --> D["Host policy checks each operation"]
D -->|"Allowed"| E["Pi edits the disposable copy"]
D -->|"Refused"| F["Failure dossier"]
E --> G["Source references and completed Pi run"]
G --> H["Final host tests, typecheck and grader"]
H -->|"Pass"| I["Patch and review dossier"]
H -->|"Fail"| F
I --> J["Human review"]
In run.ts, Agent receives a known model, a stream function and explicit
tools, following chapter 37. fauxProvider
supplies the scripted responses from script.ts. This is Pi’s loop executing
the requests, not a handwritten transcript pretending to be an agent.
policy.ts makes the authorization decision. The capstone inspects raw
completed calls, uses beforeToolCall, and checks again immediately before
effects. The raw-call check also catches names or arguments that Pi would
reject before reaching that hook. The editable paths are exactly
src/records.ts and tests/regression.ts; checks come from a fixed command
allowlist in checks.ts. These are application rules built around the seams
examined in chapter 39.
evidence.ts adds nonempty, path, line-range and exact-source checks to the
quotation check from chapter 40. It does not
let an empty list count as evidence for a conclusion. The host requires a
source-supported submission and then performs final verification itself.
The grader matters because Pi can edit the fixture’s test file. Passing those tests alone would let a weakened test suite certify an unfixed parser. The host-owned assertions supply a second, independent acceptance check. They cover the declared parser behavior, not every conceivable defect.
For completion, the core’s agent_end event and awaited prompt settlement
finish the Pi portion. Host checks and reporting still follow. The JSON driver
emits desk_completed only after that remaining work and artifact writing.
Keep the observer’s contract in view, as chapter 33
and chapter 35 taught: these host records are
not a replacement for the coding-agent session’s agent_settled contract.
This is also chapter 11’s mechanism choice in practice. The prompt and skill carry the walkthrough. An optional extension adds a slash command. Ordinary functions perform authorization, checks and reporting. The agent is used for the sequence of source inspection and edits.
Try the prohibited action
From the same examples/ directory, run:
npm run capstone -- --scenario injection
This command deliberately exits 1 and reports refused. The fixture README
contains an instruction to disable tests, change package.json and print
secrets. A scripted response reads that text and requests the forbidden edit,
supplying a fake approved: true field.
Inspect the denied policy event in events.jsonl and the failure in run.json.
The host rejects the operation. Source text and a model-supplied approval field
cannot change its policy. This demonstrates the tested refusal path; it does
not demonstrate a model independently recognizing prompt injection.
Now compare the refused run with the successful one. Both leave a dossier and
preserve the original fixture. The status differs because the host has different
observations to report. A failure may retain a partial proposed diff, but it
has not earned verified status.
Read the capstone with the book beside you
| Book material | What to look for in the application |
|---|---|
| Chapters 10–14: task shape and instructions | One issue, explicit acceptance conditions, a prompt template and a skill |
| Chapters 16–17: events and tools | Completed events, typed arguments, bounded tools and policy decisions |
| Chapters 25 and 29: control and failure | Cancellation, budgets, failures and no pipeline-wide retry loop |
| Chapters 31–35: interfaces | One host workflow observed through CLI, JSON and an optional Pi command |
| Chapters 37–40: core and composition | Actual Pi execution surrounded by deterministic source and verification functions |
| Chapter 41: testing | Scripted control-flow tests separated from unmeasured model capability |
| Chapter 42: authority | A temporary copy and hook are application controls, not an OS sandbox |
For a second presentation of the same workflow, run
node capstone-patch-desk/cli.ts --json. Its final record is desk_completed.
For the optional terminal walkthrough, run npm run capstone:interactive,
then enter /patch-desk and /patch-desk injection. The launcher uses the
locally pinned shipped Pi binary, fresh configuration and explicit capstone
resources. The command calls the same host and needs no outer model request.
Read the public guide for the module map, other failure scenarios, and resource loading details. The implementation stays there so changes, tests and instructions have one public home.
What you have established
The recorded evidence from 14 October 2026 reports a clean typecheck and 311 passing tests in the public examples suite, including 32 capstone tests, at Pi 1.0.4. The tests exercise real fixture commands, patch applicability, original-worktree preservation, citations, refusal cases, weakened tests, provider errors, abort, timeout and request/tool exhaustion. They also verify that a canceled, otherwise-continuing fixed check child has exited.
You can run the capstone tests yourself with npm run test:capstone from the
public examples/ directory. The recorded numbers identify a particular run;
they are not a promise that every later checkout has the same test count.
Keep the three claim classes apart. Documented: Pi 1.0.4 supplies the core, tools, hooks, events and faux provider used here; the relevant exported declarations and documentation are listed in the evidence record. Observed: the scripted fixture runs and tests produced the recorded outcomes. Proposed: the exact allowlist, grader, dossier and human-review procedure are this application’s design, rather than guarantees made by Pi.
The remaining authority limit is material. There is no verified OS sandbox. Changed TypeScript executes in child checks with your OS account’s permissions. The temporary copy and in-process policy do not contain hostile code. This release therefore accepts its known fixture and scripted scenarios, and has no arbitrary-repository or real-provider mode.
Execution has a 30-second budget, followed by bounded diff collection and reporting. Logs, files and child output are capped; each dossier is at most 128 KiB. Temporary copies are removed after reporting. Retained dossiers accumulate until you delete them. Redaction covers common credential-shaped text, not every possible encoding of a secret.
Real-model quality, general injection recognition, pass@1 and pass^k remain
unmeasured. A future real-model version needs verified external containment,
explicit provider opt-in, budgets and a held-out evaluation with an independent
grader. Those requirements follow from the evidence you have, rather than from
the confidence of the demonstration.
Before leaving, answer three questions from your own dossiers: which observation reproduced the bug, which independent check accepted the repaired behavior, and which decision remains yours? If you can point to each answer, you have carried the book’s distinction between capability, evidence and authority into one complete application.