TDD Guard

repository·main·Indexed 25 days ago

https://github.com/nizos/tdd-guard

Automated Test-Driven Development enforcement for Claude Code (v1.7.0). It ensures AI agents follow TDD principles by blocking implementation attempts until corresponding tests fail and preventing over-implementation. Supports multiple test frameworks including Vitest, Jest, Storybook, pytest, PHPUnit, Go, Rust, RSpec, and Minitest via dedicated reporters.

Tokens
33.2K
Snippets
98
Records
213
Agent score
80%

What's inside tdd-guard

  1. What is TDD Guard and how does it work?

    main

    TDD Guard is an automated Test-Driven Development enforcement tool designed for Claude Code. It ensures that AI agents adhere to TDD principles by monitoring their actions.

    Core Behaviors:

    • Test-First Enforcement: It blocks implementation attempts if the corresponding tests have not failed first.
    • Minimal Implementation: It prevents the agent from writing code that goes beyond the requirements of the current failing tests.
    • Lint Integration: It enforces refactoring by utilizing your existing linting rules.
    • Session Control: You can toggle the enforcement on or off during an active session.
  2. Security validations for CLAUDE_PROJECT_DIR

    main

    When using the CLAUDE_PROJECT_DIR environment variable, TDD Guard applies strict security validations to prevent path traversal attacks. If validation fails, TDD Guard will throw a descriptive error and block the operation to prevent unauthorized file system access.

    Validations include:

    • Ensuring CLAUDE_PROJECT_DIR is an absolute path.
    • Checking for and preventing .. sequences (path traversal).
    • Verifying that the current working directory is within the CLAUDE_PROJECT_DIR.
  3. Understand the TDD Guard data directory location

    main

    TDD Guard no longer supports customizing the data directory via environment variables. To prevent path traversal vulnerabilities, the data directory is now hardcoded to a predictable location within your project. All operational data, such as test results, todos, and modifications, is stored in .claude/tdd-guard/data.

    Note: The TDD_DATA_DIR environment variable has been removed and should no longer be used in your configuration or .env files.

  4. Compare @storybook/test-runner vs @storybook/addon-vitest

    main

    Choose between the standard test runner and the Vitest addon based on your environment and performance needs:

    Feature@storybook/test-runner@storybook/addon-vitest
    Test frameworkJest + PlaywrightVitest browser mode
    Storybook version6.4+10+
    Framework supportAll frameworksVite-based only
    TDD Guard reportertdd-guard-storybooktdd-guard-vitest
    SpeedSlower (full browser)Faster

    Use @storybook/addon-vitest when:

    • You are on Storybook 10+.
    • You use a Vite-based framework.
    • You want faster execution and unified Vitest testing.

    Use @storybook/test-runner when:

    • You are on Storybook 6.4-9.x.
    • You need Webpack-based support.
    • You require full Playwright browser testing.
  5. How the Rust reporter works

    main
    The tdd-guard-rust reporter acts as a filter. It captures JSON-formatted test output from the test runner, passes that output through to stdout unchanged, and simultaneously saves the TDD Guard-formatted results to .claude/tdd-guard/data/test.json within the specified --project-root.
  6. How golangci-lint integration works in TDD Guard

    main

    Unlike many other linters that operate on individual files, the golangci-lint integration in TDD Guard uses directory-based linting.

    Because golangci-lint requires package-level context to resolve types and functions correctly, TDD Guard extracts unique directories from the provided file paths and passes those directories to the linter instead of individual files. This ensures that golangci-lint can perform proper package-level analysis while still fulfilling TDD Guard's file-based interface.

    Key behaviors to note:

    • Package-level analysis: Because it runs on directories, the linter may report issues in files within the same package that were not explicitly changed or requested by the current TDD cycle.
    • Path Mode: The integration uses the --path-mode=abs flag to ensure absolute paths are handled correctly during execution.
    // Directory-based argument building
    const directories = [...new Set(filePaths.map((file) => dirname(file)))]
    const args = [
      'run',
      '--output.json.path=stdout',
      '--path-mode=abs',
      ...directories,
    ]
  7. How the Storybook Reporter works

    main

    The tdd-guard-storybook reporter integrates with @storybook/test-runner to capture component test results. It follows a specific lifecycle and hierarchy to ensure TDD workflows are supported:

    Test Granularity

    Only stories containing a play function are reported as tests. Stories without play functions are treated as passive renders and are ignored to ensure TDD Guard only reacts to actual test signals.

    Module and Test Hierarchy

    Tests are grouped by their source file. One story file equals one module, and each story within that file is a test. The resulting data structure follows this pattern:

    {
      "testModules": [
        {
          "moduleId": "src/Button.stories.tsx",
          "tests": [
            {
              "name": "Primary",
              "fullName": "Button > Primary",
              "state": "passed"
            }
          ]
        }
      ]
    }

    Reporter Lifecycle

    To optimize performance and handle interruptions, the reporter accumulates results in memory during execution and writes them to a single file only when the process exits:

    1. During execution (postVisit): Results are collected via onStoryResult.
    2. On exit (onExit): All accumulated results are written to .claude/tdd-guard/data/test.json via onComplete.

    Failure Handling

    The reporter captures two types of failures:

    • Interaction Test Failures: Failures occurring within the play function (e.g., failed expect() calls).
    • Render Failures: Synthetic failed tests created when a story crashes during render (e.g., import errors or component crashes).
  8. Understand the TDD Guard multi-package installation pattern

    main

    TDD Guard has transitioned from a monolithic package to a monorepo architecture. Instead of installing a single package that contains all language reporters, you must now install two distinct components:

    1. The Core CLI package: tdd-guard (contains core functionality, shared code, and the main CLI).
    2. The Language-Specific Reporter: A standalone package tailored to your testing framework (e.g., tdd-guard-vitest, tdd-guard-pytest, tdd-guard-jest, etc.).

    This ensures you only install the code relevant to your specific language and testing framework, reducing package bloat.

  9. Automatic creation of custom instructions

    main

    If you have the SessionStart hook configured, TDD Guard will automatically create the .claude/tdd-guard/data/instructions.md file with default rules during the following events:

    • Starting a new Claude Code session
    • Resuming an existing session
    • Using the /clear command

    Note: Once the file is created, TDD Guard will never overwrite your custom instructions. The file remains under your control.

  10. How the TDD Guard Go Reporter works

    main

    The reporter functions as a non-destructive filter in your test pipeline:

    1. It reads go test -json output from stdin.
    2. It passes the original output through to stdout unchanged, so your existing CI/CD or terminal output is not disrupted.
    3. It parses the test results and transforms them into the TDD Guard format.
    4. It saves the processed results to .claude/tdd-guard/data/test.json.
  11. Understand the project root configuration precedence

    main

    TDD Guard uses a specific hierarchy to determine the project root directory. This prevents test results from being written to incorrect locations when tests are run from subdirectories.

    When configuring the project root, the following order of precedence applies:

    1. Explicit Configuration: Any value passed via a CLI flag, a configuration file parameter, or a reporter constructor option.
    2. Environment Variable: The TDD_GUARD_PROJECT_ROOT environment variable.
    3. Error State: If no explicit configuration or environment variable is found, the reporter will fail with an error. Note: Reporters no longer silently default to the current working directory (cwd).