ntcoding/tdd-process
Strict test-driven development state machine with red-green-refactor cycles. Enforces test-first development, meaningful failures, minimum implementations, and full verification. Activates when user requests: 'use a TDD approach', 'start TDD', 'test-drive this'.
npx skills add https://github.com/NTCoding/claude-skillz --skill tdd-process
In Plan Mode: Plans should be test specifications, not implementation designs. Include key insights, architectural constraints, and suggestions—but never the full implementation of production code.
EVERY SINGLE MESSAGE MUST START WITH YOUR CURRENT TDD STATE
Format:
🔴 TDD: RED
🟢 TDD: GREEN
🔵 TDD: REFACTOR
⚪ TDD: PLANNING
🟡 TDD: VERIFY
⚠️ TDD: BLOCKED
NOT JUST THE FIRST MESSAGE. EVERY. SINGLE. MESSAGE.
When you read a file → prefix with TDD state
When you run tests → prefix with TDD state
When you explain results → prefix with TDD state
When you ask a question → prefix with TDD state
Example:
⚪ TDD: PLANNING
Writing test for negative price validation...
⚪ TDD: PLANNING
Running npm test to see it fail...
⚪ TDD: PLANNING
Test output shows: Expected CannotHaveNegativePrice error but received -50
Test fails correctly. Transitioning to RED.
🔴 TDD: RED
Test IS failing. Addressing what the error message demands...
🚨 FAILURE TO ANNOUNCE TDD STATE = SEVERE VIOLATION 🚨
<meta_governance>
🚨 STRICT STATE MACHINE GOVERNANCE 🚨
Before each response: Verify your claimed state matches your tool call evidence.
If mismatch: 🔥 STATE VIOLATION DETECTED → announce correct state → recover.
State announcement: Every message starts with 🔴 TDD: RED (or current state).
Forgot prefix? Announce violation immediately, then continue.
</meta_governance>
<state_machine>
<diagram>
user request
↓
┌──────────┐
┌────│ PLANNING │────┐
│ └─────┬────┘ │
│ │ │
│ test fails │
│ correctly │
unclear │ ↓ │ blocker
│ ┌──────────┐ │
└────│ RED │ │
│ │ │
│ Test IS │ │
│ failing │ │
└────┬─────┘ │
│ │
test │ │
passes │ │
↓ │
┌──────────┐ │
│ GREEN │ │
│ │ │
│ Test IS │ │
│ passing │ │
└────┬─────┘────┘
│
refactoring │
needed │
↓
┌──────────┐
┌────│ REFACTOR │
│ │ │
│ │ Improve │
│ │ design │
│ └────┬─────┘
│ │
│ done │
│ │
│ ↓
│ ┌──────────┐
│ │ VERIFY │
│ │ │
│ │ Run full │
fail │ │ suite + │
│ │ lint + │
└────│ build │
└────┬─────┘
│
pass │
│
↓
[COMPLETE]
</diagram>
<states>
<state name="PLANNING">
<prefix>⚪ TDD: PLANNING</prefix>
<purpose>Writing a failing test to prove requirement</purpose>
<pre_conditions>
✓ User has provided a task/requirement/bug report
✓ No other TDD cycle in progress
</pre_conditions>
<actions>
10. If failure is "method doesn't exist" - implement empty/dummy method and re-run from step 6
11. Repeat until you get a "meaningful" failure
12. Improve the code to produce a more explicit error message. Does the test failure provide a precise reason for the failure, if not ask the user if they want to make it better.
13. Transition to RED
</actions>
<post_conditions>
✓ Test written and executed
✓ Test FAILED correctly (red bar achieved)
✓ Failure message shown to user verbatim
✓ Failure reason justified (proves test is correct)
✓ Failure is "meaningful" (not setup/syntax error)
</post_conditions>
<validation_before_transition>
BEFORE transitioning to RED, announce:
"Pre-transition validation:
✓ Test written: [yes]
✓ Test executed: [yes]
✓ Test failed correctly: [yes]
✓ Failure message shown: [yes - output above]
✓ Meaningful failure: [yes - justification]
Transitioning to RED - test is now failing for the right reason."
</validation_before_transition>
<transitions>
</transitions>
</state>
<state name="RED">
<prefix>🔴 TDD: RED</prefix>
<purpose>Test IS failing for the right reason. Implement ONLY what the error message demands.</purpose>
🚨 CRITICAL: You are in RED state - test IS CURRENTLY FAILING. You MUST implement code and see test PASS, code COMPILE, code LINT before transitioning to GREEN.
DO NOT transition to GREEN until you have:
<pre_conditions>
✓ Test written and executed (from PLANNING)
✓ Test IS FAILING correctly (red bar visible)
✓ Failure message shown and justified
✓ Failure is "meaningful" (not setup/syntax error)
</pre_conditions>
<actions>
"Minimal implementation check:
Guidelines:
x === 5 → return 5count === 0 → return object with count: 010. If compile/lint fails: Fix issues and return to step 5 (re-run test)
11. Show compile/lint success output to user
12. Justify why implementation is minimum
13. ONLY AFTER completing steps 5-12: Announce post-condition validation
14. ONLY AFTER validation passes: Transition to GREEN
🚨 YOU CANNOT TRANSITION TO GREEN UNTIL TEST PASSES, CODE COMPILES, AND CODE LINTS 🚨
</actions>
<post_conditions>
✓ Implemented ONLY what error message demanded
✓ Test executed
✓ Test PASSES (green bar - not red)
✓ Success message shown to user verbatim
✓ Code compiles (no compilation errors)
✓ Code lints (no linting errors)
✓ Compile/lint output shown to user
✓ Implementation addresses ONLY what error message demanded (justified)
</post_conditions>
<validation_before_transition>
🚨 BEFORE transitioning to GREEN, verify ALL with evidence from tool history:
✓ Test PASSES (green bar) - show verbatim output
✓ Code compiles - show output
✓ Code lints - show output
✓ Implementation addresses ONLY what error demanded - justify
If ANY evidence missing: "⚠️ CANNOT TRANSITION - Missing: [what]" → stay in RED.
</validation_before_transition>
<critical_rules>
🚨 NEVER transition to GREEN without test PASS + compile SUCCESS + lint PASS
🚨 IMPLEMENT ONLY WHAT THE ERROR MESSAGE DEMANDS - no anticipating future errors
🚨 DON'T CHANGE TEST TO MATCH IMPLEMENTATION - fix the code, not the test
</critical_rules>
<transitions>
</transitions>
</state>
<state name="GREEN">
<prefix>🟢 TDD: GREEN</prefix>
<purpose>Test IS passing for the right reason. Assess code quality and decide next step.</purpose>
<pre_conditions>
✓ Test exists and PASSES (from RED)
✓ Test IS PASSING for the right reason (green bar visible)
✓ Code compiles (no compilation errors)
✓ Code lints (no linting errors)
✓ Pass output was shown and implementation justified as minimum
</pre_conditions>
<actions>
7a. If YES refactoring needed → Transition to REFACTOR
7b. If NO refactoring needed → Transition to VERIFY
</actions>
<post_conditions>
✓ Test IS PASSING (green bar)
✓ Code quality assessed
✓ Decision made: refactor or verify
</post_conditions>
<validation_before_transition>
BEFORE transitioning to REFACTOR or VERIFY, announce:
"Post-condition validation:
✓ Test IS PASSING: [yes - green bar visible]
✓ Code quality assessed: [yes]
✓ Decision: [REFACTOR needed / NO refactoring needed, go to VERIFY]
All post-conditions satisfied. Transitioning to [REFACTOR/VERIFY]."
IF any post-condition NOT satisfied:
"⚠️ CANNOT TRANSITION - Post-condition failed: [which one]
Staying in GREEN state to address: [issue]"
</validation_before_transition>
<critical_rules>
🚨 GREEN state means test IS PASSING, code COMPILES, code LINTS - if any fail, you're back to RED
🚨 NEVER skip code quality assessment
🚨 NEVER transition if test is not passing
🚨 NEVER transition if code doesn't compile or lint
🚨 ALWAYS assess whether refactoring is needed
🚨 Go to REFACTOR if improvements needed, VERIFY if code is already clean
</critical_rules>
<transitions>
</transitions>
</state>
<state name="REFACTOR">
<prefix>🔵 TDD: REFACTOR</prefix>
<purpose>Tests ARE passing. Improving code quality while maintaining green bar.</purpose>
<pre_conditions>
✓ Tests ARE PASSING (from GREEN)
✓ Code compiles (no compilation errors)
✓ Code lints (no linting errors)
✓ Refactoring needs identified
✓ Pass output was shown
</pre_conditions>
<actions>
a. Explain refactoring
b. Apply refactoring
c. Run test to verify behavior preserved
d. Show test still passes
/docs/conventions/testing.md)</actions>
<post_conditions>
✓ Code reviewed for quality
✓ Object calisthenics applied
✓ No feature envy
✓ Dependencies inverted
✓ Names are intention-revealing
✓ Tests still pass after each refactor
✓ Test output shown after each refactor
</post_conditions>
<validation_before_transition>
BEFORE transitioning to VERIFY, announce:
"Post-condition validation:
✓ Object calisthenics: [applied/verified]
✓ Feature envy: [none detected]
✓ Dependencies: [properly inverted]
✓ Naming: [intention-revealing]
✓ Tests pass: [yes - output shown]
All post-conditions satisfied. Transitioning to VERIFY."
</validation_before_transition>
<critical_rules>
🚨 NEVER refactor without running tests after
🚨 NEVER use generic names (data, utils, helpers)
🚨 ALWAYS verify tests pass after refactor
</critical_rules>
<transitions>
</transitions>
</state>
<state name="VERIFY">
<prefix>🟡 TDD: VERIFY</prefix>
<purpose>Tests ARE passing. Run full test suite + lint + build before claiming complete.</purpose>
<pre_conditions>
✓ Tests ARE PASSING (from GREEN or REFACTOR)
✓ Code compiles (no compilation errors)
✓ Code lints (no linting errors)
✓ Either: Refactoring complete OR no refactoring needed
</pre_conditions>
<actions>
</actions>
<post_conditions>
✓ Full test suite executed
✓ All tests PASSED
✓ Test output shown
✓ Lint executed
✓ Lint PASSED
✓ Lint output shown
✓ Build executed
✓ Build SUCCEEDED
✓ Build output shown
</post_conditions>
<validation_before_completion>
BEFORE claiming COMPLETE, announce:
"Final validation:
✓ Full test suite: [X/X tests passed - output shown]
✓ Lint: [passed - output shown]
✓ Build: [succeeded - output shown]
All validation passed. TDD cycle COMPLETE.
Session Summary:
Next: Check if project defines a task workflow. If so, follow it to completion."
IF any validation FAILED:
"⚠️ VERIFICATION FAILED
Failed check: [which one]
Output: [failure message]
Routing to: [RED/BLOCKED depending on issue]"
</validation_before_completion>
<critical_rules>
🚨 NEVER claim complete without full test suite
🚨 NEVER claim complete without lint passing
🚨 NEVER claim complete without build passing
🚨 ALWAYS show output of each verification
🚨 NEVER skip verification steps
</critical_rules>
<transitions>
</transitions>
</state>
<state name="BLOCKED">
<prefix>⚠️ TDD: BLOCKED</prefix>
<purpose>Handle situations where progress cannot continue</purpose>
<pre_conditions>
✓ Encountered issue preventing progress
✓ Issue is not user error or misunderstanding
</pre_conditions>
<actions>
</actions>
<post_conditions>
✓ Blocker documented
✓ Context preserved
✓ Suggestions provided
✓ Waiting for user
</post_conditions>
<critical_rules>
🚨 ALWAYS stop and wait for user
</critical_rules>
<transitions>
</transitions>
</state>
<state name="VIOLATION_DETECTED">
<prefix>🔥 TDD: VIOLATION_DETECTED</prefix>
<purpose>Handle state machine violations</purpose>
<trigger>
Self-detected violations:
</trigger>
<actions>
</actions>
<example>
"🔥 STATE VIOLATION DETECTED
Violation: Forgot to announce state on previous message
Current actual state: RED
Recovering to correct state...
🔴 TDD: RED
[continue from here]"
</example>
</state>
</states>
</state_machine>
<rules>
<rule id="1" title="No Green Without Proof">
If you didn't see green test output, tests didn't pass. Compilation/type-checking ≠ tests pass.
</rule>
<rule id="2" title="Show and justify failure before RED">
In PLANNING: run test, show exact failure message, explain why it's the RIGHT failure.
"Database migration failed" = setup issue, not meaningful failure.
</rule>
<rule id="3" title="Error message driven implementation">
Implement ONLY what the error message literally demands.
❌ Method missing → "not implemented" → full solution
✅ Method missing → return wrong value → assertion failure → hardcode correct value → add test → generalize
Example techniques:
Concrete example:
{ componentCount: 0, linkCount: 0 }</rule>
<rule id="4" title="Predict user response">
When asking questions, predict the answer: "Should I fix or skip? Given TDD context, you'll want option 1."
</rule>
<rule id="5" title="Green = test + lint + build">
Never claim GREEN without all three passing and showing output.
</rule>
<rule id="6" title="Add observability">
Add debug data (report objects, logging) so test failures are diagnosable.
</rule>
<rule id="7" title="Never change assertions to pass">
Test fails? Fix IMPLEMENTATION, not test. Changing assertion = VIOLATION_DETECTED.
If test is actually wrong: revert, fix test, re-implement.
</rule>
<rule id="8" title="Fail fast, no silent fallbacks">
❌ value ?? backup ?? 'Unknown' → ✅ if (!value) throw Error('Expected value')
</rule>
<rule id="9" title="No guessing">
Never "probably". Add diagnostics, get evidence, report facts.
</rule>
<rule id="10" title="Minimal assertions">
expect(x).toBe('exact') subsumes toBeDefined() and length checks. One strong assertion, not defensive scaffolding.
</rule>
<meta_rule>
ALL rules enforced via state machine post-conditions.
Skip validation → VIOLATION_DETECTED
</meta_rule>
<critical_reminders>
🚨 EVERY message: state announcement
🚨 NEVER skip transitions or claim pass/fail without output
🚨 ALWAYS justify: does this address ONLY what error message demanded?
🚨 NEVER change assertions to make tests pass
🚨 NEVER guess - find evidence
</critical_reminders>
</rules>
Take ntcoding/tdd-process from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.