agent/claude/issues/014-hooks-auto-test.md
Snider 8fed5bc6ef docs: add hook improvement tasks for better feedback cycle
6 new issues for Claude Code hook improvements:

- 012: Test output filtering (reduce noise, show failures only)
- 013: Stop verification (verify work complete before stopping)
- 014: Auto-test on edit (async tests after code changes)
- 015: Session context injection (git/issues/CI on startup)
- 016: Silent auto-formatting (suppress formatter output)
- 017: Expose/hide policy (define what to show vs suppress)

Based on Claude Code hooks documentation:
- PostToolUse with suppressOutput for noise reduction
- Stop hooks with agent verification
- Async hooks for background testing
- SessionStart for context injection
- additionalContext for exposing important info

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 18:57:16 +00:00

2.1 KiB

feat(hooks): Auto-run tests after code changes (async)

Summary

Add async PostToolUse hooks that automatically run tests after Write/Edit operations, reporting results without blocking.

Problem

Claude often edits code but forgets to run tests, or runs tests manually each time which is slow and repetitive.

Solution

Async PostToolUse hooks that:

  1. Detect code file changes (*.go, *.php, *.ts)
  2. Run relevant tests in background
  3. Report results on next turn via systemMessage

Hook Configuration

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "core ai auto-test",
            "async": true,
            "timeout": 120,
            "statusMessage": "Running tests..."
          }
        ]
      }
    ]
  }
}

Test Detection Logic

core ai auto-test should:

  1. Read file path from stdin:

    FILE=$(jq -r '.tool_input.file_path')
    
  2. Detect test scope:

    • *.go in pkg/foo/core go test ./pkg/foo/...
    • *.php in src/core php test --filter=related
    • *_test.go → run that specific test file
    • *.spec.ts → run that specific spec
  3. Run minimal test set:

    • Don't run full suite on every change
    • Use --filter or package scope
    • Cache recent test runs
  4. Report results:

    {
      "systemMessage": "Tests for pkg/foo: 12 passed, 0 failed (2.3s)"
    }
    

Smart Test Selection

For Go:

# Find related test file
TEST_FILE="${FILE%.go}_test.go"
if [ -f "$TEST_FILE" ]; then
  core go test -run "$(basename $TEST_FILE .go)" ./...
else
  # Run package tests
  PKG_DIR=$(dirname "$FILE")
  core go test "./$PKG_DIR/..."
fi

For PHP:

# Find related test
TEST_FILE=$(echo "$FILE" | sed 's/\.php$/Test.php/' | sed 's|src/|tests/|')
if [ -f "$TEST_FILE" ]; then
  core php test "$TEST_FILE"
fi

Debouncing

Avoid running tests multiple times for rapid edits:

  • Track last test run per package
  • Skip if <5 seconds since last run
  • Queue and batch rapid changes