test-driven-development
Skill1 starsChanged 51 days agoApache-2.0View on GitHub
Use when writing tests alongside code, fixing a reported bug, or deciding whether the red-green-refactor loop pays here.
190 other projects use a version of this.
Adopted by
Most recently taken up by
- dvy1987/agent-loomtheir own version, first seen Nov 15, 2026
- FimawLLC/fimaw-skillstheir own version, first seen Nov 15, 2026
- metaspartan/cybaratheir own version, first seen Nov 15, 2026
- crbnos/carbontheir own version, first seen Nov 15, 2026
- mdiri-ai/SoduWorktheir own version, first seen Nov 15, 2026
- KbWen/agent-virtual-officetheir own version, first seen Nov 15, 2026
Used with
Projects with it also use chinese-code-review, chinese-commit-conventions 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.
Leodorareluctant259Skillchinese-code-review
中文代码审查规范——在保持专业严谨的同时,用符合国内团队文化的方式给出有效反馈
Also in 8 projects that use this
Leodorareluctant259Skillchinese-commit-conventions
中文 Git 提交规范 — 适配国内团队的 commit message 规范和 changelog 自动化
Also in 8 projects that use this
obraSkilldiagnosing-superpowers
Use when a superpowers session went wrong and your human partner wants to know why — repeated work, ignored plans, stumbles, poor results, a skill that didn't fire, "it took too long", "why is it so expensive", "what is it doing" — or wants to build a bug report for the superpowers maintainers, for the current session or a past one identified by id or path, on any harness.
Also in 19 projects that use this
LLl0k0laDSkillusing-agent-skills
Use when starting a session or when you need to discover which skill applies to the current task. This is the meta-skill that governs how all other skills are discovered and invoked.
Also in 39 projects that use this
LLl0k0laDSkillgit-workflow-and-versioning
Use when making any code change. Use when committing, branching, resolving conflicts, or when you need to organize work across multiple parallel streams.
Also in 47 projects that use this
MrCipherSmithSkillconstraint-driven-development
Use when a project needs a persistent, measurable quality bar — starting a project without documented standards, 'set up constraints', or when coverage/perf/a11y thresholds get re-debated per-PR. Produces CONSTRAINTS.md with enforceable numbers, ratchets, and a guard against silent weakening. NOT for throwaway prototypes or a one-off CI setup.
Also in 15 projects that use this
- +3 more from Leodorareluctant259
- +3 more from LLl0k0laD
Other versions190 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 190
- obra/superpowers★ 314ksame name
- NousResearch/hermes-agent★ 264ksame name
- addyosmani/agent-skills★ 118ksame name
- cloudflare/computer★ 9.9ksame name
- jnMetaCode/superpowers-zh★ 8.5ksame name
- openai/plugins★ 7.8ksame name
- farm-fe/farm★ 5.6ksame name
- microsoft/FluidFramework★ 4.9ksame name
- mikeyobrien/ralph-orchestrator★ 3.2ksame name
- crbnos/carbon★ 2.8ksame name
180 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.
In this repository45 other files it gives its agents.
- docs/agents.mdAGENTS.md
- 3d-game-assetsSkill
- accessibility-evidenceSkill
- accessible-componentsSkill
- agent-memorySkill
- agent-orchestrationSkill
- code-qualitySkill
- code-reviewSkill
- colour-systemsSkill
- component-architectureSkill
- design-judgmentSkill
- design-reviewSkill
- design-tokensSkill
- engineering-disciplineSkill
- information-architectureSkill
- interaction-designSkill
- interface-copySkill
- interface-statesSkill
- layout-compositionSkill
- media-driven-motionSkill
- methodology-feedbackSkill
- micro-interactionsSkill
- mobile-performanceSkill
- motion-designSkill
- motion-physicsSkill
- multiplayer-game-publishingSkill
- platform-androidSkill
- platform-appleSkill
- platform-webSkill
- procedural-surfacesSkill
- public-api-integrationSkill
- rendering-performanceSkill
- responsive-architectureSkill
- reverse-engineeringSkill
- scroll-experiencesSkill
- seo-and-metadataSkill
- ship-readinessSkill
- skill-discoverySkill
- surface-and-depthSkill
- theming-systemsSkill
- typographic-systemsSkill
- ui-generation-workflowSkill
- vishwakarma-studiosSkill
- visual-feedback-loopSkill
- webgl-experiencesSkill
The file
We split this skill into the rules it gives an agent
5 rules. 0 are common, 5 are distinctive, and 0 are very specific to this project.
0
Common
Most of the 179 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 72
Before writing the assertion, state the requirement sentence it encodes.
- Distinctive: line 74
When a test is written after the fact — legacy code, a generated suite — recover the evidence by
- Distinctive: line 136
Interfaces still being discovered: If the call shape is unknown, the missing thing is the design.
- Distinctive: line 372
Run these checks against your own output.
- Distinctive: line 387
If you skipped the loop anywhere, did you name the case (spike, perceptual, undiscovered interface, branchless wiring, statistical) and the …
“Common” is measured: kept by at least 6 in 10 of the 179 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
<!--
Generated by Vishwakarma. Do not edit this file directly.
Edit the source skill and run `vishwakarma sync` to regenerate.
-->Test-Driven Development
Red, green, refactor is an ordering, and the ordering is the product. The tests you finish with look nearly the same either way; what differs is what you know about them. A test never observed failing has shown only that it agrees with the code in front of it. A test that failed first has shown it can detect the behaviour's absence — the property that makes a later green mean anything.
This skill governs the loop. code-quality governs the shape of what the loop produces:
which level to test at, fakes against mocks, selector order, flake quarantine, coverage gating.
Consult that one for what kind of test; consult this one for in what order you may write it.
1. Red is an observation, not a prediction
"This will fail" is not red. Red is a run: the test executes, the assertion is evaluated, the failure is printed, and you read it. Before the implementation exists that costs one command. Afterwards the property cannot be established cheaply at all, because every green is then equally consistent with working code and with an assertion that would pass against anything.
This is the step that gets skipped, and it is the step doing the work. Assertions that can never
fail are the most common silent defect in generated suites, and they share a signature: nobody ran
them while the answer was supposed to be wrong. A value compared to itself; a fixture already
holding the expected result; an expect inside a callback the runner never invokes; an unawaited
async assertion; a toBeDefined on something defined regardless. Each passes forever, each is
exposed by one red run, and coverage sees none of them — the lines execute.
2. Red and broken are different colours
A test failing with Cannot find module './pricing', a SyntaxError, a missing fixture, or a
wrong-arity TypeError is not red — it is broken. Turning it green proves the module resolves
or the typo is gone; it proves nothing about the assertion, which has still never been evaluated.
Red means the test ran to its assertion and the assertion disagreed: an expected-versus-actual report naming the values. Before running, state which assertion will fire and roughly what it will say, then compare. A prediction turns the run into a test of your model; an unpredicted run disconfirms nothing, since any output confirms "it failed".
The first test in a new module legitimately fails on import. Add the smallest surface — an exported function returning the wrong answer — so the failure lands on the assertion before real logic does.
3. The agent failure: one pass, two artefacts
The characteristic way an AI agent breaks this loop is not refusing it. It is writing the test and the implementation in one pass and running them together. Everything looks correct afterwards: a test exists, it passes, it references the right function.
What was lost is the direction of causation. A test written with the implementation in view is shaped by the implementation rather than the requirement. It asserts the shape the code already returns, expects the error it already throws, and reproduces the off-by-one just written. It cannot disagree with the code, because it came from it. Such tests hold refactoring hostage while catching nothing.
Make the ordering externally visible rather than internal:
- The test edit and the implementation edit are separate passes, with a run between them. If one edit touches both, the loop did not happen.
- Before writing the assertion, state the requirement sentence it encodes. An expected value obtained by running the code under test is a snapshot, pinning bugs as firmly as intentions.
- When a test is written after the fact — legacy code, a generated suite — recover the evidence by mutation: break the implementation deliberately, confirm the test fails, restore. A test that stays green through that is testing nothing, found for the price of one edit.
4. Write the minimum that turns it green
Enough to pass this test, nothing more. A hardcoded constant is a legitimate green; the next test forces generality, and if none forces it, the generality was speculative.
The mechanism is evidential, not ascetic. Every line written ahead of a test that demanded it is untested by construction — no red run showed it was needed, no green run shows it works — and it destroys what the loop was producing: once unrequested branches exist you can no longer tell which behaviour the suite pins. Anticipated error handling and unused options arrive this way.
Hold one failing test at a time. With two reds open, a green tells you neither which change fixed which, nor whether one regressed the other.
5. Refactor is a step, not a mood
The third step is the one dropped under deadline, and dropping it is how a codebase accumulates code that is simultaneously well tested and unmaintainable — the tests make the bad structure survivable, so it survives.
Green is the only state holding both a working implementation and a suite already shown to detect breakage, which is what makes restructuring safe. Under red, an introduced defect is indistinguishable from the one already there.
Three constraints make it a refactor rather than a rewrite: behaviour does not change, the suite is run after each move rather than after several, and no test is edited. A restructure that requires touching a test changed the observable contract — a redesign, which goes back through step one.
6. Name the condition and the behaviour
test_user, it('works') and testCalculateTotal make a CI failure report useless: the reader
has a name and a stack trace, no source, and must open the file to learn what broke. Name the test
so the report diagnoses alone — condition, then expected behaviour: rejects a signup when the
email domain is on the blocklist.
The name is also a cheap check on the test: it predicts what the assertion should say, so a name that does not match its assertion is a visible defect — usually a test that drifted during a refactor and now pins something nobody intended.
7. Where the loop does not pay
TDD attracts dogma. It is a technique with a domain: it pays when the behaviour is expressible as an assertion and the interface is known.
- Exploratory spikes. Tests written against a guessed API get rewritten with every guess. Spike untested in a scratch file, then throw the spike away and rebuild test-first with the interface known. Keeping it is how discovery code becomes production code.
- Perceptual work. Layout, type and motion are accepted by eye. An assertion pins a computed style, which passes while the layout is broken and fails on a legitimate redesign. Use reviewed screenshot baselines, and apply the loop underneath — to the logic deciding what renders.
- Interfaces still being discovered. If the call shape is unknown, the missing thing is the design. Test at the widest boundary you trust; leave the internals unpinned until a shape stabilises.
- Thin wiring and configuration. Branchless adapters, DI modules and config produce tests that restate the source in a second syntax. One integration smoke test over the wired path is cheaper evidence — until the adapter grows a conditional.
- Performance and concurrency. The property is statistical, so a pass/fail assertion either flakes on CI noise or is too loose to detect anything. Benchmark against a stated noise band.
Where the loop does not fit, name the mechanism that replaces it. "No tests here" without a substitute is not a boundary, it is an exemption.
Load reading-a-failing-test when a red run is ambiguous, loop-mechanics for the steps across
features, bugs and legacy code, and when-to-skip-the-loop before claiming an exemption.
Rules
MUST NOT — Do not loosen a matcher, delete an assertion, accept the actual output as a second valid value, skip a test, or regenerate a snapshot unread in order to reach green.
Why: Each of these produces a pass by lowering the bar while the defect the test reported stays in the code, and the suite silently loses the behaviour it was guarding. A test may legitimately change only when the requirement changed or the test provably contradicted the specification — in both cases the new assertion comes from the requirement, never from the observed output.
Incorrect:
expect(total).toBe(12.5) fails with 12.499999, so change it to expect(total).toBeDefined().Correct:
expect(total).toBe(12.5) fails with 12.499999 — that is a rounding defect in the implementation. Fix the rounding, or if fractional cents are the stated requirement, assert toBeCloseTo(12.5, 2) and say why.MUST — Run the new test and observe it fail before writing the implementation it describes.
Why: The red run is the only cheap proof that the test can detect the behaviour’s absence. Once the implementation exists, every green is equally consistent with working code and with an assertion that would pass against anything, so the property can no longer be established without deliberately breaking something.
Exceptions:
- Code that already exists — legacy, inherited, or generated — where no red run is available; recover the evidence by mutation instead (break the implementation, confirm the test fails, restore).
Incorrect:
Write priceWithTax and its test together, run once, see green, report the behaviour as tested.Correct:
Write the test, run it: "expected 0 to equal 12.5". Then implement, run again: green. Report both runs.MUST — Treat a test as red only when it reached its assertion and reported expected-versus-actual; import errors, syntax errors, arity errors and fixture failures are broken, not red.
Why: Turning a broken test green proves the module resolves or the typo is gone — the assertion still has never been evaluated, so the loop has produced no evidence at all. The two failure classes license different next actions: broken means fix the harness and re-run, red means write implementation.
Incorrect:
"Cannot find module './pricing'" — good, it is red. Now write pricing.ts and the test passes.Correct:
"Cannot find module './pricing'" — broken. Add a two-line stub returning 0, re-run, get "expected 0 to equal 12.5", and only then implement.MUST — Put the test edit and the implementation edit in separate passes with a test run between them; never author both in a single edit.
Why: A test written with the implementation in view is derived from the code rather than from the requirement: it asserts the shape the code already returns, expects the error the code already throws, and reproduces the off-by-one the author just wrote. Such a test cannot disagree with the code, so it blocks refactoring while catching nothing. Separating the passes is what makes the direction of causation externally checkable.
Exceptions:
- Characterisation tests over existing code, where the implementation necessarily precedes the test and mutation replaces the red run.
Incorrect:
One edit adds calculateRefund and calculateRefund.test.ts; one command runs them; the suite is green.Correct:
Edit 1 adds the test plus a stub. Run: red on the assertion. Edit 2 implements. Run: green.MUST — State the requirement sentence the assertion encodes before writing it, and reject any expected value that was obtained by running the code under test.
Why: An expected value produced by the implementation makes the test a snapshot of current behaviour, which pins bugs exactly as firmly as intentions. The requirement is the only source that can disagree with the code, and disagreement is the entire function of a test.
Exceptions:
- Characterisation tests written deliberately to pin current behaviour before a refactor, which must be labelled as such and deleted once real specifications cover the area.
Incorrect:
const expected = formatInvoice(fixture); expect(formatInvoice(fixture)).toEqual(expected)Correct:
Requirement: an invoice over 100 shows "Free" in the shipping line. expect(formatInvoice(fixture).shipping).toBe("Free")MUST — Fix a reported bug only after a test reproduces it and fails for the reported reason, and keep that test in the suite afterwards.
Why: A red run here proves two things at once: that the test can fail, and that you understood the report — a reproduction failing for a different reason is a different bug, and a fix aimed at it repairs nothing the reporter saw. The retained test is the only part of the work with permanent value, since the fix alone does not prevent the behaviour from returning.
Exceptions:
- Intermittent failures, where one red run is not evidence: characterise the rate over comparable run counts before and after (for example 7/200 to 0/200) rather than treating a single pass as proof.
Incorrect:
Report says the export drops the last row. Change the loop bound, ship.Correct:
Test exports a three-row fixture, fails with "expected 2 rows to equal 3", fix the bound, green, full suite green, test stays.MUST — For any test written after the code it covers, break the implementation deliberately, confirm that test fails, and restore — one mutation at a time.
Why: A retrofitted test has never been observed failing, so it is indistinguishable from one that cannot fail, and coverage tooling cannot tell them apart because the lines still execute. A deliberate mutation restores the missing observation for the cost of one edit. Mutating two things at once makes the resulting failures unattributable, exactly as changing two variables does while debugging.
Incorrect:
Generate twenty tests for the pricing module, watch them all pass, report the module as covered.Correct:
Invert the discount boundary: four tests fail, one that claims to test the boundary does not — that one asserts nothing, so fix it now.SHOULD NOT — Do not drive exploratory spikes, perceptual layout and motion work, undiscovered interfaces, branchless wiring, or performance work with the loop; name the substitute mechanism instead.
Why: The loop pays when the behaviour is expressible as an assertion and the interface is known. Where neither holds, the assertion pins a proxy — a computed style, a guessed signature, a timing threshold — which passes while the real property is broken and fails on legitimate change. Forcing it there produces expensive tests that guard nothing and teaches the team that the discipline is theatre.
Exceptions:
- A spike whose code is kept rather than discarded stops being a spike, and the exemption expires with it — the same applies to an adapter the moment it grows its first conditional or default.
Incorrect:
expect(getComputedStyle(card).gap).toBe('16px') as the test for whether the card layout is correct.Correct:
Reviewed screenshot baseline for the layout, automated contrast and focus-order checks for the objective properties, and the loop applied to the logic choosing which variant renders.SHOULD — State which assertion will fire and roughly what it will report before running a new test, then compare the prediction against the actual output.
Why: An unpredicted run cannot disconfirm anything, because any output confirms "it failed". A prediction turns the run into a test of your model of the code, and a mismatch catches a mis-scoped fixture, a skipped case, or a test exercising a different path than you believe — for the cost of one sentence.
Incorrect:
Expectation: "this will fail." Run: it failed. Proceed.Correct:
Expectation: the length assertion fires, "expected [] to have length 3". Run: "expected undefined to have length 3" — the factory returned nothing, so fix the fixture before implementing.SHOULD — Write only enough implementation to turn the current failing test green, including returning a constant, and let the next test force generality.
Why: Any line written ahead of a test that demanded it is untested by construction — no red run showed it was needed and no green run shows it works. It also destroys what the loop was producing: once unrequested branches exist you can no longer tell which behaviour the suite actually pins, so the suite stops being a map of verified behaviour.
Exceptions:
- Structure the surrounding code already requires — matching an existing interface, an error type the call site must handle — where deviating would be an inconsistency rather than a simplification.
Incorrect:
The first test wants free shipping over 100; the implementation arrives with tiered rates, a currency option, and a null-safe wrapper nothing calls.Correct:
Return the free-shipping branch and a flat rate. The tier test comes next and forces the table.SHOULD — Keep at most one failing test in the tree; write the next case only after the current one is green.
Why: With two reds outstanding, a green run is unattributable — you cannot tell which change fixed which test, nor whether one change regressed the other. The later tests are also written with the implementation produced by the earlier ones in view, which is the same derivation problem the loop exists to prevent.
Exceptions:
- A deliberately skipped or quarantined list of pending cases that do not run, which costs nothing because no failing run is being interpreted.
SHOULD — Make structural changes only from a green suite, run the suite after each move, and change no test while doing so.
Why: Green is the only state holding both a working implementation and a suite already shown to detect breakage, which is what makes restructuring safe; under red an introduced defect is indistinguishable from the one already there. Running between moves keeps the bisect interval to a single step. If a test must change, the observable contract changed — that is a redesign and needs its own red.
Incorrect:
Extract the service, rename four methods, invert the dependency, then run: eleven failures and no idea which move caused them.Correct:
Extract the service, run. Rename, run. Invert the dependency, run — it fails, so revert that step and try a smaller one.SHOULD — Name each test with the condition and the expected behaviour, so that the name plus the failure line diagnoses the break without opening the source.
Why: A CI failure report carries a name and a stack trace to someone who has not read the file; a name like "works" forces that person back into the source to learn what broke. The name also predicts the assertion, so a mismatch between the two is a visible defect — usually a test that drifted during a refactor and now pins something nobody intended.
Incorrect:
it('works'), test_user, testCalculateTotalCorrect:
it('rejects a signup when the email domain is on the blocklist'), it('retains the cart when the session token expires mid-checkout')Before reporting completion
Run these checks against your own output. Answer each question explicitly rather than assuming the answer, because the point of the exercise is to notice what you did not notice while building.
Confirm the ordering actually happened and produced evidence, rather than producing tests that merely agree with the code. (blocking)
- For each test you added, did you run it and watch it fail before the implementation existed — and can you quote the failure message?
- Did each of those failures report an expected-versus-actual comparison, rather than an import error, a syntax error, an arity error, or a fixture exception?
- Were the test edit and the implementation edit separate passes with a run between them, or did a single edit produce both?
- Can you name the requirement sentence each assertion encodes, and confirm no expected value was obtained by running the code under test?
- Does the implementation contain any branch, option, or error path that no test demanded — and if so, why is it there?
- For every test written after the code it covers, did you break the implementation, confirm the test failed, and restore?
- Was any test loosened, skipped, deleted, or re-snapshotted to reach green, and if so which requirement change justifies it?
- Was the restructuring done from a green suite with a run after each move and no test edited?
- Does each test name state the condition and the expected behaviour well enough to diagnose a CI failure without opening the file?
- If you skipped the loop anywhere, did you name the case (spike, perceptual, undiscovered interface, branchless wiring, statistical) and the mechanism replacing it?
Further reference
These are not loaded by default. Read one only when its question is the question you currently have.
references/reading-a-failing-test.md— My test failed — how do I tell a genuine red from a broken test, what should the failure message look like, and how do I prove an already-passing test is capable of failing at all?references/loop-mechanics.md— What does the loop actually look like step by step for a feature, for a reported bug, for restructuring working code, and for code that has no tests at all?references/when-to-skip-the-loop.md— Is the loop worth it for this particular work — a spike, a UI layout, a config change, a performance fix — and if not, which discipline replaces it?
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.

