# How TDD Enforcement Hooks Validate Test-First Development in claude-code-harness

> Discover how claude-code-harness enforces test first development using TDD enforcement hooks. Learn how it validates test frameworks, ensures correct edit order, and requires red-log evidence for task completion.

- Repository: [Chachamaru/claude-code-harness](https://github.com/Chachamaru127/claude-code-harness)
- Tags: how-to-guide
- Published: 2026-05-28

---

**The claude-code-harness validates test-first development through a coordinated pipeline of shell scripts and configuration files that detect test frameworks, enforce edit order between test and source files, and require immutable red-log evidence before marking any task as complete.**

The claude-code-harness repository implements a rigorous test-driven development (TDD) gate that prevents implementation code from being merged before failing tests exist. By combining automated framework detection, file-order validation, and immutable evidence logging, these **TDD enforcement hooks** ensure that every task tagged with `[tdd:required]` follows the red-green-refactor cycle. The system runs automatically during the `harness-work` phase, blocking tasks that lack proof of a previous failing test.

## Detecting Test Frameworks and Mapping File Patterns

The enforcement pipeline begins with framework detection and path mapping configured in [`.claude/rules/tdd-paths.yaml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/.claude/rules/tdd-paths.yaml).

**Test Framework Detection**  
The harness first executes [`scripts/detect-test-framework.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/detect-test-framework.sh) to scan the repository for known test runners such as `go test` or `npm test`. If no framework is detected, the TDD gate short-circuits automatically, allowing the task to proceed without test requirements.

**Source and Test Pattern Mapping**  
The [`tdd-paths.yaml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/tdd-paths.yaml) file defines glob patterns via `src_patterns` and `test_patterns` that map source files to their corresponding test files. These patterns enable the order-checking hook to verify relationships between implementation and test files. For example, a pattern might map `src/**/*.go` to `tests/**/*_test.go`, allowing the system to know which test file must be edited before its source counterpart.

## Enforcing Test-Before-Implementation Order

The [`scripts/tdd-order-check.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/tdd-order-check.sh) hook serves as the primary gatekeeper that validates edit sequencing.

When a task status is **WIP** (Work In Progress), the script checks [`Plans.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/Plans.md) for a `[skip:tdd]` marker. If the marker is absent, the script asserts that a failing test file (matched by the patterns defined in [`tdd-paths.yaml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/tdd-paths.yaml)) was edited **before** the corresponding source file.

If the developer attempts to edit a source file without first modifying its associated test file, the script aborts the `harness-work` phase and outputs a reminder message. This enforcement ensures that red-phase test files exist in the git history before any implementation code is written.

## Capturing Immutable Red Evidence

Once a failing test exists, the [`scripts/log-tdd-red.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/log-tdd-red.sh) script creates immutable proof of the TDD red phase.

After the failing test runs, the script appends a JSONL entry to `.claude/state/tdd-red-log/<task-id>.jsonl`. Each entry contains:

- The task ID
- The test file path
- The exit code (non-zero)
- A timestamp

This red-log file serves as the canonical proof that the test was failing before any implementation code was committed. The evidence is timestamped and append-only, creating an audit trail that survives subsequent green-phase edits.

## Configuration and Agent Enforcement

The TDD gate is controlled through [`harness.toml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/harness.toml) and enforced by coordinated agent behaviors defined in the skills and agent specifications.

**Configuration Flag**  
The `[tdd.enforce]` section in [`harness.toml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/harness.toml) contains an `enabled` boolean that activates the entire TDD gate. When set to `true`, worker and reviewer agents treat the red-log as a required rule.

**Contract Inference**  
During the planning phase, [`skills/harness-plan/SKILL.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/skills/harness-plan/SKILL.md) defines how task tags translate to contract fields. The presence of `[tdd:required]` sets `tdd_required: true` in the sprint contract, while `[tdd:skip:<reason>]` marks the task as exempt. The [`agents/worker.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/agents/worker.md) specification uses these fields together with `tdd.enforce.enabled` to determine whether red-log evidence must be present before marking a task "ready".

**Reviewer Validation**  
The [`agents/reviewer.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/agents/reviewer.md) specification performs the final compliance check. For any TDD-required task, the reviewer validates that **one** of the following conditions is met:

- A recent red-log entry exists in the task's JSONL file
- Literal failing-test output is attached as evidence
- The task is explicitly skipped with a non-empty `skip_tdd_reason`

If none of these conditions are satisfied, the reviewer automatically requests changes and blocks task completion.

## Emergency Bypass Mechanisms

For urgent scenarios, [`skills/harness-work/SKILL.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/skills/harness-work/SKILL.md) documents a `--tdd-bypass` flag that skips the TDD gate.

To use the bypass, developers must set environment variables before invoking the work command:

```bash
export HARNESS_TDD_BYPASS=1
export HARNESS_TDD_BYPASS_REASON="critical hot-fix needed"
harness-work 99 --tdd-bypass

```

The bypass reason is stored in the sprint contract under `skip_tdd_reason` and is subject to later audit. This creates a paper trail for emergencies while maintaining the integrity of the standard TDD workflow.

## Practical Usage Examples

### Running a Task with Standard TDD Enforcement

Create a failing test before touching implementation code:

```bash

# Create the failing test first

echo 'package foo; import "testing"; func TestFoo(t *testing.T) { t.Fail() }' > tests/foo_test.go
touch src/foo.go

# Run the work phase - TDD hooks execute automatically

harness-work 42

```

During execution, [`tdd-order-check.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/tdd-order-check.sh) verifies that [`tests/foo_test.go`](https://github.com/Chachamaru127/claude-code-harness/blob/main/tests/foo_test.go) was edited before [`src/foo.go`](https://github.com/Chachamaru127/claude-code-harness/blob/main/src/foo.go). After the test fails, [`log-tdd-red.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/log-tdd-red.sh) writes evidence to `.claude/state/tdd-red-log/42.jsonl`. Only then can the worker mark task 42 as ready.

### Skipping TDD for Documentation Tasks

Add the skip marker to [`Plans.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/Plans.md) for tasks that do not require tests:

```markdown
- [skip:tdd] Update README installation instructions (cc:WIP)

```

With this marker present, [`tdd-order-check.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/tdd-order-check.sh) ignores the task and allows it to proceed without red-log evidence.

### Bypassing the Gate for Emergency Hotfixes

When encountering critical production issues:

```bash
export HARNESS_TDD_BYPASS=1
export HARNESS_TDD_BYPASS_REASON="critical hot-fix needed"
harness-work 99 --tdd-bypass

```

The reason is recorded in the sprint contract and audited during review.

## Summary

The claude-code-harness validates test-first development through an integrated pipeline of enforcement hooks:

- **Framework detection** via [`scripts/detect-test-framework.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/detect-test-framework.sh) establishes whether TDD rules apply to the repository
- **Path mapping** in [`.claude/rules/tdd-paths.yaml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/.claude/rules/tdd-paths.yaml) defines which files constitute tests versus implementation
- **Order enforcement** via [`scripts/tdd-order-check.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/tdd-order-check.sh) prevents source file edits until corresponding tests exist
- **Evidence logging** via [`scripts/log-tdd-red.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/log-tdd-red.sh) creates immutable JSONL records of failing tests
- **Agent coordination** through [`agents/worker.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/agents/worker.md) and [`agents/reviewer.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/agents/reviewer.md) ensures red-log evidence is mandatory for task completion
- **Configuration control** via [`harness.toml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/harness.toml) allows teams to toggle the entire gate
- **Audit trails** through bypass mechanisms ensure emergencies are documented while standard workflow integrity is maintained

## Frequently Asked Questions

### What happens if I edit a source file before its test file?

The [`scripts/tdd-order-check.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/tdd-order-check.sh) hook aborts the `harness-work` phase and prints a reminder message. The task cannot proceed until you first commit a failing test file that matches the patterns defined in [`.claude/rules/tdd-paths.yaml`](https://github.com/Chachamaru127/claude-code-harness/blob/main/.claude/rules/tdd-paths.yaml). This prevents implementation code from entering the repository without corresponding test coverage.

### How do I skip TDD validation for documentation-only changes?

Add the `[skip:tdd]` marker to the task line in [`Plans.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/Plans.md). When [`tdd-order-check.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/tdd-order-check.sh) scans the task and finds this marker, it short-circuits the enforcement logic and allows the task to complete without requiring red-log evidence. This is intended for tasks like README updates or comment changes that do not affect executable code.

### What is the red-log and why is it required?

The red-log is a JSONL file stored at `.claude/state/tdd-red-log/<task-id>.jsonl` that records every instance of a failing test. Created by [`scripts/log-tdd-red.sh`](https://github.com/Chachamaru127/claude-code-harness/blob/main/scripts/log-tdd-red.sh), it contains the task ID, test file path, non-zero exit code, and timestamp. According to [`agents/reviewer.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/agents/reviewer.md), this log serves as immutable proof that you wrote the test before the implementation, satisfying the TDD red-phase requirement before the green phase can begin.

### Can I bypass TDD enforcement for critical production fixes?

Yes, via the `--tdd-bypass` flag documented in [`skills/harness-work/SKILL.md`](https://github.com/Chachamaru127/claude-code-harness/blob/main/skills/harness-work/SKILL.md). You must set `HARNESS_TDD_BYPASS=1` and provide a `HARNESS_TDD_BYPASS_REASON` environment variable. The bypass records the reason in the sprint contract's `skip_tdd_reason` field, creating an audit trail for the exception while allowing immediate deployment of hotfixes.