Skip to content

Add agentic TDD loop: run_tests tool, TDD state machine, and phase gates - #1

Merged
scardoso-lu merged 3 commits into
masterfrom
claude/agentic-tdd-loop-9M9OP
May 29, 2026
Merged

Add agentic TDD loop: run_tests tool, TDD state machine, and phase gates#1
scardoso-lu merged 3 commits into
masterfrom
claude/agentic-tdd-loop-9M9OP

Conversation

@scardoso-lu

Copy link
Copy Markdown
Owner

Closes the five structural gaps identified in the TDD analysis:

  1. run_tests compound tool (src/tools/run_tests.js)

    • Runs auto-detected test suite and returns structured output:
      { passed, failed, errors, skipped, failures[{name, message}], raw }
    • Per-framework parsers for pytest, jest, vitest, go test, cargo test,
      mocha, node:test — no more small-model output parsing
    • test_filter arg maps to each framework's native pattern flag
      (pytest -k, jest --testNamePattern, go -run, cargo positional, etc.)
  2. TDD state machine (src/session/tdd_state.js)

    • Tracks phase: idle → red → green → refactor → idle
    • beginCycle(testName) / confirmRed / advanceToGreen / enterRefactor /
      completeCycle — each with guard checks before transitioning
    • checkToolCall(name, args) blocks impl writes before red is confirmed,
      blocks test edits during green phase
    • phasePrompt() injects current phase context into the system prompt
    • Persists to .smallcode/tdd_state.json across session restarts
  3. TDD governor (src/governor/tdd_governor.js)

    • processTestResult(result) drives automatic phase transitions after
      every run_tests call — confirmRed, advanceToGreen, completeCycle
    • checkToolCall delegates to state machine for phase gates
    • Singleton, reset between test runs
  4. Tool wiring (bin/tools.js, bin/executor.js, src/api/index.js)

    • run_tests, tdd_begin_cycle, tdd_status, tdd_advance, tdd_reset
      added to COMPOUND_TOOLS and executor switch
    • TDD gate checked before each tool execution in the agent loop
    • Phase prompt injected into system prompt on every turn
  5. Updated skills/tdd.md — references new tools and state machine;
    documents phase gates and when each tool should be called

79 new tests across run_tests.test.js, tdd_state.test.js, tdd_governor.test.js

https://claude.ai/code/session_01S8ieQDoUu2nhnLNZYcLaR1

claude added 3 commits May 29, 2026 23:26
Closes the five structural gaps identified in the TDD analysis:

1. run_tests compound tool (src/tools/run_tests.js)
   - Runs auto-detected test suite and returns structured output:
     { passed, failed, errors, skipped, failures[{name, message}], raw }
   - Per-framework parsers for pytest, jest, vitest, go test, cargo test,
     mocha, node:test — no more small-model output parsing
   - test_filter arg maps to each framework's native pattern flag
     (pytest -k, jest --testNamePattern, go -run, cargo positional, etc.)

2. TDD state machine (src/session/tdd_state.js)
   - Tracks phase: idle → red → green → refactor → idle
   - beginCycle(testName) / confirmRed / advanceToGreen / enterRefactor /
     completeCycle — each with guard checks before transitioning
   - checkToolCall(name, args) blocks impl writes before red is confirmed,
     blocks test edits during green phase
   - phasePrompt() injects current phase context into the system prompt
   - Persists to .smallcode/tdd_state.json across session restarts

3. TDD governor (src/governor/tdd_governor.js)
   - processTestResult(result) drives automatic phase transitions after
     every run_tests call — confirmRed, advanceToGreen, completeCycle
   - checkToolCall delegates to state machine for phase gates
   - Singleton, reset between test runs

4. Tool wiring (bin/tools.js, bin/executor.js, src/api/index.js)
   - run_tests, tdd_begin_cycle, tdd_status, tdd_advance, tdd_reset
     added to COMPOUND_TOOLS and executor switch
   - TDD gate checked before each tool execution in the agent loop
   - Phase prompt injected into system prompt on every turn

5. Updated skills/tdd.md — references new tools and state machine;
   documents phase gates and when each tool should be called

79 new tests across run_tests.test.js, tdd_state.test.js, tdd_governor.test.js

https://claude.ai/code/session_01S8ieQDoUu2nhnLNZYcLaR1
The TDD system now drives a full loop across a list of requirements,
not just a single cycle. The loop only exits when every requirement
has a passing test AND a clean full-suite regression run confirms no
regressions.

Changes:

TDDStateMachine (tdd_state.js):
- New loop mode: initRequirements(list) registers requirements as
  pending, arms the loop, and resets any in-flight cycle
- Requirements tracked as {id, text, status: pending|active|done}
- After skipRefactor/completeCycle in loop mode, _finishCycle()
  auto-advances: marks requirement done, activates the next one,
  returns {loopAdvanced, nextRequirement} for the governor to relay
- allRequirementsDone() / loopComplete() / markRegressionClean()
  for the two-condition completion gate
- phasePrompt() now renders a requirements checklist with ✓/→/○
  markers showing loop progress
- Both modes (single-cycle and loop) persist to tdd_state.json

TDDGovernor (tdd_governor.js):
- processTestResult() handles the IDLE+loop case: after all
  requirements are green, a clean full-suite run triggers
  markRegressionClean() and emits "LOOP COMPLETE"
- Prompts for next requirement when idle between cycles

New tool:
- tdd_loop(requirements[]) — entry point; calls initRequirements,
  resets governor singleton, returns requirements checklist + first action

Updated tools:
- tdd_status — shows full requirements checklist in loop mode
- tdd_advance — skip_refactor auto-advances loop to next requirement

97 tests pass (56 state, 13 governor, 28 run_tests)

https://claude.ai/code/session_01S8ieQDoUu2nhnLNZYcLaR1
The TDD loop now runs without the model knowing TDD protocol.
The model only needs to write tests and implementation — the harness
handles phase transitions automatically.

Harness post-write hook (_tddPostWrite / executeToolWithTDD):
- Wraps executeTool in bin/executor.js and _executeTool in src/api/index.js
- Fires after every successful write_file / patch / append_file / read_and_patch
  when a TDD loop is active
- Runs run_tests automatically (filtered to target test in RED/GREEN,
  full suite in REFACTOR or when all requirements are done)
- Auto-begins cycle: if idle + test file written + failures detected,
  infers the test name from the first failure and calls beginCycle()
- Calls governor.processTestResult() to drive phase transitions
- Appends "[harness] run_tests: <summary>" to the tool response so
  the model sees the result without having called run_tests itself

Tool surface visible to the model reduced from 5 TDD tools to 2:
- tdd_loop(requirements[]) — entry point
- tdd_status — read current progress

tdd_begin_cycle, tdd_advance, tdd_reset remain executable via the
harness internally but are no longer in the model-facing schema.

skills/tdd.md reduced from 66 lines to 14:
  "call tdd_loop, write tests and implementation, harness handles the rest"

115 tests pass

https://claude.ai/code/session_01S8ieQDoUu2nhnLNZYcLaR1
@scardoso-lu
scardoso-lu merged commit 3354163 into master May 29, 2026
scardoso-lu added a commit that referenced this pull request May 30, 2026
Merge pull request #1 from scardoso-lu/claude/agentic-tdd-loop-9M9OP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants