ERPAVal, a Gated Six-Phase Workflow for Claude Code Agents
Updated
- Autonomous Dev
- Workflow
- Claude Code
A coding agent can finish a task and leave the next session to rediscover everything. ERPAVal adds explicit gates to the workflow and saves what each session learns. It is a six-phase loop for Claude Code: understand the codebase, research, plan, implement, validate, and carry useful lessons into the next run.
The problem #
For single-file changes, the basic loop works: paste a feature request into Claude Code, get working code back, ship it. The loop breaks when a task touches multiple modules, depends on unfamiliar APIs, or requires coordinating work across files that reference each other. And it breaks in a second, quieter way: the next session starts from scratch, even though the previous session just spent two hours learning the codebase's peculiarities.
The first failure mode is subtle. The agent produces something that compiles and passes a surface check, but invents a pattern that does not match the rest of the codebase, calls a deprecated API because its training data is stale, or duplicates logic that already exists three directories over. The code works in isolation without understanding the system it lives in.
The failure mode of unstructured AI coding is plausible code that does not belong, written by an agent that forgot last week's lessons.
The second failure mode is more expensive over time. Imagine a run that extracts a hard-won insight about the codebase (that SCIP replaces LSP cleanly here, that the build depends on the monorepo's dist/ aliases, that tsconfig project references go stale on package removal), and then the conversation ends, the context window closes, and the insight evaporates. Tomorrow's run rediscovers the same thing, if it is lucky. More often it rediscovers the lesson halfway through the work and wedges trying to unwind an assumption it should never have made.
Reading a codebase is slower than writing new code. It is slower still for a model with no durable memory of last week's architecture decisions. ERPAVal makes that upfront investment explicit and systematic, and it makes the compounding of that investment explicit too.
The six phases #
Explore and Research run in parallel, since they have no data dependency on each other. Everything after Gate 0 is sequential: Plan cannot start without both E and R completed, Act cannot start without an approved Plan, Validate cannot start with incomplete implementation, and Compound cannot start until the work has merged. The task system enforces the gating mechanically, so it does not depend on anyone's discipline.
What a "gate" is. The gates are mechanical dependency blockers the agents clear on their own. addBlockedBy wires Plan to depend on Explore and Research, every implementation task to depend on Plan, and Validate to depend on every implementation task. The orchestrator reads TaskList and advances the flow the moment predecessors flip to completed. No human waits on a button. The one exception is Gate 1 (Plan → Act), which is deliberately a human design-review checkpoint, because catching a wrong abstraction here saves hours of agent rework later.
Before the phases: adaptive intake #
The user does not see the phase flow first. Before Explore ever starts, the orchestrator runs a chain of classifiers that decide which phases apply to the task at hand. Most methodology write-ups skip this part, because it is the least photogenic, but it is where most of the practical value lives. A workflow that runs its full machinery on a one-line bug fix is a workflow nobody will use.
| Classifier | Decision | Effect |
|---|---|---|
| CL-SCOPE | Is this a coding task? | Non-coding routes to a research, PRD-writing, or presentation skill. |
| CL-COMPLEXITY | One-file fix, multi-module, or rip-and-replace? | One-file skips ERPAVal entirely. The rest of the flow runs. |
| CL-RESUME | New session or resume a prior one? | New scaffolds a fresh session-<hex>/ on disk. Resume reads the last session's state and continues from the last completed gate. |
| CL-DIR | Empty dir, existing code, or rebuild-in-place? | Empty skips Explore and starts at Research. Rebuild explores both the existing system and the target patterns. |
| CL-RIGOR | Is the problem crisp, or does it need HMW / EARS framing? | Crisp skips both. Fuzzy problems get a How-Might-We framing substep. Contract-unclear tasks get an EARS specification substep. |
| CL-SPEC | Are PRD, stack, and concept ready? | Missing prerequisites loop back through product-discovery and build-stack skills until ready. |
| CL-VALIDATE | All three validation layers green? | Failure routes back to Act with scoped fix packets. |
| CL-LESSONS | Did the session produce novel, reusable learnings? | Yes writes to .erpaval/solutions/. No skips the write. |
Each classifier is a strict-JSON prompt run against the current context. Every verdict appends to a classifier_trace in the session's YAML record, so the routing decisions are auditable after the fact. The user never picks from a menu. Claude judges, and the trace shows why.
The newest member of that chain is CL-RESUME. It answers a question the first version of ERPAVal did not ask: should this ask start a fresh session, or continue the one from yesterday? If the ask references a prior session, or the work overlaps the module and goal of a session whose last disk activity was within 72 hours, the classifier resumes. Otherwise it scaffolds a new session directory. This matters because the Compound phase at the other end of the flow is coupled to that session directory. Without one on disk, the Stop hook that nudges Claude to extract lessons has no anchor, and Compound silently no-ops.
A workflow that runs its full machinery on a one-line bug fix is a workflow nobody will use. Adaptive classifiers make the structure earn its weight.
The phases in detail #
0. Session 0, the mandatory intake scaffold #
Two tool calls run before any classifier except SCOPE and COMPLEXITY. Running erpaval-recall.py bootstrap comes first and always; it surfaces the category counts and index path from .erpaval/solutions/. Cold repos print "no prior lessons" and proceed; warm repos start the session already aware of what the codebase has taught previous sessions.
The second, for multi-module and rebuild tasks only, is either erpaval-new.py, which creates .erpaval/sessions/session-<hex>/intake.yaml and ensures the .gitignore entry, or a read of the prior session's session.yaml if CL-RESUME picked resume. This step exists for exactly one reason: without a session directory on disk, the Compound phase at the end of the flow cannot recognize the session and will silently skip writing lessons. Making the scaffold mandatory at intake removes the most common way the compounding loop fails to close.
1. Explore #
The Explore phase answers: what does this codebase look like, and where do my changes land?
A dedicated exploration agent, or several in parallel across different areas, reads the project structure, traces module boundaries, and catalogs patterns for error handling, logging, dependency injection, and testing. It identifies the build toolchain, linting configuration, and test conventions. The output is a structured summary: architecture patterns, file locations, naming conventions, test infrastructure. This becomes the conventions section that every implementing agent receives later.
Explore is read-only: no files are created or modified, and the agent is building understanding rather than artifacts. That constraint prevents the common failure mode where an agent starts exploring and then quietly begins implementing before it has the full picture.
2. Research #
Research addresses the staleness problem. An agent's training data has a cutoff. The library you are integrating shipped a breaking change last month. The API you are calling deprecated an endpoint. The framework version in your lockfile has different patterns than what the model learned.
A code-researcher agent fetches current documentation via Context7, DeepWiki, or web search. It checks package versions against what is in your lockfile, pulls API signatures, usage examples, and migration guides. The output is a dependency inventory with version pins and concrete code patterns.
Research runs in parallel with Explore. They answer different questions: Explore asks what our code looks like, Research asks what the external tools expect. Launching both simultaneously halves the pre-coding phase without sacrificing either dimension.
3. Plan #
The Plan is the single most consequential artifact in the entire flow. A good plan means Act executes cleanly; a bad plan means agents step on each other, duplicate work, or produce incompatible interfaces.
Planning decomposes the implementation into atomic tasks, each completable by a single agent in isolation. Tasks are grouped into waves that can run in parallel within the wave, with explicit dependency edges between waves. When the intake included an EARS specification from the rigor substep, the plan derives one implementation task per acceptance criterion, carrying the AC's parallel-safe flag forward so the orchestrator can launch safe tasks concurrently.
Wave 1 (parallel):
Task A: Create data models → blocks C, D
Task B: Add API route stubs → blocks D
Wave 2 (parallel):
Task C: Implement service layer → blocks E
Task D: Implement API handlers → blocks E
Wave 3:
Task E: Integration tests
Each task includes success criteria: what tests must pass, what type checks must clear, what lint rules must hold. These criteria are mechanical, so a subagent can verify them without human judgment.
The plan is also the first review gate. A senior engineer reviews the task graph (about 50 lines of structured YAML) and approves the architecture before any code is written. Catching a wrong abstraction boundary here saves hours of agent rework later, which is why Gate 1 is the one place a human stays in the loop. Expect two to four revision rounds before it clears; the gate is a design-review checkpoint rather than a rubber stamp.
4. Act #
Each task in the plan becomes a delegation to a subagent. The context packet is the complete briefing each implementing agent receives, and it is also the agent's work log, a single Markdown file that the agent edits section-by-section as it works, following a write protocol that sets status, summary, and a running log in place. The orchestrator never polls the agent's output stream. It watches the packet files with wc -l, and a task whose line count is identical across two consecutive check-ins is flagged as stuck.
Context Packet Structure (10 sections)
- Objective: what to build, one sentence, restated from the acceptance criterion
- Scope: exact files to create or modify, plus files that must not be touched
- EARS requirement: the acceptance criterion pasted verbatim from the spec
- Architecture context: excerpt from Explore: patterns, dependency direction, error handling, test style
- API contracts: exact signatures, types, interfaces the work must match
- Conventions: naming, imports, async discipline, from Explore
- Dependencies: pinned versions, breaking changes, known pitfalls, from Research
- Prior lessons: specific
.erpaval/solutions/files the recall step scored as relevant - Success criteria: static-check baseline plus task-specific mechanically verifiable checks
- Anti-goals: no refactoring, no new dependencies, no new abstractions; report missing prereqs instead of improvising
Each subagent is an expert developer with zero context. It can write excellent code, but it knows nothing about your codebase, your conventions, or your architecture. The context packet is what transforms a general-purpose coding agent into a specialist for your system. The Prior lessons section is what transforms a specialist into a specialist who has already seen this class of problem before.
Tasks within a wave launch in parallel. When all of Wave 1 completes, Wave 2 begins. The orchestrator also does eager unblocking: after each completion, it scans the dependency graph for any downstream work whose blockers have all cleared, and launches immediately rather than waiting for its sibling tasks. On a 26-task run this saves about 30 to 40 percent of wall-clock time compared to strict wave-by-wave execution.
When a task gets stuck, the recovery path is defined. The first three in-task fix attempts happen via SendMessage to the same worker. On attempt four, the orchestrator runs the CL-C2 classifier against the packet and the last error, and dispositions the situation as one of: apply a one-to-two-line fix inline, respawn a fresh worker with the same packet, or route to a missing-prereq replan that inserts a new task and re-wires the dependency graph. None of these recovery paths involves a human picking from a menu.
5. Validate #
Layer 1, static checks. The project's existing toolchain: ruff check plus ruff format plus pytest for Python, pnpm lint plus pnpm typecheck plus pnpm test for TypeScript, and so on. Fast and automated, sub-second lint and sub-minute type checking. The closed-loop toolchain is designed for this: Rust-based tools like ruff (about 100x faster than pylint) and biome (about 50 to 100x faster than eslint) give agents a tight feedback loop.
Layer 2, code quality review. A dedicated Opus agent analyzes the complete diff for tech debt creep, DRY violations, dead code, convention drift, and API surface bloat. This catches the things static tools miss: a function that compiles but does not match the codebase's patterns, duplicated logic across files, unnecessary complexity.
Layer 3, security scanning. Semgrep with OWASP Top 10 rules, language-specific tools (bandit for Python, npm audit for Node), dependency vulnerability checks, and an Opus-powered security review for logic flaws that static tools miss.
If any layer fails, the cycle loops back to Act with scoped fix packets on just the failing tasks. The fix-to-validate loop is fast because all checks are local and deterministic. The agent writes a fix, re-runs lint in about 300 milliseconds, re-runs type checking in about 800 milliseconds, re-runs module tests in about 2 seconds. The full cycle takes under 4 seconds, against 60 to 300 seconds for a CI roundtrip.
6. Compound #
Compound is the phase most methodologies forget. It runs after Gate 2 clears and the work merges. The CL-LESSONS classifier reads the trace from first tool call through final validation and identifies candidate learnings along two tracks: bug-track lessons are root causes uncovered during fix cycles (the C2 and C4 loops), and knowledge-track lessons are architectural or API patterns surfaced during Explore and Research that a later run would not infer on its own. Each candidate is filtered on two criteria: novel (no existing entry in .erpaval/solutions/ already covers it) and reusable (likely to apply elsewhere, rather than a one-off hack).
Surviving lessons are written to .erpaval/solutions/<category>/<slug>.md with YAML frontmatter carrying tags and module scope. The next session's recall step greps this directory with a path-boundary match on module and a tag-overlap score, and the top-scoring lessons are pasted directly into the Prior Lessons section of each task's context packet.
That is the compounding loop. A lesson learned in March shows up in an Act packet in May without anybody having to remember it was there.
A session that ends without Compound only wrote code. A session that ends with Compound wrote code and made the next session smarter.
Why gates matter #
The gates are the workflow. Without them, ERPAVal is a checklist. With them, it is a mechanical constraint that prevents the most expensive failure mode in AI-assisted development: acting on incomplete understanding. No planning happens until the codebase and dependencies are understood, no code is written until the architecture is approved, and no merge happens on partial or unsafe work.
AI agents are eager. Given a vague instruction, they start coding immediately. ERPAVal's gates are a structural override: you cannot code until you have proven you understand the system.
The closed-loop toolchain #
ERPAVal's fix-to-validate speed depends on every check being local, fast, and deterministic:
| Principle | Implementation |
|---|---|
| All-in-one tools | ruff replaces 6 Python tools. biome replaces eslint and prettier. |
| Rust-based speed | ruff, ty, uv, biome, all 10 to 100x faster than their predecessors |
| Task runner | mise run check, one universal interface; agents do not need to know which tools sit behind it |
| Targeted tests | Run the changed module's tests, not the full suite. The full suite runs only at final validation. |
Tight loop (agent): Loose loop (CI):
write → lint (0.3s) write → push → wait (60-300s)
→ fix → lint (0.3s) → get error → re-read code
→ typecheck (0.8s) → fix → push → wait again
→ test module (2s)
→ done (3.4s total)
The tight loop is what makes Act-to-Validate-to-fix-to-revalidate fast enough to feel iterative rather than batch. An agent that waits five minutes for CI feedback will context-switch and lose coherence. An agent that gets feedback in three seconds can fix and retry in a single thought.
When to use ERPAVal #
The CL-COMPLEXITY classifier makes this decision for you, but the underlying heuristic is worth stating plainly.
| Scenario | Classifier verdict |
|---|---|
| Feature touching multiple modules | Multi-module → full flow |
| Bug fix in a single file | One-file-fix → skip ERPAVal |
| Greenfield project setup | Multi-module plus empty-dir → skip Explore, start at Research |
| Rip-and-replace rebuild | Rebuild → full flow with a destructive first wave |
| Refactoring with behavioral preservation | Multi-module → full flow |
| Integrating a new dependency or API | Multi-module → heavy Research phase |
| Quick script or one-off tool | One-file-fix → skip ERPAVal |
The heuristic is the same as it was: if a senior engineer would want to review the approach before coding starts, use ERPAVal. If not, just code. The classifier chain makes this judgment on every request, so the full flow only runs when it is earning its weight.
In practice #
I have been running ERPAVal as a daily driver across about a dozen Claude Code projects. Over the last two weeks, the skill fired 28 times across 22 distinct sessions, and roughly three quarters of those triggered automatically from the skill description rather than from me typing the slash command. The sessions themselves were large: assistant message counts ran from 89 to 1,458, and a single open-code-hub rebuild session fired 138 subagent spawns and burned 2.3M output tokens over an overnight run.
The tool-call shape confirms the task-gated, parallel-subagent pattern is running: across those sessions, 516 TaskCreate and 1,249 TaskUpdate calls, 363 Agent calls, and a subagent mix dominated by general-purpose Act workers (229 spawns), the researcher role (57), and the built-in Explore subagent (56). The ratio of TaskCreate to TaskUpdate, about one to two and a half, tells you the gating is real. Every task gets wired, started, and closed; the dependency edges are live.
One illustrative session: a clean-room reimplementation of an internal code-graph tool. Three parallel agents ran Explore plus Research. Planning produced a task graph with nearly thirty implementation tasks across four waves, wired with explicit addBlockedBy dependencies. Act dispatched agents in waves with eager unblocking as soon as transitive blockers cleared, and Compound at the end wrote 13 durable lessons to .erpaval/solutions/ on SCIP replacing LSP, monorepo path aliases, zero-indexed-vs-one-indexed graph semantics, and a handful of conventions specific to the repo. A subsequent session in the same repo, two days later, pulled three of those lessons into its Act packets before writing a line of code. That is the compounding loop closing in practice.
Agent output drops in quality when sessions start with "build me X" and no structure, and the agent improvises a path forward. ERPAVal makes the context investment explicit, and the memory layer makes it cumulative.
The parallel execution alone would be worth the workflow overhead: three agents researching simultaneously, four agents implementing simultaneously, an order of magnitude faster than a single-thread session. The compounding is what makes the workflow pay rent over time. A lesson written in week one saves a dead-end in week three.
ERPAVal is implemented as a Claude Code skill. Typing /erpaval loads the full workflow (phase definitions, classifier prompts, context-packet templates, validation playbook, compound procedure) and the orchestrator follows it mechanically. The skill includes reference files for execution mechanics, planning patterns, delegation templates, and validation configurations, plus three imperative Python tools (erpaval-new.py, erpaval-recall.py, erpaval-validate.py) and three hooks that enforce session start, packet schema, and end-of-session compound nudging. It is a structured workflow rather than a prompt. The source is at github.com/laithalsaadoon/erpaval.
What is your approach to structured AI-assisted development? If you are running multi-agent coding workflows or have developed your own methodologies, I want to hear about it. Reach out on LinkedIn.
Before a plan reaches the execution gate, symspec can check structured requirements for contradictions. That is a narrower, testable claim than asking a reviewer whether a spec looks right.