tdd
Skill36 starsChanged 6 days agoMITView on GitHub
Red-green-refactor procedure: write the failing test first, show it fail, write the minimum code, refactor on green. Use for any bug fix or new behavior in code that has or could have tests, including 'fix this bug', 'add a function', 'use TDD' and 'write the test first'.
We split this skill into the rules it gives an agent
11 rules. 0 are common, 10 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 185 edited versions we read keep these.
10
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
- Distinctive: line 30
Run the existing suite once.
- Very specific: line 38
Write a single test for one behavior.
- Distinctive: line 40
Run only that test. Show the output.
- Distinctive: line 49
Write the simplest code that makes this test pass, even if it looks naive.
- Distinctive: line 51
Run the single test. Show the output.
- Distinctive: line 80
If you notice yourself writing production code before a red test, delete it and start from the test.
- Distinctive: line 97
If a test needs more than a few lines of setup, the code under test has too many dependencies.
- Distinctive: line 102
When a test fails after your change, decide which of these is true before touching anything:
- Distinctive: line 114
Keep the test as a regression test.
- Distinctive: line 118
Do not refactor or change untested code blind.
- Distinctive: line 121
Write a characterization test: call the code with a realistic input, assert whatever it returns today, run it, and keep that assertion even …
“Common” is measured: kept by at least 6 in 10 of the 185 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.
Files
Test-driven development loop
Write one failing test, make it pass with the least code, clean up while the tests stay green, repeat. The loop is useful for agents for a specific reason: a test that has never failed proves nothing. If you only ever see tests pass, you cannot tell a test that checks the behavior from one that checks nothing. Watching the failure is what makes the later pass meaningful.
Each step produces evidence: command output you can quote. Without it the loop has not been run, only described.
This playbook covers the procedure, not test strategy or test-double theory.
Core principles
| Principle | Meaning |
| No production code without a failing test first | The test defines the behavior; the code only satisfies it |
| One test at a time | Small steps keep the cause of any failure obvious |
| Show the red | Run the test and read the failure. It must fail for the reason you expect |
| Minimum code to green | Write only what the current test needs. More code is untested code |
| Refactor only on green | Cleanup while red hides whether you broke something |
| Test behavior, not implementation | A test should survive a refactor that keeps behavior the same |
Step 0: Prepare
- Find the project's test command and how to run a single test (check
AGENTS.md,CLAUDE.md, theMakefile,package.json,composer.json, CI config). Do not guess. - Run the existing suite once. Record the result. A suite that is already red must be understood before you add to it.
- Pick the smallest behavior to start with. If a spec exists with requirement IDs and WHEN/THEN criteria (see
spec-driven-development), each criterion is one or more tests. - Find the right seam (see below) and an existing test file in the same area to copy conventions from.
The loop
1. Red: write one failing test
Write a single test for one behavior. Name it after the behavior (rejects_expired_token), not the method. Use arrange, act, assert, with one reason to fail.
Run only that test. Show the output. Check two things:
- It fails. If it passes, the behavior already exists or the test checks nothing; stop and find out which.
- It fails for the right reason: an assertion about the missing behavior, not a syntax error, missing import, wrong fixture, or setup crash. Fix the test until the failure message describes the missing behavior.
State in one line what the failure shows, for example "Expected 401, got 200: expired tokens are accepted."
2. Green: write the minimum code
Write the simplest code that makes this test pass, even if it looks naive. Returning a constant is allowed if only one test exists; the next test will force the general form. Do not add parameters, branches, or abstractions no test demands.
Run the single test. Show the output. Then run the surrounding suite and show that too. A passing test next to a newly broken one is not green.
3. Refactor: clean up on green
With all tests passing, remove duplication, improve names, simplify structure, in code and in tests. Run the tests after each small change and show the result. Never skip this step: green code written to pass one test usually needs shaping. Do not change behavior here; behavior changes start a new red.
4. Repeat
Pick the next behavior: another criterion, an edge case, an error path. Common ones: empty input, boundary values, invalid input, permission denied, upstream failure, duplicate request. When the list from the spec is done, commit (one logical change per commit, using the project's convention).
Excuses to skip red
These are the reasons agents give for skipping the first step. Each has a response.
| Excuse | Response |
| "The change is trivial, a test is overkill" | Trivial code breaks too. If it is trivial, the test takes a minute. Write it |
| "I will add tests after" | Tests written after pass by construction and encode what the code does, not what it should do. Write the test first |
| "I know it will fail, no need to run it" | You do not know it fails for the right reason. Run it and read the output |
| "The test passed immediately, great" | A test that cannot fail is broken or redundant. Break the code on purpose and confirm it goes red, or find the existing behavior it duplicates |
| "It is hard to test" | That is design feedback. Find a seam, extract the logic, or write a characterization test. Do not skip |
| "I will write all the tests first, then all the code" | That is batch mode, and a bad first test will wreck all of them. One test, one pass, repeat |
| "Let me write the full implementation, I already see it" | You are writing untested code. Write the test for the first behavior and only that code |
| "The test suite is slow" | Run the single test during the loop and the suite at the end of each cycle. If one test is slow, the seam is too high |
| "This is just config, a script, or glue" | Test the behavior it produces, or state why no automated check exists and what you verified by hand, with output |
| "Mocking everything is faster" | Over-mocked tests pass while the system is broken. Use real collaborators unless they are slow, nondeterministic, or external |
| "The existing test is wrong, I will just fix it" | Maybe. But follow the rule on editing tests below, and say so |
| "I am running out of time, I will skip refactor" | Refactor is where the design gets paid for. Skip it only by saying you skipped it, and add a task to do it |
If you notice yourself writing production code before a red test, delete it and start from the test. The deleted code will be rewritten faster and tighter.
Test at the right seam
A seam is a place where you can observe behavior or substitute a dependency without editing the code under test. Pick the lowest seam that still exercises the behavior from the outside.
| Test at | Good for | Watch out for |
| Pure function or small class (unit) | Business rules, calculations, state machines, parsing | Testing private helpers; test through the public API |
| Module boundary or service with real collaborators | Behavior that spans two or three classes | Setup growing large: the unit is probably doing too much |
| Public interface of the system (HTTP, CLI, queue handler) | Wiring, serialization, auth, error mapping | Slow tests; keep these few and meaningful |
| External systems (database, clock, network, filesystem) | Cover the real adapter with a few integration tests | Faking at the wrong layer; fake the port, not internals |
Rules of thumb:
- Assert on outputs and observable state, not on which private methods ran.
- Inject the clock, randomness, and I/O so tests control them.
- If a test needs more than a few lines of setup, the code under test has too many dependencies. Treat that as a design signal.
- A test that breaks when you rename a private method but behavior is unchanged is coupled to implementation. Move it up a seam.
Never edit a test just to make it pass
When a test fails after your change, decide which of these is true before touching anything:
- The code is wrong. Fix the code. This is the usual case.
- The test encodes behavior that has intentionally changed (by the spec, ticket, or user). Update the test, and say in your message which requirement changed and why.
- The test is wrong or flaky (bad fixture, hidden order dependence, time dependence). Fix it, and say what was wrong and how you know.
Never loosen an assertion, delete a test, skip a test, or widen an expected value without writing one of those explanations. If you cannot say which case applies, stop and ask. A silently edited test is the most common way an agent turns a red suite green without fixing anything.
Bug fixes
- Reproduce the bug with a test that fails for the reported reason. Show the red. If you cannot reproduce it in a test, you do not yet understand the bug (see
debugging). - Fix the cause, not the symptom. Show the green.
- Keep the test as a regression test. Name it after the behavior, and reference the ticket or issue if the project does that.
Legacy code with no tests
Do not refactor or change untested code blind. First pin what it does now:
- Choose the seam closest to the change (see
references/legacy-and-characterization.md). - Write a characterization test: call the code with a realistic input, assert whatever it returns today, run it, and keep that assertion even if the behavior looks wrong. The test records current behavior; it is not a judgment of it.
- Cover the paths your change will touch: normal case, edge cases, error cases.
- Now make your change in the normal loop: new failing test for the new behavior, minimum code, refactor.
- Mark behavior that looks like a bug in a note or ticket. Do not fix it in the same change unless asked.
When the loop gets stuck
| Symptom | Action |
| Cannot get the test to fail for the right reason | The setup is wrong; simplify the test until the failure message is about the behavior |
| Green needs a huge code change | The step was too big. Revert, write a smaller test |
| A test is hard to write | Look for a missing seam; extract the logic into a function you can call directly |
| Tests pass but the feature does not work | A test is missing at a higher seam: add an integration test for the real path |
| Two attempts to get green have failed | Stop guessing. Report what you tried and observed, and re-read the test and the code under it |
| Unrelated failure appears | Note it, do not fix it in this change, and tell the user |
Quick checklist
- Test command found, baseline suite run and recorded
- Each behavior: one test, red output shown, failure reason matches
- Minimum code written; single test and surrounding suite green, output shown
- Refactor done on green, tests re-run
- No test edited without a stated reason
- Bug fixes keep a regression test
- Legacy changes started with characterization tests
- Final full suite, lint, and static analysis output captured (
verification-before-completion)
Reference files
| Reference | Contents |
| legacy-and-characterization | Finding seams in untested code, writing characterization tests, safe first moves |
Integration with other skills
| Situation | Recommended skill |
| Implementing tasks from a spec and task list | spec-driven-development |
| A test fails and the cause is unclear | debugging |
| Claiming the work is done | verification-before-completion |
Other versions193 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 193
- mattpocock/skills★ 309ksame name
- Yeachan-Heo/oh-my-claudecode★ 40ksame name
- Yeachan-Heo/oh-my-claude-sisyphus★ 40ksame name
- QuivrHQ/quivr★ 40ksame name
- ryoppippi/ccusage★ 19ksame name
- ccusage/ccusage★ 19ksame name
- MODSetter/SurfSense★ 17ksame name
- GreyDGL/PentestGPT★ 16ksame name
- open-metadata/OpenMetadata★ 16ksame name
- prowler-cloud/prowler★ 15ksame name
183 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Used alongsideProjects with it also use poteto-mode, setup-pstack 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.
jtarorehSkillpoteto-mode
poteto's agent style for concise, detailed responses, deliberate subagents, unslopped prose, simple code, and verified work. Use for poteto, /poteto-mode, or requests to work in this style.
Also in 5 projects that use this
bnemaSkillsetup-pstack
Configure which Pi models pstack uses per role. Detects available provider/model specs and writes pstack's user configuration. Use for /setup-pstack, "configure pstack models", or changing pstack model choices.
Also in 22 projects that use this
jaydubya818Skillprinciple-laziness-protocol
Apply when a refactor is adding wrappers or abstractions instead of simplifying.
Also in 38 projects that use this
jaydubya818Skillprinciple-make-operations-idempotent
Apply when an operation must tolerate retries after partial completion.
Also in 38 projects that use this
- +8 more from jaydubya818
In this repository38 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- llm-evalsSkill
- llm-observabilitySkill
- accessibilitySkill
- context-engineeringSkill
- debuggingSkill
- docs-lookupSkill
- performanceSkill
- securitySkill
- verification-before-completionSkill
- finishing-branchSkill
- game-feature-loopSkill
- handoffSkill
- hooks-and-guardrailsSkill
- pr-feedbackSkill
- security-researchSkill
- spec-driven-developmentSkill
- agent-creatorSkill
- agentic-rules-writerSkill
- audit-dependenciesSkill
- brainstormingSkill
- communication-styleSkill
- find-test-gapsSkill
- plan-migrationSkill
- plugin-creatorSkill
- pr-message-writerSkill
- report-writerSkill
- researchSkill
- review-pr-coldSkill
- review-prSkill
- scan-refactorsSkill
- skill-creatorSkill
- skill-measureSkill
- stakeholder-update-writerSkill
- ticket-writerSkill
- ui-reviewSkill
- verify-acceptanceSkill
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
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.

