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

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.

Test Framework Detection
The harness first executes 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 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 hook serves as the primary gatekeeper that validates edit sequencing.

When a task status is WIP (Work In Progress), the script checks 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) 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 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 and enforced by coordinated agent behaviors defined in the skills and agent specifications.

Configuration Flag
The [tdd.enforce] section in 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 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 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 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 documents a --tdd-bypass flag that skips the TDD gate.

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

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:


# 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 verifies that tests/foo_test.go was edited before src/foo.go. After the test fails, 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 for tasks that do not require tests:

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

With this marker present, 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:

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:

Frequently Asked Questions

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

The 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. 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. When 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, it contains the task ID, test file path, non-zero exit code, and timestamp. According to 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →