Best for
- Adding a new function, method, or behavior
- Fixing a bug (the bug needs a regression test before the fix)
- Refactoring a unit whose current behavior is unclear
event4u-app/agent-config/src/skills/test-driven-development/SKILL.md
Use when implementing a feature, fixing a bug, or refactoring — write a failing test first, then the code — even if the user just says 'add this function' or 'fix this bug'.
Decision brief
Use when implementing a feature, fixing a bug, or refactoring — write a failing test first, then the code — even if the user just says 'add this function' or 'fix this bug'.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/test-driven-development"Inspect the Agent Skill "test-driven-development" from https://github.com/event4u-app/agent-config/blob/0adf49a8ae84b0ff6e2de8759eea43257e020eff/src/skills/test-driven-development/SKILL.md at commit 0adf49a8ae84b0ff6e2de8759eea43257e020eff. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Plain TDD (red → green → refactor) is the right size for most work. A small subset benefits from a gated 5-phase wrapper — Spec → Pseudocode → Architecture → Refine → Complete — where each gate produces a written artifact before the next phase runs.
State in one sentence: "When X happens, the system should do Y."
Adding a new function, method, or behavior Fixing a bug (the bug needs a regression test before the fix) Refactoring a unit whose current behavior is unclear Any task where expected behavior can be expressed as an assertion
Drive implementation from a verified-failing test, not from the agent's belief that the code "should work". Catch edge cases before they become production bugs. Leave every change with a regression test that runs in CI.
If step 2 is skipped, the test is not trusted — a test that has never failed proves nothing about the code under test.
Permission review
The documentation asks the agent to run terminal commands or scripts.
npx vitest run --testNamePattern "rejects empty email"The documentation asks the agent to run terminal commands or scripts.
Re-run the same targeted command. Required:Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 93/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 7 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Do NOT use when:
.md, AGENTS.md, README)agent-config package on skill/rule markdownPlain TDD (red → green → refactor) is the right size for most work. A small subset benefits from a gated 5-phase wrapper — Spec → Pseudocode → Architecture → Refine → Complete — where each gate produces a written artifact before the next phase runs.
Decision tree — escalate if any branch is true:
When escalating: drop the Spec artifact in agents/roadmaps/ (or the
project's planning location), capture it as an ADR via adr-create
when the decision is load-bearing, then run plain TDD inside each
Refine cycle. Do not skip RED→GREEN inside a SPARC phase — the
wrapper adds gates, not exemptions.
For everything else (single-AC ticket, leaf-module change, bug fix), stay on plain TDD — the section above.
1. Write ONE failing test that describes the desired behavior.
2. Run it. WATCH it fail for the right reason.
3. Write the MINIMUM production code to make it pass.
4. Run it again. Watch it pass.
5. Clean up (rename, deduplicate) while keeping the test green.
If step 2 is skipped, the test is not trusted — a test that has never failed proves nothing about the code under test.
WHEN UNTESTED CODE EXISTS AND A TEST IS NEEDED — DELETE THE CODE,
WRITE THE TEST, REIMPLEMENT. NEVER KEEP IT "AS REFERENCE".
Reading the existing implementation while writing its test is
test-after-the-fact with extra steps. The 12-row anti-rationalization
table that follows expands the most common ways this Iron Law gets
talked-around. Externalized to
testing-anti-patterns/process-anti-patterns.md
to keep this skill under the 400-line sunset trigger.
The flow runs as four modes. Each Forbidden item names how a reviewer checks it from the diff — an unverifiable prohibition does not ship.
| Mode | Goal | Activities | Forbidden (diff check) | Output contract |
|---|---|---|---|---|
| Design | One-sentence behavior + enumerated cases | Steps 1–2 | No production code (diff touches no src/** production path) · no test bodies yet | Case list (happy/boundary/error) |
| Test-Red | A failing test that fails RIGHT | Steps 3–4 | No production edits (diff = tests/** only) · test must fail at an assertion, not an import/setup error (failure output cites the assertion line) | Failing test + its observed failure reason |
| Implement | Minimum code to green | Steps 5–6 | No test edits (no tests/** paths in Implement-phase diffs — changing the assertion to fit the code is the canonical violation; genuinely-wrong test → STOP and ask, never silently edit) · no scope beyond the one case | Green run output |
| Debug | Fix a defect found later | (re-enter at 3) | No bugfix before a reproducing regression test exists (the fix commit contains a tests/** addition that fails without the fix) | Regression test + fix, verified red→green |
Step 0 of any resume: if agents/runtime/state/HANDOFF.md exists, resume
from its Mode + Contract-owed fields (see /agent-handoff file mode) instead
of re-deriving. Otherwise infer the mode from observable state — never
assume Design:
| Observed state | Resume in |
|---|---|
| No test for the target behavior | Design |
| Test exists, currently failing at an assertion | Implement |
| Test exists + passing, defect reported | Debug |
| Test failing at import/collection error | Test-Red (fix the test, not the code) |
At every mode transition, one consent-checkpoint sentence (per
ask-when-uncertain / autonomous-execution — no new mechanism): name the
mode you are leaving, the output contract you hand over, and the mode you
enter; under an autonomous mandate the sentence is stated, not asked.
State in one sentence: "When X happens, the system should do Y."
If you cannot state it in one sentence, the scope is too big — split into multiple tests, each covering one sentence.
Before the first test is written, run the
test-case-discovery funnel for the
behavior: dimension scan → case synthesis → optional subagent cross-check →
prioritization. Do not proceed to step 3 with fewer than the floor:
Each case from the list then gets its own RED → GREEN cycle (steps 3–6). A behavior whose only test is the happy path is not done — it is the first item of an unfinished case list.
Write the smallest test that expresses the sentence from step 1.
it_rejects_empty_email, not test_email_1.Execute the single test (targeted, not the full suite):
# PHP/Pest
./vendor/bin/pest --filter=it_rejects_empty_email
# JS/Vitest
npx vitest run --testNamePattern "rejects empty email"
Required observations before proceeding:
Add just enough production code to make the test green. No extra features, no unrelated refactoring, no "while I'm here" cleanups.
If you feel the urge to add a parameter, edge case, or helper not covered by the current test — stop. That belongs in the next RED step, not this GREEN step.
Re-run the same targeted command. Required:
With all tests green, you may:
Do not add new behavior during refactor — that needs its own failing test first. Re-run tests after the refactor to confirm still-green.
Back to step 1 with the next single-sentence behavior.
Twelve common rationalizations that fire before the test is written —
plus the delete-and-restart Iron Law — live in
testing-anti-patterns/process-anti-patterns.md.
Read the table when:
For mock-isolation failure modes (separate concern), see
testing-anti-patterns.
// tests/Unit/EmailValidatorTest.php — RED
it('rejects empty email', function () {
$result = (new EmailValidator())->validate('');
expect($result->isValid())->toBeFalse();
expect($result->error())->toBe('Email required');
});
Run: ./vendor/bin/pest --filter='rejects empty email' → fails
(EmailValidator does not exist yet, or returns isValid()=true).
// app/Validators/EmailValidator.php — GREEN (minimum)
final class EmailValidator
{
public function validate(string $email): EmailResult
{
if (trim($email) === '') {
return EmailResult::invalid('Email required');
}
return EmailResult::valid();
}
}
Run the filter again → passes. No additional rules (format, MX, length) until a next failing test drives them.
// src/retry.test.ts — RED
import { retry } from './retry';
it('retries a failing operation up to 3 times', async () => {
let attempts = 0;
const op = async () => {
attempts += 1;
if (attempts < 3) throw new Error('transient');
return 'ok';
};
await expect(retry(op)).resolves.toBe('ok');
expect(attempts).toBe(3);
});
Run: npx vitest run --testNamePattern "retries a failing" → fails
(retry is undefined).
// src/retry.ts — GREEN (minimum)
export async function retry<T>(op: () => Promise<T>): Promise<T> {
let lastError: unknown;
for (let i = 0; i < 3; i += 1) {
try { return await op(); } catch (e) { lastError = e; }
}
throw lastError;
}
Run again → passes. Configurable attempt count, backoff, and jitter all wait for their own failing tests.
expect() with three or four assertions on unrelated fields describes
multiple behaviors. Split them.it('works') — no behavior describedtest-case-discoveryquality-toolspest-testingtests-executesystematic-debuggingBefore marking TDD work complete:
See also developer-like-execution
for the broader think → analyze → verify loop this skill plugs into.
Alternatives
obra/superpowers
Use when implementing any feature or bugfix, before writing implementation code
event4u-app/agent-config
Use when the user says "review the design", "check the UI", or wants a comprehensive UI/UX review. Uses a 7-phase methodology covering interaction, responsiveness, accessibility, and more.
event4u-app/agent-config
Use when writing, generating, or improving Pest tests for Laravel — clear intent, good coverage, maintainable structure, and alignment with project testing conventions.
affaan-m/ECC
Test-driven development for Quarkus 3.x LTS using JUnit 5, Mockito, REST Assured, Camel testing, and JaCoCo. Use when adding features, fixing bugs, or refactoring event-driven services.