agentleFS
SpencerGossSpencerGoss/agent-engineering/tdd-workflow/SKILL.md

tdd-workflow

Skill0 starsChanged 5 months agoMITView on GitHub

Use when a spec or plan exists and it's time to write code — or when fixing a bug. Trigger on: "fix this bug", "write tests for", "write a function that", "create a module", "the spec is ready, let's implement", or any request to write working code when the WHAT is already clear. The hard gate: no implementation before a failing test exists.

  • Installs packages

128 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use brand-discovery, configure-ecc and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • ysyecustSkill

    brand-discovery

    Use when a brand needs to discover or articulate its identity through structured multi-session interviews. Covers purpose, positioning, audience, personality, voice, narrative, and founder-brand tension across 8 modules using laddering, 5 Whys, and projective techniques. Produces a resumable session with disk-persisted state and a master brandbook (90_SYNTHESIS.md).

    Also in 6 projects that use this

  • royaluniondesign-sysSkill

    configure-ecc

    Interactive installer for Everything Claude Code — guides users through selecting and installing skills and rules to user-level or project-level directories, verifies paths, and optionally optimizes installed files.

    Also in 12 projects that use this

  • junimnjwSkill

    ralphinho-rfc-pipeline

    RFC-driven multi-agent DAG execution pattern with quality gates, merge queues, and work unit orchestration.

    Also in 12 projects that use this

  • loulanyueSkill

    nuxt4-patterns

    Nuxt 4 app patterns for hydration safety, performance, route rules, lazy loading, and SSR-safe data fetching with useFetch and useAsyncData.

    Also in 10 projects that use this

  • royaluniondesign-sysSkill

    content-hash-cache-pattern

    Cache expensive file processing results using SHA-256 content hashes — path-independent, auto-invalidating, with service layer separation.

    Also in 16 projects that use this

  • RojiosSkill

    dart-flutter-patterns

    Production-ready Dart and Flutter patterns covering null safety, immutable state, async composition, widget architecture, popular state management frameworks (BLoC, Riverpod, Provider), GoRouter navigation, Dio networking, Freezed code generation, and clean architecture.

    Also in 7 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

30 rules. 0 are common, 29 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 117 edited versions we read keep these.

  • 29

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Write the test first. Watch it fail.

    line 17
  2. Distinctive:

    Hard gate: Never write implementation code before a failing test exists.

    line 19
  3. Distinctive:

    Write a test that describes the behavior you want

    line 27
  4. Distinctive:

    Run it — it MUST fail (if it passes, the test is wrong or already implemented)

    line 28
  5. Distinctive:

    Write the smallest possible code that makes the test pass

    line 47
  6. Distinctive:

    Run — it MUST pass

    line 48
  7. Distinctive:

    No extra code, no "while I'm here" additions

    line 49
  8. Distinctive:

    If GREEN fails: your implementation is incomplete.

    line 52
  9. Distinctive:

    Never skip RED → always verify test fails before implementation.

    line 53
  10. Distinctive:

    Never modify tests to make them pass — fix the implementation.

    line 54
  11. Distinctive:

    Run tests — still must pass

    line 64
  12. Distinctive:

    After REFACTOR, if you discovered anything non-obvious during the cycle:

    line 69
  13. Distinctive:

    Write it to your project notes using your persistent insight format.

    line 74
  14. Distinctive:

    Before marking any feature complete:

    line 108
  15. Distinctive:

    Must reach 80%+ on new code

    line 110
  16. Distinctive:

    If below: write more tests for uncovered branches

    line 111
  17. Distinctive:

    If you're writing tests for existing code (characterization tests):

    line 125
  18. Distinctive:

    Write tests that describe what the code currently does (not what it should do)

    line 127
  19. Distinctive:

    Run — they should pass (capturing existing behavior)

    line 128
  20. Distinctive:

    If modifying code that has no existing tests and is too complex to test from scratch:

    line 133
  21. Distinctive:

    Write characterization tests first (describe current behavior, even if broken)

    line 134
  22. Distinctive:

    Do NOT skip characterization tests and go straight to new tests on legacy code

    line 137
  23. Distinctive:

    One assertion per test: when possible (makes failures clear)

    line 156
  24. Distinctive:

    No implementation before RED: if you wrote code before a failing test, delete the code and start over

    line 159
  25. Distinctive:

    NOT for planning what to build — use a spec-driven-development skill to write the spec before starting TDD

    line 166
  26. Distinctive:

    NOT for diagnosing why something is broken — use a debug skill to find the root cause first, then write a fix test here

    line 167
  27. Very specific:

    NOT for code review or style enforcement — use a code-review skill after the RED/GREEN/REFACTOR cycle

    line 168
  28. Distinctive:

    NEVER use this for writing tests against code you don't understand yet — read the code or spec first

    line 169
  29. Distinctive:

    Mocking too much: When every dependency is mocked, your test proves the mocks work, not the code.

    line 176
  30. Distinctive:

    Skipping RED — writing code before the failing test: If you write the implementation first, the test might pass because it's testing what …

    line 178

“Common” is measured: kept by at least 6 in 10 of the 117 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

TDD Workflow

Write the test first. Watch it fail. Write minimal code to pass it. Refactor.

Hard gate: Never write implementation code before a failing test exists. No exceptions.


The Cycle

RED: Write a Failing Test

  1. Write a test that describes the behavior you want
  2. Run it — it MUST fail (if it passes, the test is wrong or already implemented)
  3. Commit: test: add failing test for <feature>
# Python example
def test_calculate_spread():
    result = calculate_spread(home_score=105, away_score=98)
    assert result == 7  # RED: function doesn't exist yet
// JavaScript/TypeScript example
test('calculateSpread returns point difference', () => {
  expect(calculateSpread(105, 98)).toBe(7);  // RED: not implemented
});

GREEN: Write Minimal Implementation

  1. Write the smallest possible code that makes the test pass
  2. Run — it MUST pass
  3. No extra code, no "while I'm here" additions
  4. Commit: feat: implement <feature>

If GREEN fails: your implementation is incomplete. Debug before moving to REFACTOR. Never skip RED → always verify test fails before implementation. Never modify tests to make them pass — fix the implementation.

def calculate_spread(home_score: int, away_score: int) -> int:
    return home_score - away_score  # Minimal. Done.

REFACTOR: Clean Up Without Breaking

  1. Improve names, remove duplication, simplify logic
  2. Run tests — still must pass
  3. Commit: refactor: clean up <feature>

EXTRACT: Capture What You Learned (Optional but High-Value)

After REFACTOR, if you discovered anything non-obvious during the cycle:

  • A constraint the test revealed about the system
  • An approach that failed during GREEN and why
  • A pattern that applies beyond this specific function

Write it to your project notes using your persistent insight format. Before writing, scan existing notes for the same tag — MERGE or UPDATE if an entry already exists, do not add a duplicate. Duplicate domain insights dilute the core insights and cause confusion.

Skip if nothing surprising happened. Don't force it.


Per-Language Quick Start

Python (pytest)

# Install
pip install pytest
uv pip install pytest  # if using uv

# Run tests
pytest                          # all tests
pytest tests/test_module.py     # specific file
pytest -k "test_name"           # specific test
pytest --tb=short               # short traceback

JavaScript/TypeScript (Jest or Vitest)

# Run tests
npm test                        # Jest
npx vitest                      # Vitest
npm test -- --watch             # watch mode
npm test -- --coverage          # coverage report

Coverage Gate

Before marking any feature complete:

  • Run coverage check
  • Must reach 80%+ on new code
  • If below: write more tests for uncovered branches
# Python
pytest --cov=. --cov-report=term-missing

# JavaScript (Jest)
npm test -- --coverage

"Already Have Code" Path

If you're writing tests for existing code (characterization tests):

  1. Write tests that describe what the code currently does (not what it should do)
  2. Run — they should pass (capturing existing behavior)
  3. Commit: test: add characterization tests for <module>
  4. Now refactor or fix — tests will catch regressions

Legacy Code Exception: If modifying code that has no existing tests and is too complex to test from scratch:

  1. Write characterization tests first (describe current behavior, even if broken)
  2. These are not RED tests — they document the existing contract
  3. Then apply TDD for new behavior on top of characterized behavior
  4. Do NOT skip characterization tests and go straight to new tests on legacy code

Quick Reference

SituationWhat to do
Tempted to write code firstStop. Write the test first.
Test passes immediatelyThe test is wrong — check your assertion or the code already exists
Can't figure out what to testWrite the function signature in a comment, then write what the caller expects
Test is too hard to writeThe function is too large — break it into smaller pieces
"Just a simple function"Still write the test first. Simple tests take 60 seconds.
Feature has multiple behaviorsOne test per behavior. Don't test everything in one test.

Rules

  • One assertion per test when possible (makes failures clear)
  • Test names describe behavior: test_returns_none_when_input_empty not test_function
  • Arrange-Act-Assert pattern: set up → call function → assert result
  • No implementation before RED: if you wrote code before a failing test, delete the code and start over
  • Commit each phase: RED commit, GREEN commit, REFACTOR commit — makes history readable

Out of Scope

  • NOT for planning what to build — use a spec-driven-development skill to write the spec before starting TDD
  • NOT for diagnosing why something is broken — use a debug skill to find the root cause first, then write a fix test here
  • NOT for code review or style enforcement — use a code-review skill after the RED/GREEN/REFACTOR cycle
  • NEVER use this for writing tests against code you don't understand yet — read the code or spec first

Common Traps

  • Testing implementation details instead of behavior: Tests that assert internal method calls, private state, or execution order break on every refactor. Test the output given an input — not how the function arrives at the answer.
  • Mocking too much: When every dependency is mocked, your test proves the mocks work, not the code. Mock external services (APIs, databases) but let internal modules interact naturally. If a test requires 5+ mocks, the function under test likely needs to be decomposed.
  • GREEN test that passes for the wrong reason: A test that asserts result is not None passes even when the result is garbage. Write assertions that would fail if the implementation returned a plausible-but-wrong value (e.g., assert exact value, not just truthiness).
  • Skipping RED — writing code before the failing test: If you write the implementation first, the test might pass because it's testing what you wrote rather than what's correct. The RED step catches this: if the test passes immediately, something is wrong.
  • Flaky tests from shared state or timing: Tests that depend on execution order, global variables, or wall-clock time pass locally but fail in CI. Use fresh fixtures per test (scope="function" in pytest), avoid time.sleep() in assertions, and never depend on test ordering.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.