Chapter 20 | File-Based State Machine

10 MIN READ | UPDATED: 2026-05-15

Chapter 20: File-Based State Machine

Learning Objectives

Understand why state must persist in files instead of residing solely in-memory (main Claude's "memory")—this is the watershed for a system evolving from a "toy" to "production-grade."

In-Memory State vs. File-Based State

flowchart LR
    subgraph Bad["In-Memory State (Bad)"]
        M1["main Claude remembers
'Group 3 tests passed'"] end subgraph Good["File State (Good)"] F1["test-reports/3.md
**Status:** PASS"] end M1 -->|/clear / Crash| Lost["State Lost"] F1 -->|/clear / Crash| Recover["Recover by re-reading files"] style Bad fill:#ffcdd2 style Good fill:#c8e6c9

→ File-Based State = crash-safe + auditable + recoverable.

Complete State Machine

stateDiagram-v2
    [*] --> PENDING
    PENDING --> DEVELOPING : dispatch developer
    DEVELOPING --> TESTING : DEV_DONE
    TESTING --> DEVELOPING : FAIL
    TESTING --> REVIEWING : PASS
    REVIEWING --> DEVELOPING : REJECTED
    REVIEWING --> GROUP_DONE : APPROVED
    GROUP_DONE --> [*]

    DEVELOPING --> ESCALATION : round >= 3
    TESTING --> ESCALATION : fail >= 5
    REVIEWING --> ESCALATION : reject >= 3
    ESCALATION --> STUCK : architect dispatched
    ESCALATION --> DEVELOPING : developer-deep PATH B

    STUCK --> [*] : Human Decision

State Lookup Table (Core of CLAUDE.md)

Each state corresponds to which file to read and which field to check:

State Determination Method
PENDING All tasks for this group are - [ ] and review/N.md does not exist
DEVELOPING Some - [x] but not all
DEV_DONE All tasks in the group are - [x]
TEST_PASSED test-reports/N.md exists + **Status:** PASS
APPROVED review/N.md exists + **Status:** APPROVED
STUCK STUCK.md mentions group N
GROUP_DONE DEV_DONE && TEST_PASSED && APPROVED

→ main Claude re-reads files every turn to determine the state, avoiding caching.

Schema of State Files

Each state file must follow a fixed, parsable format:

# Review for Group 3

**Status:** APPROVED          ← This line is read by the state machine
**Reviewer Round:** 1         ← This counts the round number
**Reviewed Commit:** abc123

## Findings
(Specific content)

## Required Changes
(Only when REJECTED)

Format must be strict**Status:** APPROVED needs exact spacing, colons, and asterisks; missing any of these will prevent main Claude from parsing it correctly.

Relationships Between the Three Core State Files

flowchart TB
    Tasks["tasks.md
(checkbox checked status)"] -.-> ST1["DEV State"] TR["test-reports/N.md
**Status:** PASS|FAIL"] -.-> ST2["TEST State"] Rev["review/N.md
**Status:** APPROVED|REJECTED"] -.-> ST3["REVIEW State"] Stuck["STUCK.md
(Architect's Diagnosis)"] -.-> ST4["STUCK State"] ST1 --> Combined["Group N Combined State"] ST2 --> Combined ST3 --> Combined ST4 --> Combined style Combined fill:#c8e6c9

Pseudocode for State Determination

The logic running in main Claude's mind:

def get_group_state(N):
    if exists(f"STUCK.md") and N in STUCK.md:
        return "STUCK"
    
    tasks = parse_tasks_md()
    group_tasks = tasks[N]
    if all(t.checked for t in group_tasks):
        dev_done = True
    elif any(t.checked for t in group_tasks):
        return "DEVELOPING"
    else:
        return "PENDING"
    
    if exists(f"test-reports/{N}.md"):
        report = read(f"test-reports/{N}.md")
        if "**Status:** PASS" in report:
            test_passed = True
        else:
            return "DEVELOPING (rework)"
    else:
        return "TESTING (pending run)"
    
    if exists(f"review/{N}.md"):
        review = read(f"review/{N}.md")
        if "**Status:** APPROVED" in review:
            return "GROUP_DONE"
        else:
            return "DEVELOPING (rework)"
    else:
        return "REVIEWING (pending review)"

→ This is precisely what Step 3 in dev.md accomplishes.

Crash Recovery Demo

You run /dev 1
  ↓
Group 1 reaches the REVIEWING stage
  ↓
Your machine suddenly crashes / Claude Code crashes
  ↓
Restart Claude Code
You: /dev 1
  ↓
main Claude reads files:
  - tasks.md shows 1.1~1.4 all checked
  - test-reports/1.md has **Status:** PASS
  - review/1.md does not exist
  ↓
Determination: State = REVIEWING (pending review)
  ↓
Directly dispatches the reviewer, without redoing previous work

→ Perfect recovery, not a single step lost.

Hidden Benefits of This Design

✅ git diff immediately shows "what state changed this run"
✅ git log provides historical records, showing when each round occurred
✅ State can be read by external scripts (monitoring, reporting)
✅ Zero cost for switching devices (laptop → desktop)
✅ Multi-person collaboration (A runs halfway, B takes over) just by looking at files

Anti-Patterns

✗ main Claude uses chat history to record state
   → Lost after /clear

✗ State files lack a fixed schema
   → Inconsistent formats like "**Status: APPROVED**" and "**Status:** APPROVED"
   → Parsing fails

✗ Using emojis as status markers ("✅ Done")
   → Looks good, but parsing is fragile

✗ State scattered across multiple unrelated files
   → Restoring state requires reading 10 files = exhausting

✗ Writing state and then changing state
   → e.g., reviewer.md modifies tasks.md after writing a review → role transgression

What You Can Do Now

  • Map out the state machine for your own project
  • Design the schema for each state file
  • Explain how crash-safety is implemented
  • Understand why it's necessary to "re-read files every turn instead of caching"

Milestone Summary: What You Can Achieve After Chapter 20

flowchart LR
    Ch1to10["Ch 1~10
First change
(Knowledge Layer Foundation)"] --> Ch11to13["Ch 11~13
spec/design/tasks
Runnable"] Ch11to13 --> Ch14to18["Ch 14~18
Multi-agent Design
Including Escalation Chain"] Ch14to18 --> Ch19to20["Ch 19~20
CLAUDE.md
+ State Machine"] Ch19to20 --> You["✓ Possess complete
'Governance Layer + Knowledge Layer'
Awaiting integration with Tool Layer"] style You fill:#c8e6c9

Core Checkpoint: By now, you should be able to:

  • Write a 4-artifact set (proposal/design/spec/tasks) for your own project
  • Design agent files for 4-6 roles
  • Write a CLAUDE.md to make main Claude act according to the rules
  • Explain how the entire state machine and escalation chain work

If not yet—go back to the corresponding chapters and redo the exercises.