Appearance
An ADW State File is the JSON that threads an identity through subprocesses — the ADW ID, branch, plan path, ports, phase history — so a crashed run can resume and composite pipelines can chain.
Primitive
ADW State File
The artifact
Identity, not content. Small, fast to read.
agents/cc73faf1/adw_state.json
{"adw_id": "cc73faf1",← the thread through everything"issue_number": 47,"issue_class": "feature","branch_name": "feat-47-cc73faf1-oauth2","plan_file": "specs/issue-47-adw-cc73faf1.md","worktree_path": "trees/cc73faf1",← where the run lives"backend_port": 9107,"frontend_port": 9207,"model_set": "base","all_adws": ["cc73faf1"],← correlation across composites"phase_history": [← append-only replay log{"phase": "plan", "success": true},{"phase": "build", "success": true} ]}
The gate at the front
State is identity. Content is not state.
belongs in state
Identifiers + correlation data
- adw_id, issue_number, issue_class
- branch_name, plan_file, worktree_path
- backend_port, frontend_port, model_set
- all_adws[], phase_history[]
The test: lose this and you can't reconstitute the workflow.
NOT in state
Content that lives elsewhere
- The plan itself (lives in specs/)
- The codebase (lives in the worktree)
- Agent working memory (stays in-context)
- Tool outputs, summaries, logs
The test: lose this and you can regenerate from git + spec.
Mixing state + content makes the file grow unboundedly. State was supposed to be small and fast; now it's the thing you parse before every phase.
The save discipline
Atomic writes. Crash-safe.
01
Write to temp
state.json.tmp
→
02
fsync
flush to disk
→
03
rename
.tmp → state.json
Rename is atomic on POSIX. The reader either sees the old state or the new state — never a half-written file. A crashed process leaves state.json.tmp around (cleanup-able) but the canonical file stays valid.
Why phase_history exists
Replay without forensics.
[01] ✓2026-04-16 10:00 plan success[02] ✓2026-04-16 10:15 build success[03] ✕2026-04-16 10:28 test failed ← replay here[04] — commit pending
Without phase_history, replay is forensic — grep scattered logs, guess which phase ran last, hope the worktree is still in the expected state.
With it, the decision is mechanical — read the history, find the last success: false, re-invoke that phase.
What breaks if you cut corners
Four failure modes. All common.
State in prompts
Correlation IDs embedded in prompt text. Parsing back requires regex. Regex breaks on model updates.
Per-phase schemas
Phase N+1 can't read Phase N's state. Composite workflows collapse because each phase drifts.
Non-atomic writes
Corrupted state on crash. Recovery becomes manual. A half-written file is worse than no file.
State + content mixed
File grows unboundedly. State was supposed to be small; now it's slow to parse between phases.
The discipline
State is the thread, not the tapestry.
A Pydantic schema so phases can't disagree on shape. Atomic writes so a crash doesn't corrupt it. Append-only phase history so replay is mechanical. Five-to-ten fields, never fifty. The state file is what makes a multi-phase pipeline survive a crashed laptop — and that's its only job.