Skip to content
Skillv1.0.0

tdd-workflow

Explicit, spec-driven TDD for non-trivial product behavior: requirements, UseCases, RED/GREEN/REFACTOR, E2E, and evidence-backed delivery. Use when the user selects $tdd-workflow and names a /tdd:* wo

by yanjunz(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from yanjunz/tdd-workflow (skills/SKILL.md). Install upstream with npx skills add yanjunz/tdd-workflow --skill skills. Copyright stays with the author.

TDD Workflow — Spec-Driven Full-Cycle Development

Command Overview

Command Purpose
/tdd:auto <name> [--yolo] One-shot full cycle: chains new → ff → loop → e2e → done with 4 inter-stage checkpoints. --yolo skips checkpoints (real failures still halt).
/tdd:new <name> Start new feature, interactive requirements gathering (collects UC framework)
/tdd:ff <name> UseCase-first: generate usecases.md as primary output, then derive requirements → design → tasks from it
/tdd:change Mid-course requirement change: analyze impact (UseCase dimension first), sync all 4 docs
/tdd:spec Generate/update spec documents individually (preserves discovery context)
RED / GREEN / REFACTOR phases Phase markers used inside /tdd:loop; not separate slash commands. See "Loop-internal phases" below for the rules each phase enforces.
/tdd:loop Auto-cycle red -> green -> refactor until Phase 2 complete
/tdd:e2e Derive E2E tests from usecases.md paths (each applicable path → E2E or an explicit unit/integration-only decision)
/tdd:verify-setup Interactive project-level verify config (tdd-specs/.verify/project.md)
/tdd:verify-local Interactive personal verify params (tdd-specs/.verify/project.local.md, gitignored)
/tdd:cleanup [env] Manual cleanup — run pre_verify_cleanup without running verification itself
/tdd:done 4-stage verification: deterministic spec preflight → code checks → local E2E → staging → delivery (includes UC sync to paths.usecases.dir, default docs/usecases/)
/tdd:notes Generate TDD practice notes — record decisions, pitfalls, lessons learned
/tdd:bug [--fast|--standard|--full] Automatic triage before writes: Fast operational repair, Standard behavior TDD, or Full workflow
/tdd:continue <name> Resume in-progress feature
/tdd:archive Archive completed specs (warns if usecases.md not synced to docs/)

Codex invocation: Select this skill with $tdd-workflow, then state the workflow entry point, for example: $tdd-workflow Run /tdd:new checkout. In Codex, the /tdd:* names identify workflows inside this skill; they are not project slash commands. Codex implicit invocation is disabled for this skill, so an ordinary request such as "fix CI" does not opt into the workflow.

Command dispatch (mandatory)

Before executing any /tdd:<id> workflow other than /tdd:e2e, read commands/<id>.md completely and follow it as the authoritative command contract. This SKILL.md provides shared rules and routing summaries; it does not replace command-specific compatibility, migration, or verification steps. /tdd:auto loads each delegated command except at its E2E stage.

E2E information-boundary exception: the main/orchestrating agent must not read commands/e2e.md. For manual /tdd:e2e, spawn from the boundary below; for /tdd:auto, follow commands/auto.md Stage 4 and spawn directly. The spawned Tester—not the main agent—reads commands/e2e.md completely and executes it. The documented single-UC exception remains available without opening that resource in the main context.

Active spec path safety

Before using a feature name or tdd-specs/.current in any path, require one non-empty [A-Za-z0-9._-]+ name other than . or ... For an existing spec, reject symlinked tdd-specs/ or tdd-specs/<name>/ directories. Stop on invalid state; never normalize a parent traversal into an accepted path.


Discovery handoff and complete UseCases

discovery.md is an optional feature artifact. Create it when the current conversation, a grill-me session, an Issue, or project notes contain useful decisions before formal specification starts. It records settled decisions, open questions, scope boundaries, assumptions, trade-offs, candidate UseCases, acceptance signals, and negative/boundary cases. If no reusable context exists, do not create an empty file.

UseCases must not stop at the happy path. For every UC, inspect input and validation, identity and permission, state and concurrency, external dependencies, timeout/recovery, and empty/boundary conditions. Model each applicable case as an alternate or failure path; record why a category is not applicable instead of silently omitting it.


Project Context Detection

Before starting any feature, detect project structure to determine test framework and directory conventions:

# Detect package management and test framework
ls package.json pyproject.toml Cargo.toml go.mod pom.xml build.gradle 2>/dev/null | head -5
grep -E '"test"|"jest"|"vitest"|"pytest"|"mocha"' package.json 2>/dev/null || true

# Detect source and test directories (monorepo-aware: check subdirs too)
find . -maxdepth 3 -name "package.json" -not -path "*/node_modules/*" \
  -exec sh -c 'echo "$(dirname {})/src $(dirname {})/lib $(dirname {})/app"' \; 2>/dev/null | \
  xargs -I{} sh -c 'ls -d {} 2>/dev/null' | sort -u | head -10

Adapt all subsequent commands based on detection results:

  • Test commands: npm test / npx jest / npx vitest / pytest / go test ./... / mvn test / cargo test etc.
  • Test directories: test/ / tests/ / __tests__/ / spec/ etc.
  • Source directories: read from tdd-specs/.verify/project.mdpaths.src_dirs (may be multiple paths for monorepos). Fall back to detection results if not configured.
  • Source directories: src/ / app/ / lib/ etc.

Test Output Frugality (token-saving)

Test runs are the biggest cache-invalidation driver in TDD. A single default-verbose npm test can emit hundreds of KB of output, blowing away the prompt cache and burning $1+ per re-build. Apply silent / minimal output by default; only re-run with details when a test fails.

Per-framework default flags (use silent unless tdd-specs/.verify/project.md already specifies a quieter command):

Framework Default (silent) On failure (re-run only the failing test)
jest npx jest --silent --reporters=summary npx jest <test-name> --verbose
vitest npx vitest run --reporter=dot npx vitest run <test-name> --reporter=verbose
pytest pytest -q --tb=line --no-header pytest <test-name> -vv --tb=long
go test go test ./... -count=1 (Go is quiet by default) go test -v -run <test-name> <pkg>
cargo test cargo test --quiet cargo test <test-name> -- --nocapture
mocha npx mocha --reporter=min npx mocha --reporter=spec <test-file>
maven mvn test -q mvn test -Dtest=<test-name>

Rules (applied by main agent / Coder / Tester whenever running tests):

  1. Default silent: every RED test run, every GREEN full-suite run, and every /tdd:done regression run starts with the silent flags above. Expected output: a single summary line ("N passed, M failed, time").
  2. Re-run only the failure verbose: when a test fails in silent mode, re-run only the failing test name with verbose flags to get the stack trace. Do not re-run the full suite verbose.
  3. Cap large outputs: if a command emits > 100 lines of stdout, pipe to | tail -100 (or | head -50; echo ...; tail -50) before reading the result. Never read a multi-MB CI log fully into context.
  4. Don't cat log files: grep -E 'FAIL|Error' test.log | head -30 is almost always what you actually wanted.
  5. Per-project override: if tdd-specs/.verify/project.md declares commands.unit already with silent flags, use it as-is. The defaults above are the floor, not a mandate to overwrite explicit config.

Why this matters: in a typical TDD cycle (200+ test runs across a feature), default-verbose can add several hundred dollars in cache_creation tokens vs default-silent — see CHANGELOG 3.13.1 rationale for the measured driver.


/tdd:new <name>

Start a new feature.

  1. If no <name>, ask user what they want to build; derive kebab-case name from description
  2. Create tdd-specs/<name>/ directory, write to tdd-specs/.current
  3. Enter requirements gathering (cannot be skipped)

Requirements gathering — all dimensions must be covered:

Dimension Question
Target users Who will use this? (based on actual project roles)
Core scenarios Top 1-3 most important use cases?
Input/Output What does the user input? What does the system return?
Error handling What situations cause failure? Expected error behavior?
Scope boundaries What is explicitly out of scope?
Acceptance criteria How do we know it's done?

After each round of Q&A, reflect understanding back to user for confirmation. Scope must be confirmed before proceeding.

Output after collection:

  • Feature name and path: tdd-specs/<name>/
  • Confirmation summary (user stories + acceptance criteria)
  • Prompt: Run /tdd:ff to generate all spec docs at once, or /tdd:spec for step-by-step

/tdd:ff <name>

Fast-forward: generate requirements -> design -> tasks in one shot.

  1. If tdd-specs/<name>/ doesn't exist, first run /tdd:new requirements gathering

  2. Step 1: Review known Issues (if project uses issues directory; path from paths.issues.dir in tdd-specs/.verify/project.md, defaults to docs/issues)

    # ISSUES_DIR resolves to paths.issues.dir (default: docs/issues). External-tool mode: skip local scan.
    ls ${ISSUES_DIR}/*.md 2>/dev/null | grep -v README || echo "No issues directory, skipping"
    grep -rl "<feature-keywords>" ${ISSUES_DIR}/ 2>/dev/null || true
  3. Step 2: Update UseCase docs (target dir from paths.usecases.dir, default docs/usecases/; external-tool mode prompts manual sync)

  4. Step 3: Generate tdd-specs/<name>/requirements.md

  5. Step 4: Generate tdd-specs/<name>/design.md (incorporating actual project tech stack)

  6. Step 5: Generate tdd-specs/<name>/tasks.md (using actual project test commands and paths)

    CRITICAL — Vertical Slice Rule (mandatory):

    Phase 2 tasks MUST be organized by UC (vertical slice), and each UC MUST include tasks for ALL technical layers it touches:

    Layer Include when... Example tasks
    Database migration UC introduces new table/field CREATE TABLE, execute migration to local DB
    Backend service UC has business logic service unit test + implementation
    Backend controller UC has API endpoint controller/route test
    Frontend page UC actor is end-user (web/mobile/native app) page JS/HTML/CSS implementation
    Client app UC involves client-side processing Python/native test + implementation

    FORBIDDEN: Separating frontend into a standalone "Phase 4". All layers of a UC belong together in Phase 2.

    Exception: Pure infrastructure setup (Phase 1: creating directories, Entity skeletons, module registration) is allowed as a separate phase since it's shared across all UCs.

    Database migration execution rule: Phase 1 must include actually running the migration on local dev DB (not just writing the SQL file). After migration, run the project's schema dump command if one exists.

  7. Step 6: Test coverage check (mandatory, cannot skip)

    After generating tasks.md, immediately verify all 3 test layers have tasks. If any layer has 0, proactively add before continuing:

    Layer Check Gap-fill direction
    Unit tests tasks.md has tasks with "unit test:" prefix Add pure function unit tests for core business logic
    Integration tests tasks.md has "integration test:" prefix tasks covering key HTTP endpoint chains + DB write verification Add: POST /api/xxx full chain (request -> response -> DB state); concurrency safety; permission boundaries (4xx for unauthorized roles)
    E2E Phase 3 has E2E tasks Add key user flow end-to-end verification
  8. Show summary, wait for confirmation

Output format:

OK requirements.md — N requirements, N acceptance criteria
OK design.md       — N modules, N interfaces
OK tasks.md        — Phase 1: N items / Phase 2: N items (by UC, all layers) / Phase 3: N E2E items
Issues reviewed: <related IDs or "none">

Ready! Run /tdd:loop to start TDD implementation.

/tdd:spec

Generate or update spec documents individually. Same as /tdd:ff Steps 1-6, but checks existing files and asks whether to overwrite.


Loop-internal phases

The three phases below are NOT standalone slash commands. They are phase markers enforced inside /tdd:loop; Standard/Full /tdd:bug paths reuse RED/GREEN while commands/bug.md defines their verification breadth. Users do not invoke /tdd:red directly — the loop transitions through these phases automatically for each Phase 2 task.

The rules in each phase are the contract between the loop and the Coder/Reviewer it spawns.

RED phase

Write a failing test (TDD Red phase).

  1. Pick next [ ] Phase 2 task from tasks.md
  2. Write test file (rules: one test at a time, test behavior not mocks, name describes behavior)
  3. Run immediately to verify it actually fails (using project's actual test command)
  4. Confirm failure reason is "feature not implemented" not syntax error
  5. Mark task as [~]

Failure verification triple-check:

  • The test fails (not errors out)
  • Failure message matches expectation
  • Failure is due to missing functionality, not typo

GREEN phase

Write minimum code to pass current test (TDD Green phase).

Step 0 (mandatory for /tdd:loop and Full /tdd:bug): Check Issues first (if project has issues tracking; path from paths.issues.dir)

grep -rl "<error-keywords>" ${ISSUES_DIR}/ 2>/dev/null || echo "No existing records"
  1. Write only the minimum code to pass the test — no premature abstraction
  2. Run tests (using project's actual command)
  3. All selected tests green, with no regressions in the selected surface, to mark complete. /tdd:loop uses its full configured suite; /tdd:bug uses the Fast/Standard/Full verification breadth from commands/bug.md.
  4. Mark task as [x]

Three-Strike Protocol — triggered when same test fails 3 times:

WARNING: Three-Strike Protocol

Test: <test-name>
Attempt history:
  1. <approach> -> <error>
  2. <approach> -> <error>
  3. <approach> -> <error>

Issues search result: <found/none>

Please choose:
  A. Try a different approach (describe your idea)
  B. Split into smaller test granularity
  C. Mark [!] skip, move to next
  D. Need more context

REFACTOR phase

Refactor (only when all tests are green).

  • Eliminate duplication, improve naming, extract shared logic
  • Run tests after each small change
  • Follow project's existing conventions (reference lint/style config and issues prevention notes)

/tdd:loop

Auto-cycle until all implementation tasks (Phase 1 + Phase 2) are terminal.

Terminal means [x] or a documented [!]; do not silently retry [!] tasks.

Agent Team Design: Coder + Orchestrator separation

Orchestrator (main agent session)
  ├── Assigns tasks to Coder sub-agent(s)
  │     - 1 Coder for sequential mode (default fallback)
  │     - N parallel Coders for independent UC modules
  │       (when host supports concurrent Agent tool calls, e.g. Claude Code)
  │     Coder(s) read: tdd-specs/ + src/ + test/
  │     Coder(s) write one phase per call: RED tests or GREEN implementation
  │
  └── Enforces the Observed RED gate, then reviews GREEN independently

commands/loop.md owns the Observed RED gate: RED and GREEN use separate Agent calls. After RED-only work, the Orchestrator runs the narrowest relevant test itself and must observe the expected non-zero before any GREEN implementation write. A Coder report is not evidence. If that result is not observable, Mode A is unavailable; use Mode B or self mode.

commands/loop.md supports two execution modes, chosen at runtime based on host capability:

Mode A — Parallel multi-Coder (preferred, when host supports it)

Hosts that allow multiple Agent/sub-agent tool calls in the same turn to execute concurrently (Claude Code, and any other host with truly-async parallel agents) can dispatch one Coder per independent UC module:

  • Same-turn spawn N Agent tool calls, one per independent UC
  • Each Coder isolated via worktree (no write conflicts on the file system)
  • Dispatch RED-only Coders, merge and observe each RED, then dispatch new GREEN-only Coders
  • Orchestrator awaits all GREEN work, merges, then runs the full test suite
  • Recommended N: 2–5 (API rate limits + token budget per agent)

When parallel is safe:

  • 2+ UC modules with no shared files and no service-level dependencies
  • Each UC's tests/impl live in distinct directories

When NOT to parallelize (must serialize):

  • Shared DB schema changes — run Phase 1 migrations sequentially first, then parallel Phase 2
  • UC-B depends on UC-A's service / module exports — process UC-A first, then UC-B

Mode B — Sequential single-Coder (fallback)

Hosts without parallel sub-agent execution (or no sub-agent tool at all — Cursor, CodeBuddy, Cline, Codex, GitHub Copilot) fall back to one-UC-at-a-time:

  • One UC's vertical slice reaches a terminal state through separate RED and GREEN steps
  • When Agent is available, RED and GREEN use separate Coder calls
  • Same review checkpoints, same test discipline — only the dispatch fan-out is removed
  • This is the supported mode on every host that runs the skill

The Orchestrator picks the mode at the start of /tdd:loop based on whether parallel Agent dispatch is available; the rest of the loop logic (RED → GREEN → REFACTOR review checkpoints) is identical in both modes.

WHILE tasks.md Phase 1 or Phase 2 has ANY [ ] or [~] task:
  IF current task is Phase 1 (infrastructure):
    Execute directly (no RED/GREEN cycle needed for migrations, scaffolding)
    VERIFY then mark [x]
  ELSE (Phase 2 implementation task):
    IF task is a "unit test" task:
      RED phase      -> Write failing test
    IF task is an "implement" task:
      GREEN phase    -> Implement to pass (with issues lookup)
    IF task is a frontend page task:
      Write page files directly (js/html/css or framework equivalent)
      VERIFY then mark [x]
    REFACTOR phase  -> Refactor (if applicable)

  IF same test fails 3 times:
    STOP -> Three-Strike Protocol -> Await decision

IF Phase 1+2 have no [ ] or [~] tasks ([x] or documented [!]):
  Run full test suite (project's actual command)
  Output: completion report (N tests, Xs elapsed, plus every [!] blocker)
  Prompt: Run /tdd:e2e for E2E acceptance

Marking [x] Verification Protocol (MANDATORY — cannot bypass):

Before marking ANY task [x], you MUST verify with evidence:

Task type Required evidence before [x]
Unit test Test file exists + test runner shows it passes
Implementation Source file exists + related tests pass
Frontend page All page files exist (framework-appropriate: tsx/vue/svelte/html+js+css) + registered in router/config
Database migration Schema inspection confirms new tables/columns exist
Any task FORBIDDEN: marking [x] for incomplete work. Use [!] for blocked tasks.

If you cannot complete a task, you MUST either:

  • Mark [!] with a documented blocker reason
  • Keep as [ ] and ask user for guidance
  • NEVER mark [x] for unfinished work

Key behavior: The loop processes ALL layers within each UC (backend test → backend impl → frontend page) before moving to the next UC. This ensures each UC is fully deliverable when its tasks complete.

Task completeness scan (runs once at loop start, cannot skip):

Scenario Type Check Prompt
DB migration executed Phase 1 has migration task AND local DB has the new tables? Migration SQL exists but was never executed. Run it now and verify with SHOW TABLES or equivalent.
Real DB integration test At least 1 test in tasks.md connects to real DB (not all mocked)? All tests use mock repositories. Add at least 1 integration test that writes to real DB and reads back to verify schema correctness.
Error response parsing Tests for "response structure doesn't match expected"? Missing error response parsing test, suggest adding
Crash/restart recovery Tests for "state recovery after process restart"? Missing crash recovery test, suggest adding
External URL/Host changes Tests for "external resource URL host mismatch"? Missing URL host rewrite test, suggest adding
Network timeout Tests for "return False/empty instead of throwing on timeout"? Missing timeout handling test, suggest adding
Integration tests (HTTP chain) tasks.md has "integration test:" tasks covering key endpoint HTTP request -> response -> DB write chain? Missing integration test tasks, suggest adding: key endpoint e2e chain (with DB state verification), concurrency safety, permission boundaries

DB Migration Verification Protocol (mandatory when Phase 1 has migration tasks):

When processing a Phase 1 migration task, the loop MUST:

  1. Execute the SQL file against local dev DB
  2. Verify tables/columns exist: SHOW TABLES LIKE '<pattern>' or equivalent
  3. Run the project's schema dump command if one exists
  4. Only mark task [x] after verification passes

If DB is not running or migration fails → STOP and ask user to fix DB before continuing. Do NOT proceed with mock-only tests and claim "verification passed".


/tdd:e2e

Phase 3: E2E acceptance tests.

E2E Type Selection (mandatory first decision)

Before writing any test, classify each target:

  • Type A — User-Flow E2E (controlled dev/CI env, seedable, 3rd-party mockable): follow Hard Rules 1–5 in this file.
  • Type B — Staging Smoke (real external deps, real credentials, uncontrolled data, cannot mock): MUST read STAGING_SMOKE.md (sibling file) and follow its Hard Rules B1–B4 + produce tdd-specs/<feature>/staging-smoke-design.md with the Negative-Proof Checklist filled in.

If a target involves real upstream dependencies that the dev/CI environment cannot reach or mock (e.g. an external API only accessible from staging/prod network, a vendor SDK requiring real credentials, a DB whose schema lives outside your control), it is Type B by definition. Never write it as a Type A test with weakened assertions like status < 500 or [200, 4xx] — that pattern silently passes when the real dependency is fully broken. See STAGING_SMOKE.md Anti-Patterns.

When both types are needed for one feature, produce two separate test files in the project's E2E directory. Do not merge.

MANDATORY FIRST STEP — Spawn Tester Agent (cannot skip)

Before writing a single line of test code, you MUST call the Agent tool to spawn a Tester Agent. Writing E2E tests directly as the main agent is FORBIDDEN when the feature has 2+ UCs.

REQUIRED:
  Agent(
    subagent_type: "general-purpose",
    prompt: """
      You are an independent Tester. Your ONLY job is to write and run E2E tests
      for the feature described in tdd-specs/<feature>/usecases.md.

      FIRST: Read the installed `commands/e2e.md` completely. You are already
      the Task sub-agent named by its self-check, so do not spawn another Tester;
      execute its Steps 1-N yourself.

      ALLOWED to read:
        - tdd-specs/<feature>/usecases.md          (source of truth for test scenarios)
        - tdd-specs/<feature>/requirements.md      (acceptance criteria)
        - API route files (route definitions only, not service implementations)
        - DB schema files (table structure only)
        - Existing E2E test files (for project structure/helper patterns)
        - tdd-specs/.verify/project.md             (test commands, health check URL)

      FORBIDDEN to read (paths listed in tdd-specs/.verify/project.md → paths.src_dirs):
        - Any implementation code under src_dirs
        - Any unit test files created during Phase 2

      IF you feel the need to read implementation code to understand behavior,
      STOP — that means the spec is incomplete. Report back what is unclear
      instead of reading the implementation.

      STEPS:
        1. Read usecases.md — derive test scenarios (1 per UC path)
        2. Start services if needed (health check from project.md)
        3. Write E2E tests starting from real user entry points:
           - Navigate from home/index page, not direct URL injection
           - No state injection bypassing UI interactions
           - No mocking your own backend endpoints
        4. Run ALL tests. Fix failures (Three-Strike Protocol applies).
        5. Report: N passed / N failed / N skipped (with skip reasons)
    """
  )

Exception — single-agent E2E is allowed only when:

  • Feature has exactly 1 UC, and its path-coverage section explicitly proves there are no applicable alternate, failure, or boundary paths
  • In that case, main agent writes tests but MUST commit in writing:

    "I am writing this E2E as main agent. Feature has exactly 1 UC and no applicable alternate/failure/boundary paths. I have not read any src_dirs implementation since /tdd:e2e started."

Enforcement checklist (Orchestrator runs AFTER Tester Agent reports back):

Check Pass condition
Agent tool was called Tool call log shows Agent invocation
Tests start from real entry points No direct deep-link navigation bypassing home/app entry
No bulk skips Skipped count ≤ 3, each skip has documented reason
No src_dirs reads in Tester prompt Tester did not read implementation files

If any check fails → mark Phase 3 tasks [!] blocked and report to user before continuing.

Why This Matters

When the Orchestrator writes E2E tests itself (without a separate Tester Agent), it tends to:

  • Navigate directly to deep pages, bypassing real app entry flows
  • Assume implementation correctness it just wrote (confirmation bias)
  • Miss integration gaps that only appear when starting from a real user perspective

The Tester Agent boundary exists precisely to catch these integration gaps.


Tester Agent Information Boundary

Tester Agent
  ✅ Can read: tdd-specs/<feature>/usecases.md
  ✅ Can read: tdd-specs/<feature>/requirements.md
  ✅ Can read: API route definitions / interface signatures
  ✅ Can read: DB schema (table structure only)
  ❌ Cannot read: any implementation code (paths from paths.src_dirs in project.md)
  ❌ Cannot read: unit test files written by Coder

paths.src_dirs is the authoritative source for "what counts as implementation code". It may contain multiple paths for monorepos (e.g. api/src, frontend/src, mobile/lib). Do NOT assume implementation lives under src/ — always check project.md first.

⚠️ isolation: "worktree" does NOT achieve Tester blindness:

isolation: "worktree" prevents write conflicts between parallel agents. It does NOT prevent reading implementation files — the worktree is a full code copy. Tester blindness is enforced via prompt constraints only (FORBIDDEN list above).

E2E Mode: Real Stack First

Prefer running E2E against a real running service stack, not mocked responses.

REAL mode (default):
  1. Detect service port (use auto-discovery from project config first;
     only ask user if auto-discovery fails after 2 retries)
  2. Verify service stack is running (health check from project.md)
  3. Seed test data
  4. Run E2E — no API response mocking (no route intercepts for your own endpoints)
  5. Assert: UI state + API response + DB state (triple verification)
  6. Teardown test data

MOCK mode (opt-in, requires justification):
  - Acceptable for: 3rd-party payment APIs, SMS, email sends
  - Unacceptable for: your own backend endpoints
  - Each mock must have inline comment: // mocked because: <reason>
  - If accumulated mocks > 3, create a test environment stub instead

Deriving E2E Test Cases from UseCases

For each UC in usecases.md:
  Success path    → 1 E2E test (full flow, verify postcondition)
  Each alt path   → 1 E2E test (verify error/boundary handling)

Each test must:
  - Start from real user entry point (home page or app launch)
  - Trigger via actual user action (tap/click/input)
  - Have explicit assertions (not just navigate to page)
  - Record function name in tasks.md (anti fake-checkoff rule)

tasks.md E2E task format:

# CORRECT (function name recorded before checking off)
- [x] 3.1 UC-01 success path — user completes <action>, system shows <result>
      → test_function_name (tests/e2e/flow.spec.ts:L142)

# WRONG (fake checkoff, cannot trace)
- [x] 3.1 UC-01 E2E

Hard Rules:

Rule 1: Must cover real network layer

Do not bypass the network layer with state injection or store manipulation. Trigger real user actions that cause actual API calls.

Rule 2: Skipped tests must have documented reasons

# WRONG: Silent skip
test.skip('env not supported')

# CORRECT: Document reason and reference UC
test.skip('UC-01 alt 4a: DB failure recovery — cannot simulate in local env, covered by unit test: <path>')

If accumulated skips exceed 3, must establish mock/stub environment to resolve — no more skip stacking.

Rule 3: Assert results after every key action

Rule 4: Assert specific values for critical business fields

Rule 5: Success path must reach the postconditions stated in usecases.md

A "success path" E2E test MUST run all the way to the UC's postconditions — not stop at an intermediate step.

WRONG — test stops before postcondition:

test "order full flow":
  # Steps 1-3: inject uploaded state (OK to bypass file picker via test helpers)
  set_uploaded_state(page, files)
  assert page.data['allUploaded'] == True
  # ← stops here, never calls POST /api/orders
  # Named "full flow" but only covers half the UC
  # DB constraints, order creation logic: completely invisible

CORRECT — must verify the postcondition:

test "order full flow":
  # Steps 1-3: inject uploaded state (bypassing file picker is acceptable)
  set_uploaded_state(page, files)

  # Steps 4-5: proceed to confirmation, trigger the real write API
  navigate_to_preview(page)
  confirm_order(page)   # triggers POST /api/orders with real HTTP call

  # Assert postcondition from usecases.md:
  # "orders record created, status=pending_payment"
  wait_until(page, lambda d: d['orderId'] is not None)
  assert page.data['orderId'] is not None, 'Postcondition: order ID must be returned'

Checklist before marking a success-path E2E as [x]:

  • Every UC step that triggers a write operation (POST/PUT/DELETE) is actually executed (not skipped)
  • At least one postcondition from usecases.md is asserted (DB record created, status field, returned ID, etc.)
  • Test name accurately reflects actual coverage depth — if it only covers setup steps, name it accordingly, not "full flow"

Rule 6: Type B targets defer to STAGING_SMOKE.md

Rules 1–5 above govern Type A (user-flow E2E in controlled environments). For any test target that hits real external dependencies which cannot be mocked or seeded (Type B per the type selection at the top of this section):

  • Hard Rules 1–5 are not sufficient — Rule 1 ("real network layer") is satisfied, but assertion strength rules don't translate (no postcondition, no UC path, no seedable data).
  • Apply STAGING_SMOKE.md Hard Rules B1–B4 instead, and produce the required staging-smoke-design.md with Negative-Proof Checklist answers before marking the task [x].

The Orchestrator enforcement checklist for Phase 3 gains one row when any Type B test exists in the feature:

Check Pass condition
Type B design doc tdd-specs/<feature>/staging-smoke-design.md exists with B3 answers filled in

Missing the design doc → Type B task stays [!] until produced.


/tdd:done

Phase 4: Delivery. Every check must pass before continuing.

Load and follow commands/done.md; in particular, retain its compatible CLI selection and legacy-spec finalization rules. The list below is only a summary.

  1. Deterministic spec preflight — use the compatible CLI selection in commands/done.md to run verify --delivery-ready; stop on a non-zero exit code. This requires every Phase 1–3 task to be terminal ([x] or documented [!]) and verifies UseCase success + alternate/failure + path-coverage sections. It does not run project tests or external services.
  2. Compilation verification (mandatory for compiled languages: TypeScript, Java, Go, Rust, etc.)
  3. Full unit tests with coverage (project's actual command) — coverage >= 80% (or project target)
  4. Full regression (if project has regression scripts)
  5. E2E (if applicable)
  6. Issue tracking judgment — create an Issue for bugs routed to Full, or when an explicit project policy requires one. Time spent and changed-file count alone do not promote a Fast/Standard fix to Full.
  7. Delivery checklist:
    [ ] Compilation clean (if applicable)
    [ ] All tests passing, coverage >= 80% (or project target)
    [ ] Full regression passing (if project has regression scripts)
    [ ] E2E tests passing (if applicable)
    [ ] Feature docs updated (if project has usecases/docs directory)
    [ ] Issues logged (Full bugs or explicit project policy)
    [ ] Environment variable examples synced (if new env vars added)
    [ ] tdd-specs/<name>/tasks.md has no Phase 1–3 [ ]/[~]; every [!] is documented in the final report
    
  8. Output delivery report — include the spec-verification.md path and result
  9. Prompt to run /tdd:notes to capture practice notes, then /tdd:archive

/tdd:notes

Generate TDD practice notes — record the full development story.

When to use: after /tdd:done, or at any point you want to capture the development journey.

  1. Read requirements.md, design.md, tasks.md from current spec
  2. Scan git history for feature-related commits, reverts, fix iterations
  3. Generate tdd-specs/<name>/tdd-practice-notes.md covering:
    • Background: what the user wanted and why
    • TDD process: Phase 1-4 record, each RED/GREEN cycle
    • Pitfalls: real problems encountered (from git history, not hypothetical)
    • File inventory: new/modified files + test coverage numbers
    • Key lessons: 3-5 actionable lessons learned
  4. Cross-check: pitfalls ≥ 1, lessons ≥ 3, file list matches git diff

Guardrails:

  • Must read spec docs first — don't fabricate from memory
  • Pitfalls must reference actual problems (git reverts, fix commits, user reports)
  • Lessons must be actionable ("do X" / "avoid Y"), not vague ("testing is important")

/tdd:bug

Explicit bug entry point with automatic, evidence-based routing. Load and follow commands/bug.md. Before creating files or editing code, run its read-only Step 0 and print the triage evidence.

Mode Select when Default scope
Fast Confirmed CI/environment/config/dependency/build/tooling cause; no behavior contract changes Minimum repair + exact failing check
Standard Stable, limited behavior regression; no high-risk flags RED + minimum GREEN + targeted/affected regression
Full Security/auth/payment/data/migration/concurrency/production risk, recurrence after a prior fix, or broad independent-boundary/external-contract impact Issue + RED/GREEN + full regression + relevant E2E + escape analysis/prevention

--fast, --standard, and --full express user intent, but evidence selects the mode. Report any conflict, then proceed automatically with a definite Fast, Standard, or Full decision. Ask for mode input only when bounded diagnosis returns Unresolved or multiple mode flags make the request ambiguous. Announce mode changes before continuing with the evidence-supported scope.

Three-Strike Protocol applies to repeated Standard/Full attempts.


/tdd:change

Mid-course requirement change flow.

  1. Confirm current spec

  2. Collect change description (interactive if not provided)

  3. Analyze impact across all 3 spec docs

    Output impact assessment:

    ## Change Impact Assessment
    ### Affected spec entries
    | Document | Entry | Impact Type | Description |
    ### Affected tasks
    | Task | Current Status | Action Needed |
    ### Risk notes
    - Completed tasks affected: N
    - Estimated additional work: small / medium / large
    
  4. Wait for user confirmation before modifying anything

  5. Execute updates (requirements.md, design.md, tasks.md, UseCases if applicable)

    • Completed but affected tasks: revert to [ ] with note <- needs redo due to requirement change
  6. Output change summary

Guardrail: If change causes 10+ task reverts, suggest considering a fresh /tdd:ff


/tdd:continue <name>

Resume in-progress feature.

  1. Read tdd-specs/<name>/tasks.md
  2. Check .harness first: phase=deliver means already shipped, so suggest notes/archive and stop
  3. Otherwise find the first [ ] or [~] task; do not silently retry a terminal [!]
  4. Write to tdd-specs/.current; route Phase 1/2 to /tdd:loop, Phase 3 to /tdd:e2e, and legacy Phase 4 to /tdd:done
  5. If only [!] tasks remain, report their blockers and continue to the next workflow gate
  6. Output recovery summary (completed N/M tasks, current phase, next step)

/tdd:archive

Archive completed specs.

  1. Require phase=deliver and terminal Phase 1–3 tasks; delivered legacy 4.x rows are historical, while [!] requires its blocker in the final report
  2. Check for tdd-practice-notes.md — if missing, prompt to run /tdd:notes first (recommend, don't block)
  3. Move to tdd-specs/archive/<YYYY-MM>/
  4. Clear tdd-specs/.current

File Structure Convention

tdd-specs/
+-- .current                    <- Currently active spec name
+-- <feature-name>/
|   +-- requirements.md         <- Requirements (EARS format)
|   +-- design.md               <- Technical design
|   +-- tasks.md                <- Implementation checklist (live-updated)
|   +-- tdd-practice-notes.md   <- Practice record (generated by /tdd:notes)
+-- archive/
    +-- YYYY-MM/
        +-- <completed-feature>/

Task Status Markers

Marker Meaning
- [ ] Not started
- [~] In progress (RED written, GREEN incomplete)
- [x] Completed
- [!] Blocked or explicitly skipped; terminal only after the decision and reason are recorded

YOLO Mode (/tdd:auto --yolo)

When .harness contains yolo=1 (and user-prompt-submit.sh shows Mode: yolo in the harness line), the main agent is in a /tdd:auto --yolo flow. Behavior changes vs default:

Default behavior YOLO behavior
Finish one UC's vertical slice → write 本轮报告 → ask "commit or continue UC-N+1?" Don't checkpoint per UC. Report once Phase 1+2 have no [ ] / [~], including every [!] blocker. Proceed straight to next UC.
Three-Strike (3× same test fail) → halt, ask user A/B/C/D Auto-pick C: mark task [!] with last failure as reason, log it, continue to next task
Task-completeness scan finds gaps → ask user to accept Auto-accept all suggestions, append tasks
Reviewer rejects Coder output 2× in a row → escalate to user Mark task [!] with reviewer feedback, continue

YOLO does NOT change:

  • /tdd:done real failures (compile / test / coverage / regression / E2E) → always halt
  • DB migration failures → always halt
  • Tester Agent boundary in /tdd:e2e → main agent must spawn Tester via Task tool. While phase=e2e, pre-write-edit.sh blocks main-agent Write/Edit outside tdd-specs/ and allows sub-agent writes with an agent_id. This is a narrow guard, not a complete sandbox: other write-capable tools remain governed by the workflow instruction.
  • Initial requirements intake in /tdd:new → must still run if no usecases.draft.md exists

User exits yolo mid-flow by deleting the yolo=1 line from .harness, or by running /tdd:continue (which doesn't carry yolo forward). Each spec's .harness is feature-isolated, so yolo on feature-A never leaks into feature-B.


Mandatory Issues Lookup Timing

Timing Method
Before /tdd:ff or /tdd:spec Browse project issues directory (if exists)
Before each GREEN phase (inside /tdd:loop) grep -rl "<error-keywords>" <issues-dir>/
After Three-Strike Protocol triggers Full-text search + module filter

Not Applicable For

  • Ordinary CI, environment, dependency, build, or tooling diagnosis when the user did not explicitly invoke TDD Workflow
  • Single-line typo fixes
  • Pure documentation or simple style changes
  • Diagnosis-only requests

Handle these directly with verification proportional to the change. If the user explicitly invokes /tdd:bug, confirmed operational/configuration cases normally route to Fast rather than the full TDD cycle.


Post-Delivery Development

After /tdd:done, the harness enters deliver state. Any source code change after this point must follow these rules to prevent test debt accumulation.

Scenario A: Bug found during integration testing

Run /tdd:bug triage before choosing the repair scope:

Bug found
  -> Fast: confirmed operational cause -> minimum repair -> exact failing check
  -> Standard: behavior regression -> RED -> minimum GREEN -> affected tests
  -> Full: high-risk/prior-fix recurrence/broad independent-boundary impact
     -> Issue + full workflow

Line count does not determine the mode. Standard and Full behavior fixes need a relevant RED test first; Fast requires confirmed non-behavioral evidence and a rerun of the exact failing check.

Scenario B: Adding functionality after spec delivery

# 1. Append tasks to tasks.md (annotate with: Post-delivery: <description>)
# 2. Reset harness back to green
sed -i 's/phase=deliver/phase=green/' tdd-specs/<spec>/.harness
# 3. Run normal loop → done flow

Modifying implementation code in deliver state without appending tests is not allowed.

Scenario C: Pure style / UX / config changes

May be done directly, but:

  • Annotate commit message with [style] / [ux] / [config]
  • Run the smallest check that directly verifies the changed surface; broaden verification only when the dependency surface justifies it

/tdd:done check: post-delivery change audit

# Read paths.src_dirs config (fall back to common dirs if not configured)
SRC_DIRS=$(grep -A20 'src_dirs:' tdd-specs/.verify/project.md 2>/dev/null | \
  grep '^\s*-' | sed "s/.*- //;s/['\"]//g" | tr '\n' ' ')
[ -z "$SRC_DIRS" ] && SRC_DIRS="src app lib"

# List source files modified during this spec cycle
git log --oneline --name-only -- $(echo $SRC_DIRS | xargs -n1 printf "'%s/**' ") \
  | grep -v "^[a-f0-9]" | sort -u | head -30

Cross-check against tasks.md:

  • Every new business method → has unit test coverage
  • Every new/modified API endpoint → has E2E test coverage
  • Every bug fix during integration -> records triage mode and verification; Full bugs also have the corresponding Issue record

Uncovered logic found → stop delivery, add tests, re-run /tdd:done.

Pre-commit self-check

□ Does every new business method have a unit test?
□ Does every new/modified API endpoint have an E2E test?
□ Any external service integrations? → mock/stub tests?
□ Verification matches the selected Fast / Standard / Full mode?
□ Any behavior bug fixes? -> relevant RED for Standard/Full?
□ Any Full bug fixes? -> Issue, regression, and risk evidence recorded?

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/yanjunz-tdd-workflow-skills/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

yanjunz-tdd-workflow-skills.ocm.jsonjson
{
  "ocm": "1",
  "id": "yanjunz-tdd-workflow-skills",
  "kind": "skill",
  "name": "tdd-workflow",
  "description": "Explicit, spec-driven TDD for non-trivial product behavior: requirements, UseCases, RED/GREEN/REFACTOR, E2E, and evidence-backed delivery. Use when the user selects $tdd-workflow and names a /tdd:* workflow, or explicitly requests TDD. /tdd:bug automatically triages Fast, Standard, or Full. Do not invoke for ordinary CI, build, environment, configuration, dependency, tooling, documentation, style, or diagnosis-only work unless explicitly requested.",
  "publisher": "yanjunz",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding",
      "medical"
    ],
    "tags": [
      "skill-md",
      "github"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Explicit, spec-driven TDD for non-trivial product behavior: requirements, UseCases, RED/GREEN/REFACTOR, E2E, and evidence-backed delivery. Use when the user selects $tdd-workflow and names a /tdd:* workflow, or explicitly requests TDD. /tdd:bug automatically triages Fast, Standard, or Full. Do not invoke for ordinary CI, build, environment, configuration, dependency, tooling, documentation, style, or diagnosis-only work unless explicitly requested."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "github",
      "repository": "https://github.com/yanjunz/tdd-workflow",
      "path": "skills/SKILL.md",
      "ref": "4f6e7f7b5a0e1f571c4e297f5cfd83e6d62614bf",
      "url": "https://github.com/yanjunz/tdd-workflow/blob/4f6e7f7b5a0e1f571c4e297f5cfd83e6d62614bf/skills/SKILL.md",
      "key": "yanjunz/tdd-workflow/skills/SKILL.md"
    },
    "allowed_tools": [
      "Read,",
      "Write,",
      "Edit,",
      "Bash,",
      "Glob,",
      "Grep,",
      "Agent,",
      "TeamCreate"
    ]
  },
  "instructions": "# TDD Workflow — Spec-Driven Full-Cycle Development\n\n## Command Overview\n\n| Command | Purpose |\n|---------|---------|\n| `/tdd:auto <name> [--yolo]` | **One-shot full cycle**: chains new → ff → loop → e2e → done with 4 inter-stage checkpoints. `--yolo` skips checkpoints (real failures still halt). |\n| `/tdd:new <name>` | Start new feature, interactive requirements gathering (collects UC framework) |\n| `/tdd:ff <name>` | **UseCase-first**: generate usecases.md as primary output, then derive requirements → design → tasks from it |\n| `/tdd:change` | **Mid-course requirement change**: analyze impac",
  "cost": {
    "context_tokens": 11033
  }
}

Fetch it by URL: GET /api/v1/registry/yanjunz-tdd-workflow-skills/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.