From godmode
Use when implementing any feature or bugfix, before writing implementation code
npx claudepluginhub noobygains/godmode --plugin godmodeThis skill uses the workspace's default tool permissions.
Write the test first. Observe it fail. Write the minimum code to pass.
Enforces strict TDD workflow: Red (failing test), Green (minimal code), Refactor for features, bugfixes, refactors. Includes examples and verification steps.
Enforces strict TDD: write failing test first for features, bugfixes, refactors; verify red, implement green minimally, refactor. Prevents production code before tests.
Enforces strict Test-Driven Development (TDD) workflow: write failing test first, minimal code to pass, refactor. For new features, bug fixes, refactoring.
Share bugs, ideas, or general feedback.
Write the test first. Observe it fail. Write the minimum code to pass.
Core principle: If you did not watch the test fail, you have no evidence it validates the correct behavior.
No exceptions. No workarounds. No shortcuts.
Required:
Exceptions (confirm with your human partner):
Tempted to think "skip test-first just this once"? Stop. That is rationalization.
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
Wrote code before the test? Delete it. Start over.
Zero tolerance:
Build fresh from tests. Full stop.
digraph tdd_loop {
rankdir=LR;
red [label="RED\nWrite failing test", shape=box, style=filled, fillcolor="#ffcccc"];
check_red [label="Fails\ncorrectly?", shape=diamond];
green [label="GREEN\nMinimal code", shape=box, style=filled, fillcolor="#ccffcc"];
check_green [label="All tests\npass?", shape=diamond];
refactor [label="REFACTOR\nClean up", shape=box, style=filled, fillcolor="#ccccff"];
next [label="Next", shape=ellipse];
red -> check_red;
check_red -> green [label="yes"];
check_red -> red [label="wrong\nfailure"];
green -> check_green;
check_green -> refactor [label="yes"];
check_green -> green [label="no"];
refactor -> check_green [label="stay\ngreen"];
check_green -> next;
next -> red;
}
Write one minimal test that describes the expected behavior.
```typescript test('retries failed operations up to 3 times', async () => { let callCount = 0; const unstableOp = () => { callCount++; if (callCount < 3) throw new Error('transient failure'); return 'done'; };const outcome = await withRetry(unstableOp);
expect(outcome).toBe('done'); expect(callCount).toBe(3); });
Descriptive name, tests actual behavior, single concern
</Good>
<Bad>
```typescript
test('retry works', async () => {
const spy = jest.fn()
.mockRejectedValueOnce(new Error())
.mockRejectedValueOnce(new Error())
.mockResolvedValueOnce('done');
await withRetry(spy);
expect(spy).toHaveBeenCalledTimes(3);
});
Vague name, validates mock interactions not real behavior
Criteria:
MANDATORY. Never skip.
npm test path/to/test.test.ts
Confirm:
Test passes? You are testing existing behavior. Rewrite the test.
Test errors? Fix the error, re-run until it fails correctly.
Write the simplest possible code that makes the test pass.
```typescript async function withRetry(fn: () => Promise): Promise { for (let attempt = 0; attempt < 3; attempt++) { try { return await fn(); } catch (e) { if (attempt === 2) throw e; } } throw new Error('unreachable'); } ``` Just enough to pass ```typescript async function withRetry( fn: () => Promise, opts?: { maxAttempts?: number; backoffStrategy?: 'linear' | 'exponential'; onAttempt?: (n: number) => void; } ): Promise { // YAGNI } ``` Over-engineeredDo not add features, refactor unrelated code, or "improve" beyond what the test requires.
MANDATORY.
npm test path/to/test.test.ts
Confirm:
Test fails? Fix the code, not the test.
Other tests fail? Fix them now.
Only after green:
Keep tests green. Do not add new behavior.
Next failing test for the next behavior.
| Quality | Good | Bad |
|---|---|---|
| Focused | One thing. "and" in the name? Split it. | test('validates email and domain and whitespace') |
| Descriptive | Name explains the behavior | test('test1') |
| Intentional | Demonstrates the desired API | Obscures what the code should do |
"I'll write tests afterward to confirm it works"
Tests written after code pass immediately. Passing immediately proves nothing:
Test-first forces you to observe the failure, proving the test actually verifies something.
"I already manually tested all the edge cases"
Manual testing is ad hoc. You believe you covered everything but:
Automated tests are systematic. They execute identically every time.
"Deleting X hours of work is wasteful"
Sunk cost fallacy. The time is already spent. Your choice now:
The real waste is keeping code you cannot trust. Working code without legitimate tests is technical debt.
"Test-first is dogmatic, being pragmatic means adapting"
Test-first IS pragmatic:
"Pragmatic" shortcuts = debugging in production = slower.
"Tests after achieve the same goals - it's about the spirit not the ritual"
No. Tests-after answer "What does this do?" Tests-first answer "What should this do?"
Tests-after are biased by your implementation. You verify what you built, not what is required. You check the edge cases you remember, not ones you discover.
Tests-first force edge case discovery before implementing. Tests-after verify you remembered everything (you did not).
30 minutes of tests after is not test-first. You get coverage, but lose proof that tests work.
| Rationalization | What Is Actually True |
|---|---|
| "Too simple to test" | Simple code breaks. A test takes 30 seconds. |
| "I'll test afterward" | Tests passing immediately prove nothing. |
| "Tests after achieve the same thing" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
| "I already tested manually" | Ad hoc is not systematic. No record, cannot rerun. |
| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
| "Keep as reference, write tests first" | You will adapt it. That is testing after. Delete means delete. |
| "Need to explore first" | Fine. Discard the exploration, then start with test-first. |
| "Hard to test = I should skip it" | Listen to the test. Hard to test = hard to use. Simplify the design. |
| "Test-first will slow me down" | Test-first is faster than debugging. Pragmatic = test-first. |
| "Manual testing is faster" | Manual testing does not prove edge cases. You retest every change. |
| "Existing code has no tests" | You are improving it. Add tests for what exists. |
All of these mean: Delete the code. Start over with test-first.
Bug: Empty email accepted by form
RED
test('rejects empty email', async () => {
const result = await processForm({ email: '' });
expect(result.error).toBe('Email required');
});
Verify RED
$ npm test
FAIL: expected 'Email required', got undefined
GREEN
function processForm(data: FormData) {
if (!data.email?.trim()) {
return { error: 'Email required' };
}
// ...
}
Verify GREEN
$ npm test
PASS
REFACTOR Extract a validation pipeline for multiple fields if needed.
Before declaring work finished:
Cannot check every box? You skipped test-first. Start over.
| Problem | Solution |
|---|---|
| Do not know how to write the test | Write the API you wish existed. Write the assertion first. Ask your human partner. |
| Test too complicated | Design too complicated. Simplify the interface. |
| Must mock everything | Code too coupled. Use dependency injection. |
| Test setup is enormous | Extract helpers. Still heavy? Simplify the design. |
Bug found? Write a failing test that reproduces it. Follow the test-first cycle. The test both proves the fix and prevents regression.
Never fix bugs without a test.
When adding mocks or test utilities, read @testing-anti-patterns.md to avoid common pitfalls:
Production code -> test exists and failed first
Otherwise -> not test-first
No exceptions without your human partner's permission.