cf-tdd
Medium~1K–2.5K tokens injected into promptEnforces test-driven development: RED, GREEN, REFACTOR.
Context footprint: ⚡⚡ (medium) — what does this mean?
The cf-tdd skill automatically activates when you're writing new code or refactoring existing code. It enforces the test-driven development (TDD) discipline: write a failing test first, implement minimal code to pass it, then refactor.
Skip Conditions
TDD is automatically skipped when:
- All changed files are non-code — styles (
.css,.scss,.sass,.less,.styl), docs (.md,.mdx,.txt,.rst), or config (.json,.yaml,.yml,.toml,.env,.ini,.lock,.config). Whitelist matches only when all changed files belong to these types — mixing in a.tsfile (or any other code file) re-enables TDD for the whole change. - User passes
--no-tdd— explicitly opts out with a one-line acknowledgment. This flag is recognized by thecf-tddskill itself. Passing it through/cf-fixor/cf-plantoday does not propagate to the downstreamcf-implementeragent; those skills always delegate to the strict TDD implementer regardless of the flag.
When skipped, the skill notes why and proceeds directly to implementation.
Agent Handoff
When cf-tdd dispatches the cf-implementer agent for substantial implementations, it uses a structured JSON context file to pass findings without losing nuance through text serialization. See Agent Context Handoff for the full mechanism, schema, and retry protocol.
When It Activates
Automatically triggered when:
- Creating new functions or methods
- Adding new modules or classes
- Writing feature code from scratch
- Refactoring existing code ("refactor this", "clean up", "extract this", "simplify")
- Test file exists but implementation doesn't
The TDD Cycle
RED: Write Failing Test
Start by writing a test that describes desired behavior—it fails because the code doesn't exist yet.
// test/user.test.ts
test("should hash password with bcrypt", () => {
const password = "secret123";
const hashed = hashPassword(password);
expect(hashed).not.toBe(password);
expect(hashed.length).toBeGreaterThan(10);
});
GREEN: Implement Minimal Code
Write the simplest code that makes the test pass. No over-engineering.
// src/user.ts
export function hashPassword(password: string): string {
// Minimal implementation to pass test
return "hashed_" + password;
}
REFACTOR: Improve Code
Now improve the code while keeping tests green.
// src/user.ts
import bcrypt from "bcrypt";
export function hashPassword(password: string): string {
return bcrypt.hashSync(password, 10);
}
Benefits
- Confidence — Tests ensure code works before production
- Design — Writing tests first leads to better API design
- Coverage — Most code has tests automatically
- Refactoring — Safe to improve code with test safety net
- Documentation — Tests serve as usage examples
When It Helps Most
- Complex business logic
- Data transformations
- Critical paths (auth, payments)
- Edge case handling
- Error scenarios
Key Rules
- Always test first — No code without failing test
- Keep tests simple — Each test validates one behavior
- One assert per test — Clear pass/fail indication
- Test edge cases — Null, empty, invalid input
- Refactor freely — Tests prevent regressions