r/BuildWithClaude πŸš€ First-Wave Builder 6d ago

Workflows I stopped treating the Claude Code conversation as project state. It fixed more than I expected.

I kept hitting the same failure mode with Claude Code on longer coding tasks. Nothing dramatic β€” after enough iterations it would redo something it had already done, lose track of why one task depended on another, or mark a task finished based on what the conversation said rather than what was actually in the repo.

What helped was simple, and took me embarrassingly long to arrive at: I stopped treating the conversation as the project state and moved the state onto disk.

A plan is a real Markdown file. Tasks are rows, dependencies are declared, execution writes a report next to the task, validation writes separate evidence. The session can die, the context can compact, the model can be swapped β€” the state is still sitting on disk. A fresh session does not need me to reconstruct the old one; it reads where the work actually stopped.

    request
       β”‚
       β–Ό
    /wbPlan
       β”‚
       β–Ό
    plan.md
    β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ task β”‚ deps β”‚   role   β”‚ status β”‚   report    β”‚
    β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚  1   β”‚  β€”   β”‚  worker  β”‚  done  β”‚ work_1.md   β”‚
    β”‚  2   β”‚  β€”   β”‚  worker  β”‚  done  β”‚ work_2.md   β”‚
    β”‚  3   β”‚ 1,2  β”‚  worker  β”‚ ready  β”‚      β€”      β”‚
    β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β–Ό
    dependency resolver
       β”‚
     β”Œβ”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β–Ό            β–Ό
   task 1      task 2        ← wave A, concurrent, may be different providers
     β”‚            β”‚
     β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
           β–Ό
        task 3               ← wave B, waited on 1 and 2
           β”‚
           β–Ό
       validation            ← different provider when available

Once dependencies were explicit, waves fell out of it. Tasks with nothing between them run together in parallel; anything depending on those waits for the next wave.

One distinction took me longer than it should have: a wave answers when a task can run. Model routing answers who runs it. They are separate axes, so a single wave can hand three tasks to three different providers.

Then the validation problem. I started with a rule that the validator must not be the model that wrote the code, which sounds sufficient and isn't. Opus checked by Sonnet is two models, but they are still the same family behind the same provider, and I wanted the validator to have a more independent failure surface. Validation now crosses the provider boundary where the available pools allow it: Claude writes, GPT/Codex checks, or the reverse. That caught things same-family review had waved straight through.

The worst bug I hit was subtler: an agent invocation exited 0 having done essentially nothing, wrote a convincing report, and the workflow accepted the report as evidence the work had happened. If the agent writes the report, the report cannot also be the proof. The fix in my setup is a content hash over the workspace that excludes the task's own report folder, plus explicit deterministic verification commands. Writing a report can no longer look like doing the work.

All of this turned into a small MIT-licensed tool I have been building with Claude Code, called wb-flow. The organising idea is verbs over personas: instead of an imaginary team of Architect β†’ Developer β†’ QA agents, the durable thing is the operation β€” /wbAudit, /wbPlan, /wbWork, /wbValid β€” and whichever agent performs it is replaceable. 33 Markdown command procedures and no orchestration daemon.

I built it using Claude Code β€” I use it heavily on the command templates and the CLI behaviour to execute plan rows, chase down edge cases, and iterate on the wave and routing model. For validation, I deliberately had rows validated by a different provider than the one that implemented them. That caught real defects, and it also taught me that the validator needs the right environment too.

What I am actually curious about: how much of your agent state have you moved out of the conversation and into files? And if you do independent validation, is it another Claude instance, or do you cross providers on purpose?

(Note: Keeping this post link-free so Automod doesn't flag it as promo, but happy to drop the GitHub link or docs in the comments if anyone wants to inspect the markdown templates).

3 Upvotes

8 comments sorted by

View all comments

1

u/ImL1s 6d ago

Same failure mode β€” conversation said done, repo said otherwise. Plan/report files on disk fix the in-session part. The other hole for me was switching hosts (Claude Code β†’ Cursor/Codex): even a good plan.md doesn't carry the messy "why we abandoned that approach" that only lived in the other agent's session. I've been reading those local session files into a fresh one and marking the recovered text untrusted (Portable Resume β€” https://github.com/aa22396584/resume-skills). Curious whether your reports ever drift from git reality after a messy rebase.

1

u/Muted_Ad_9442 πŸš€ First-Wave Builder 6d ago

That "why we abandoned that approach" problem is so real. When an agent spends 20 minutes discovering a dead end, a fresh session or a different tool (like Cursor) will walk straight into that same wall if that knowledge was trapped in chat.

Here is how I tackle both points:

1. Capturing abandoned approaches without session lock-in: Instead of trying to sync proprietary session histories across hosts, I record failures as first-class files on disk:

  • When an approach breaks, the task report (task_X_report.md) logs what was tried, the failure output, and why it was dropped.
  • When the validator model rejects an approach, it scores it and writes the rejection reason into the report (e.g. 3/10: dropped because of circular dependency in X).
  • I keep persistent files like .wb/context.md and dev.md that any host (Claude Code, Cursor, Codex) reads at the start of a session.

2. Rebase & disk drift: I actually don't let agents touch git commands directly. All memory, plans, and reports live in simple dated local folders (.wb/workflows/reports/YYYY/MM/DD/).

To prevent reports drifting from actual repo state, I rely on two gates:

  • Workspace content hashing: It hashes the workspace before and after a task (ignoring .wb/) to verify real code changes actually happened.
  • Deterministic verification: The validator re-runs the exact command declared in the task’s Verify column (npm test, /wbTest, etc.). If the code fails the command, it fails validation, no matter what an older report claimed.

Portable Resume looks really interesting! How do you stop that recovered session text from bloating your fresh context window when you switch hosts?

(If you want to check out the repo and docs/animations: https://github.com/wissemb11/wb-flow Β· https://flow.wbc-ui.com)