dev-tdd

This skill should be used when the user asks to 'implement using TDD', 'test-driven development', 'RED-GREEN-REFACTOR', or 'write failing test first'.

6 stars

Best use case

dev-tdd is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

This skill should be used when the user asks to 'implement using TDD', 'test-driven development', 'RED-GREEN-REFACTOR', or 'write failing test first'.

Teams using dev-tdd should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/dev-tdd/SKILL.md --create-dirs "https://raw.githubusercontent.com/edwinhu/workflows/main/skills/dev-tdd/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/dev-tdd/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How dev-tdd Compares

Feature / Agentdev-tddStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

This skill should be used when the user asks to 'implement using TDD', 'test-driven development', 'RED-GREEN-REFACTOR', or 'write failing test first'.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

## Contents

- [The Iron Law](#the-iron-law-of-tdd)
- [The TDD Cycle](#the-tdd-cycle)
- [What Counts as a Test](#what-counts-as-a-test)
- [Logging TDD Progress](#logging-tdd-progress)
- [TDD Facts](#tdd-facts)
- [Delete & Restart](#delete--restart)
- [E2E Test Requirement](#e2e-test-requirement)

# Test-Driven Development

<EXTREMELY-IMPORTANT>
## Task Reframing: What Your Job Actually Is

**Your job is NOT to implement features. Your job is to write tests that prove features work.**

Reframe every task:
- ❌ "Implement user login"
- ✅ "Write a test that proves user login works. Then make it pass."

- ❌ "Fix the icon rendering bug"
- ✅ "Write a test that fails when icons render wrong. Then fix it."

**The test IS your deliverable. The implementation just makes the test pass.**
</EXTREMELY-IMPORTANT>

<EXTREMELY-IMPORTANT>
## File-Based Logging (MANDATORY)

**ALL CODE MUST USE FILE-BASED LOGGING.**

Every application you write MUST redirect output to a log file:
- CLI apps: `./app > /tmp/app.log 2>&1 &`
- GUI apps: `./app --log-file=/tmp/app.log 2>&1 &`
- Test runners: `pytest -v > /tmp/test.log 2>&1`

**Why:** Without log files, you have NO EVIDENCE of what happened. "I saw it in terminal" is not verification.

**Read the full requirements:** `@references/logging-requirements.md`
</EXTREMELY-IMPORTANT>

<EXTREMELY-IMPORTANT>
## The Execution Gate (MANDATORY)

**NO E2E TESTS WITHOUT PASSING THE EXECUTION GATE FIRST.**

Before running E2E tests or taking screenshots, you MUST complete all 6 gates in order:

```
GATE 1: BUILD
GATE 2: LAUNCH (with file-based logging)
GATE 3: WAIT
GATE 4: CHECK PROCESS
GATE 5: READ LOGS ← MANDATORY, CANNOT SKIP
GATE 6: VERIFY LOGS
THEN AND ONLY THEN: E2E tests/screenshots
```

**Key enforcement:**
- If you catch yourself thinking "let me take a screenshot" → STOP, you skipped gates 1-6
- If process is running → READ LOGS (GATE 5) before testing
- Logs come BEFORE screenshots, not after

**For GUI applications:**
- Screenshot WINDOW ONLY (not whole screen)
- When testing specific feature (toolbar icons), crop to THAT REGION only
- Whole screen = false conclusions from other apps

**Read the complete gate sequence:** `@references/execution-gates.md`
</EXTREMELY-IMPORTANT>

<EXTREMELY-IMPORTANT>
## The Iron Law of TDD

**YOU MUST WRITE THE FAILING TEST FIRST. YOU MUST SEE IT FAIL. This is not negotiable.**

Before writing ANY implementation code:
1. You write a test that will fail (because the feature doesn't exist yet)
2. You run the test and **SEE THE FAILURE OUTPUT** (RED)
3. You document in LEARNINGS.md: "RED: [test name] fails with [error message]"
4. Only THEN you write implementation code
5. You run the test again, **SEE IT PASS** (GREEN)
6. You document: "GREEN: [test name] now passes"

**The RED step is not optional. If the test hasn't failed, you haven't practiced TDD.**
</EXTREMELY-IMPORTANT>

## The TDD Cycle

```
RED → Write test → Run through GATES → See failure → Read logs → Document
GREEN → Minimal code → Run through GATES → See pass → Read logs → Document
REFACTOR → Clean up while staying green
```

### Step 1: RED - Write Failing Test

```python
# Write the test FIRST
def test_user_can_login():
    result = login("user@example.com", "password123")
    assert result.success == True
    assert result.token is not None
```

Run the test through the execution gates:

```bash
# For unit tests, minimum gates are: EXECUTE + READ OUTPUT
pytest tests/test_auth.py::test_user_can_login -v 2>&1 | tee /tmp/test.log
# pytest: run specific test and see RED failure

# READ the output (MANDATORY)
cat /tmp/test.log
```

Output will show:
```
FAILED - NameError: name 'login' is not defined
```

**Log to LEARNINGS.md:**
```markdown
## RED: test_user_can_login
- Test written
- Ran through gates (pytest executed, output read)
- Fails with: NameError: name 'login' is not defined
- Expected: function doesn't exist yet
```

### Step 2: GREEN - Minimal Implementation

Write the **minimum code** to make the test pass:

```python
def login(email: str, password: str) -> LoginResult:
    # Minimal implementation
    return LoginResult(success=True, token="dummy-token")
```

Run the test through gates again:

```bash
pytest tests/test_auth.py::test_user_can_login -v 2>&1 | tee /tmp/test.log
# pytest: run test again and see GREEN success

# READ the output (MANDATORY)
cat /tmp/test.log
```

Output will show:
```
PASSED
```

**Log to LEARNINGS.md:**
```markdown
## GREEN: test_user_can_login
- Minimal login() implemented
- Ran through gates (pytest executed, output read)
- Test passes
- No errors in output
- Ready for refactor
```

### Step 3: REFACTOR - Improve While Green

Clean up the code while keeping tests passing:

```python
def login(email: str, password: str) -> LoginResult:
    user = User.find_by_email(email)
    if user and user.check_password(password):
        return LoginResult(success=True, token=generate_token(user))
    return LoginResult(success=False, token=None)
```

Verify tests remain green after refactoring:

```bash
pytest tests/test_auth.py -v
# pytest: run all tests and verify GREEN after refactor
```

Output will show:
```
All tests PASSED
```

## What Counts as a Test

<EXTREMELY-IMPORTANT>
### REAL Tests vs FAKE "Tests"

**Read the shared enforcement:**

Read `${CLAUDE_SKILL_DIR}/../../references/constraints/real-test-enforcement.md`.

**Key rule: THE TEST MUST EXECUTE THE CODE AND VERIFY RUNTIME BEHAVIOR.** Grepping is NOT testing. Log reading is NOT testing. Code review is NOT testing.
</EXTREMELY-IMPORTANT>

## Logging TDD Progress

Document every TDD cycle in `.planning/LEARNINGS.md`:

```markdown
## TDD Cycle: [Feature/Test Name]

### RED
- **Test:** `test_feature_works()`
- **Command:**

```bash
pytest tests/test_feature.py::test_feature_works -v
# pytest: run test and observe RED failure
```

- **Output:**
```
FAILED - AssertionError: expected True, got None
```
- **Expected:** Feature not implemented yet

### GREEN
- **Implementation:** Added `feature_works()` function
- **Command:**

```bash
pytest tests/test_feature.py::test_feature_works -v
# pytest: run test and verify GREEN success
```

- **Output:**
```
PASSED
```

### REFACTOR
- Extracted helper function
- Added type hints
- Verify tests still pass:

```bash
pytest tests/test_feature.py -v
# pytest: run all tests and confirm GREEN after refactor
```
```

## TDD Facts

- A test that passes on its first run has proven nothing: it never failed, so it cannot distinguish working code from a test that exercises nothing. The RED run is the only evidence that the test actually tests the feature. Claiming TDD on a never-red test is an unverified claim presented as fact.
- When an assertion fails during GREEN, the test itself may be wrong — but editing the assertion to match observed output converts the test into a record of the bug. Question the assertion before changing it.
- Mocks, direct function calls, and substitute protocols verify the stand-in, not the production behavior — boundary bugs live exactly where the stand-in replaces the real thing. A test that doesn't replicate what the user does is a FAKE test, and unit tests alone hide those boundary bugs.

**If your test doesn't fail first, you haven't practiced TDD.**

## Delete & Restart

<EXTREMELY-IMPORTANT>
**Wrote implementation code before test? You MUST DELETE IT. No exceptions.**

When you discover implementation code that wasn't driven by a test:
1. **DELETE** your implementation code
2. **WRITE** the test first
3. **RUN** it, **SEE RED**
4. **REWRITE** the implementation

"But it works" is not an excuse. "But it would waste your time" is not an excuse.

**Code you wrote without TDD is UNTRUSTED code. You delete it and do it right.**
</EXTREMELY-IMPORTANT>

## E2E Test Requirement

<EXTREMELY-IMPORTANT>
### The Iron Law of E2E in TDD

**USER-FACING FEATURES REQUIRE E2E TESTS IN ADDITION TO UNIT TESTS.**

TDD cycle for user-facing changes:

```
Unit TDD:     RED → GREEN → REFACTOR
                    ↓
E2E TDD:      RED → GREEN → REFACTOR
```

**Both cycles must complete. Unit GREEN does not mean DONE.**

### When E2E is Required

| Change Type | Unit Tests | E2E Required? |
|-------------|------------|---------------|
| Internal logic | Yes | No |
| API endpoint | Yes | Yes (test full request/response) |
| UI component | Yes | **Yes** (Playwright/automation) |
| CLI command | Yes | Yes (test actual invocation) |
| User workflow | Yes | **Yes** (simulate user actions) |
| Visual change | Yes | **Yes** (screenshot comparison) |

### E2E TDD Cycle

1. **RED**: Write E2E test simulating user action
   - Run through ALL 6 GATES (BUILD → LAUNCH → WAIT → CHECK → READ LOGS → VERIFY LOGS)
   - Only after GATE 6: Run the E2E test
   - Observe the failure (feature doesn't exist)
   - Document: "E2E RED: [test] fails with [error]. All gates passed, logs clean."

2. **GREEN**: Implement to make E2E pass (unit tests already green)
   - Run through ALL 6 GATES again
   - Only after GATE 6: Run the E2E test
   - Verify the pass
   - Document: "E2E GREEN: [test] passes. All gates passed, logs clean."

3. **REFACTOR**: Ensure both unit and E2E stay green
   - Continue running through gates for each test run

### Delete & Restart (E2E)

**You shipped user-facing code without E2E test? You MUST WRITE ONE NOW.**

Retroactive E2E is better than no E2E. But next time: You write E2E FIRST.
</EXTREMELY-IMPORTANT>

## Integration

This skill is invoked by:
- `dev-implement` - for TDD during implementation
- `dev-debug` - for regression tests during debugging

For testing tool options (Playwright, ydotool, etc.), see:

Read `${CLAUDE_SKILL_DIR}/../../skills/dev-test/SKILL.md` and follow its instructions.

Related Skills

writing

6
from edwinhu/workflows

This skill should be used when the user asks to 'write a paper', 'start a writing project', 'draft an article', 'write about', 'brainstorm writing topics', 'gather sources for a paper', 'what should I write about', or needs the writing workflow entry point for any writing task.

writing-validate

6
from edwinhu/workflows

Validate draft sections cover all PRECIS claims before review.

writing-setup

6
from edwinhu/workflows

Internal skill for creating PRECIS.md, OUTLINE.md, and ACTIVE_WORKFLOW.md. Called after brainstorm sources are gathered.

writing-revise

6
from edwinhu/workflows

This skill should be used when the user asks to 'revise writing', 'fix review issues', 'polish draft', 'apply review feedback', 'complete writing workflow', or after /writing-review produces REVIEW.md with issues to fix.

writing-review

6
from edwinhu/workflows

Internal skill for hierarchical document review. Called by writing-validate after claim validation passes.

writing-precis-reviewer

6
from edwinhu/workflows

Internal skill used by writing-setup at exit gate. Dispatches a reviewer subagent to verify PRECIS.md quality before outlining. NOT user-facing.

writing-outline

6
from edwinhu/workflows

Internal skill for creating detailed section outlines. Called by /writing workflow after PRECIS and master OUTLINE are complete.

writing-outline-reviewer

6
from edwinhu/workflows

Internal skill used by writing-outline at exit gate. Dispatches a reviewer subagent to verify OUTLINE.md quality before drafting. NOT user-facing.

writing-lit-review

6
from edwinhu/workflows

Internal skill for literature review and source materialization. Called after brainstorm, before setup. NOT user-facing.

writing-legal

6
from edwinhu/workflows

Internal skill for academic legal writing. Loaded by /writing when style=legal. Based on Volokh's "Academic Legal Writing".

writing-handoff

6
from edwinhu/workflows

Create structured handoff document for writing workflow session pause/resume.

writing-general

6
from edwinhu/workflows

Internal skill for Strunk & White writing rules. Loaded by /writing for quick edits or as base layer for domain skills.