agentleFS
milad-ahmdmilad-ahmd/agent-skills/skills/tdd-loop/SKILL.md

tdd-loop

Skill5 starsChanged 15 days agoMITView on GitHub

Runs strict test-driven development one behaviour at a time. Picks the next smallest behaviour from the spec or task list, writes one failing test, makes the smallest change that passes it, then refactors with the tests green. A guard script records each step and refuses the usual shortcuts. It rejects a red step that fails for the wrong reason (syntax, import or compile error, missing function, no tests ran) and code written before any failing test. It also rejects a test that was edited, deleted, skipped or focused with .only to reach green. Works with pytest, unittest, Jest, Vitest, go test, cargo test, RSpec, Maven and Gradle. Use when the user asks to do TDD, work test-first, write the test first, follow red green refactor, build a feature test-driven from a spec or user story, or stop the agent from changing tests to make them pass.

9 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 3 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 9 edited versions we read keep these.

  • 3

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Remove duplication, rename, extract, and simplify the test code as well as the production code.

    line 59
  2. Very specific:

    Commit after each refactor if the user wants a commit per cycle.

    line 69
  3. Very specific:

    After each cycle, give one line: behaviour, test name, red reason (assertion), green, refactor done or skipped, commit.

    line 75
  4. Distinctive:

    Write several tests before making any of them pass.

    line 80
  5. Distinctive:

    Add behaviour during refactor, or refactor while red.

    line 84
  6. Very specific:

    Run --allow-test-change or --allow-error without telling the user the reason.

    line 85
  7. Very specific:

    Delete .tdd/ to get around a failed check.

    line 86

“Common” is measured: kept by at least 6 in 10 of the 9 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 Loop

Build one behaviour at a time: a failing test, the least code that passes it, then a cleanup with the tests green. The guard script makes each step checkable, so "I wrote the test first" is a recorded fact rather than a claim.

0. Set up once

python3 scripts/tdd_guard.py detect        # suggests the test command from project files

Pick a command that runs once and exits (npx vitest run, not vitest in watch mode). Prefer one that runs the current test file or test, so cycles stay fast, and run the whole suite before each commit. The guard keeps its state in .tdd/ at the project root and writes a .tdd/.gitignore so git ignores it. Add .tdd/ to the project's .gitignore too if the user wants it listed there.

Run one test:

RunnerCommand
pytestpython3 -m pytest -q tests/test_slug.py::test_lowercases
unittestpython3 -m unittest tests.test_slug.SlugTest.test_lowercases
Vitest / Jestnpx vitest run src/slug.test.ts -t "lowercases" / npx jest src/slug.test.ts -t "lowercases"
go testgo test ./slug -run '^TestLowercases$'
cargocargo test lowercases
Mavenmvn -Dtest=SlugTest#lowercases test

1. Make a behaviour list

From the spec, issue or user story, write a short list of behaviours, each one observable from outside: "slugify('Hello World') returns hello-world", "a cart with an expired code is charged full price". Order them so each builds on the last, simplest and most central first. Show the list to the user and keep it updated in the conversation.

Slice vertically. One behaviour goes through every layer it needs (route, service, storage) in a single cycle. Don't write all the models first, then all the services.

2. Red: one failing test

Write exactly one test for the next behaviour. Test through the public interface (the function, the endpoint, the CLI), and assert on results the caller can see, not on private helpers or which internal methods were called. If the code doesn't exist yet, add a stub that compiles and returns a placeholder, so the test fails on its assertion rather than on an import.

python3 scripts/tdd_guard.py red --test "python3 -m pytest -q tests/test_slug.py"
python3 scripts/tdd_guard.py red --test "npx vitest run src/slug.test.ts" --files src/slug.test.ts
python3 scripts/tdd_guard.py red          # later cycles reuse the recorded command

red passes only when the command fails on an assertion. It refuses if the tests pass already, if the failure is a syntax, import, compile or collection error, a missing function, a missing command, a timeout, or if no tests ran. It records SHA-256 snapshots of the test files: --files, plus every test file git status shows as changed. Without --files it needs at least one test file that is new or changed since the last cycle. It warns when more than one new test appeared, when the new test's name isn't in the failure output, and when source files were already changed. If the error really is the behaviour under test, pass --allow-error "reason", which is recorded.

3. Green: the smallest change that passes

Change only production code. Hard-coding the expected value is fine when it is the simplest thing that passes. The next test will force the general version.

python3 scripts/tdd_guard.py green

green re-runs the recorded command and passes only if it exits 0 with tests run and no test file changed since red. A changed or deleted test file, or an added skip or focus marker (@pytest.mark.skip, @unittest.skip, it.skip, xit, describe.only, t.Skip(), #[ignore], @Disabled), fails the check and prints the diff. This covers older test files too. If the test itself was wrong, revert it and run red again, or tell the user why and run green --allow-test-change "reason".

4. Refactor with the tests green

Remove duplication, rename, extract, and simplify the test code as well as the production code. Keep the behaviour the same and re-run after each small step.

python3 scripts/tdd_guard.py refactor

It passes when the tests pass and no test file lost tests or assertions, gained a skip marker or was deleted. It lists the test files that changed. If a test was added, write it in the next red cycle instead.

5. Commit and repeat

Commit after each refactor if the user wants a commit per cycle; otherwise keep going. Tick the behaviour off the list and return to step 2. python3 scripts/tdd_guard.py status shows the phase, the guarded files and the cycle count.

Exit codes for every command: 0 check passed, 1 check failed (the reason is printed), 2 usage or state error, such as green with no recorded red. Add --json for machine-readable output and --dir to point at the project root.

Report

After each cycle, give one line: behaviour, test name, red reason (assertion), green, refactor done or skipped, commit. At the end, list the behaviours done and the ones left, plus any --allow-* overrides and why they were needed.

What not to do

  • Skip red, or write the implementation and then a test that passes on the first run.
  • Write several tests before making any of them pass.
  • Change, loosen, delete, .skip, xit or .only a test to get to green.
  • Mock everything. Mock only what is slow or outside your control (network, clock, payment provider), and use real objects for the rest.
  • Assert on implementation details (private methods, call counts on internal collaborators) that break on every refactor.
  • Add behaviour during refactor, or refactor while red.
  • Run --allow-test-change or --allow-error without telling the user the reason.
  • Delete .tdd/ to get around a failed check. Fix the cause, or ask the user.

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.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

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.