cf-tdd

Medium1,500 – 3,000 tokens injected into promptupdated

Implementation workflow — direct code by default, TDD opt-in with --add-tests.

Context footprint: (medium) — what does this mean?

CLI Requirement: NONE

Works without coding-friend-cli. See CLI requirements for the full matrix.

The cf-tdd skill automatically activates when you're writing new code or refactoring existing code. By default it uses direct implementation — write code directly without new tests, then run any existing tests. To enable TDD (RED → GREEN → REFACTOR), pass --add-tests or set tdd: true in your config. To enable the end-to-end autopilot loop (auto review + fix + commit after implementation), pass --auto.

Mode Detection

The skill detects which mode to use at startup. Mode (Direct vs TDD) and autopilot (off vs on) are orthogonal — any combination is valid:

  • --add-tests flag present in the invocation → TDD mode
  • tdd: true in .coding-friend/config.json → TDD mode
  • Neither → Direct mode (default)
  • --auto flag present → Autopilot post-implementation loop activates on top of the chosen mode

Direct mode shows: > Direct mode — implementing without new tests TDD mode shows: > TDD mode enabled Autopilot shows: > 🤖 Autopilot enabled — will auto-review, auto-fix Critical+Important, and auto-commit after implementation

Autopilot Loop (--auto)

Activates iff --auto is in the current /cf-tdd invocation's arguments. This is a single, simple gate — Claude does not introspect whether it was loaded transitively. The autopilot loop is intentionally NOT activated when cf-tdd is loaded as a fallback under /cf-plan (because /cf-plan owns the loop there and never propagates --auto to subagents).

When active, after implementation completes its own verification (tests + typecheck):

  1. Auto-invoke /cf-review on uncommitted changes
  2. If 🚨 Critical or ⚠️ Important findings → dispatch one fix task to cf-implementer → re-run review (max 2 review rounds; 1 fix attempt)
  3. If the fix task itself fails ([CF-RESULT: failure]) → STOP autopilot, do NOT consume the second review round
  4. On clean review (or only 💡 Suggestions) → git add -A + single conventional commit (<type>(<scope>): <task summary>). Suggestions are logged in the commit body
  5. Report what was implemented, reviewed, fixed, and committed

Stop conditions (autopilot only halts on these):

  • Implementation fails its own verification
  • Fix task returns failure
  • Review round 2 still has Critical or Important findings
  • Review output cannot be parsed
  • git commit fails repeatedly after hook fixes
  • User explicitly interrupts

Skip Conditions

Both modes skip entirely 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.
  • User passes --no-tdd — deprecated flag, kept for backward compatibility.

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

Direct Mode (Default)

Implements the feature without writing new tests:

  1. Read task context and understand requirements
  2. Implement the feature directly
  3. Run existing tests if any (npm test, pytest, etc.) — do not write new ones
  4. Run type checking and linting if configured
  5. Report what was done

TDD Mode (--add-tests)

The classic RED → GREEN → REFACTOR 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 {
  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);
}

When TDD Helps Most

  • Complex business logic
  • Data transformations
  • Critical paths (auth, payments)
  • Edge case handling
  • Error scenarios

Config Option

Set tdd: true in .coding-friend/config.json to make TDD the default for all implementations in a project:

{
  "tdd": true
}

Or configure it interactively with cf config or cf init.