Skip to content

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.