mcpField
I
iterative-development

iterative-development

github.com/alinaqiテスト・品質711276 回インストール2 週間前に更新
リポジトリ

iterative-development について

Claude Code の Stop hook で各応答後にテストやチェックを実行し、コード上の失敗をモデルに返す TDD ループを作るスキルです。合否を明確に判定できる開発作業に向いています。

主な機能

  1. 01Stop hook によるテストと lint の反復
  2. 02失敗内容を Claude に返却
  3. 03反復回数の上限設定
  4. 04任意の書き込み前 lint hook
  5. 05セッション開始時のコンテキスト注入

活用シーン

  1. 01テストを確認しながらの機能実装
  2. 02失敗テストを使ったバグ修正
  3. 03回帰チェックを伴うリファクタリング

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/alinaqi/maggy --skill iterative-development

インストール後、Claude Code で/iterative-developmentを入力して読み込まれたか確認します。

詳細

反復開発スキル(Stop フックによる TDD ループ)

概要: Claude Code の Stop フックは、Claude が応答を完了する直前に実行されます。終了コード 2 を返すと、stderr がモデルにフィードバックされ、会話が続きます。これにより、プラグインを使わずに実際の TDD ループを実現できます。


実際の動作

Claude Code には、Claude が応答を終了しようとすると実行される Stop フック があります。フックスクリプトがコード 2 で終了すると、その stderr がモデルに表示され、会話が自動的に続きます。

┌─────────────────────────────────────────────────────────────┐
│  1. User asks Claude to implement a feature                 │
├─────────────────────────────────────────────────────────────┤
│  2. Claude writes tests + implementation                    │
├─────────────────────────────────────────────────────────────┤
│  3. Claude finishes its response                            │
├─────────────────────────────────────────────────────────────┤
│  4. Stop hook runs: executes tests, lint, typecheck         │
├─────────────────────────────────────────────────────────────┤
│  5a. All pass (exit 0) → Claude stops, work is done         │
│  5b. Failures (exit 2) → stderr fed back to Claude          │
├─────────────────────────────────────────────────────────────┤
│  6. Claude sees failures, fixes code, response ends         │
├─────────────────────────────────────────────────────────────┤
│  7. Stop hook runs again → repeat until green or max tries  │
└─────────────────────────────────────────────────────────────┘

重要なポイント: 偽のプラグインや /ralph-loop コマンドは不要です。このフックは、Claude Code の実際のインフラストラクチャであり、自動的に実行されます。


セットアップ:Stop フックの設定

プロジェクトの .claude/settings.json に次の内容を追加します。

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "scripts/tdd-loop-check.sh",
            "timeout": 60,
            "statusMessage": "Running tests..."
          }
        ]
      }
    ]
  }
}
TDD ループチェック用スクリプト

プロジェクトに scripts/tdd-loop-check.sh を作成します。

#!/bin/bash
# TDD Loop Check - runs after each Claude response
# Exit 0 = all good, Claude stops
# Exit 2 = failures, stderr fed back to Claude to fix

MAX_ITERATIONS=25
ITERATION_FILE=".claude/.tdd-iteration-count"

# Track iteration count
if [ -f "$ITERATION_FILE" ]; then
    count=$(cat "$ITERATION_FILE")
    count=$((count + 1))
else
    count=1
fi
echo "$count" > "$ITERATION_FILE"

# Safety: stop after max iterations
if [ "$count" -ge "$MAX_ITERATIONS" ]; then
    rm -f "$ITERATION_FILE"
    echo "Max iterations ($MAX_ITERATIONS) reached. Stopping loop." >&2
    exit 0
fi

# Skip if no test files exist yet
if ! find . -name "*.test.*" -o -name "*.spec.*" -o -name "test_*" 2>/dev/null | grep -q .; then
    rm -f "$ITERATION_FILE"
    exit 0
fi

# Run tests
TEST_OUTPUT=$(npm test 2>&1) || {
    echo "ITERATION $count/$MAX_ITERATIONS - Tests failing:" >&2
    echo "$TEST_OUTPUT" | tail -30 >&2
    echo "" >&2
    echo "Fix the failing tests and try again." >&2
    exit 2
}

# Run lint (if configured)
if [ -f "package.json" ] && grep -q '"lint"' package.json; then
    LINT_OUTPUT=$(npm run lint 2>&1) || {
        echo "ITERATION $count/$MAX_ITERATIONS - Lint errors:" >&2
        echo "$LINT_OUTPUT" | tail -20 >&2
        echo "" >&2
        echo "Fix lint errors and try again." >&2
        exit 2
    }
fi

# Run typecheck (if configured)
if [ -f "tsconfig.json" ]; then
    TYPE_OUTPUT=$(npx tsc --noEmit 2>&1) || {
        echo "ITERATION $count/$MAX_ITERATIONS - Type errors:" >&2
        echo "$TYPE_OUTPUT" | tail -20 >&2
        echo "" >&2
        echo "Fix type errors and try again." >&2
        exit 2
    }
fi

# All green - reset counter and let Claude stop
rm -f "$ITERATION_FILE"
exit 0
Python 版
#!/bin/bash
# Python TDD Loop Check

MAX_ITERATIONS=25
ITERATION_FILE=".claude/.tdd-iteration-count"

if [ -f "$ITERATION_FILE" ]; then
    count=$(cat "$ITERATION_FILE")
    count=$((count + 1))
else
    count=1
fi
echo "$count" > "$ITERATION_FILE"

if [ "$count" -ge "$MAX_ITERATIONS" ]; then
    rm -f "$ITERATION_FILE"
    echo "Max iterations ($MAX_ITERATIONS) reached." >&2
    exit 0
fi

if ! find . -name "test_*" -o -name "*_test.py" 2>/dev/null | grep -q .; then
    rm -f "$ITERATION_FILE"
    exit 0
fi

TEST_OUTPUT=$(pytest -v 2>&1) || {
    echo "ITERATION $count/$MAX_ITERATIONS - Tests failing:" >&2
    echo "$TEST_OUTPUT" | tail -30 >&2
    exit 2
}

if command -v ruff &>/dev/null; then
    LINT_OUTPUT=$(ruff check . 2>&1) || {
        echo "ITERATION $count/$MAX_ITERATIONS - Lint errors:" >&2
        echo "$LINT_OUTPUT" | tail -20 >&2
        exit 2
    }
fi

if command -v mypy &>/dev/null; then
    TYPE_OUTPUT=$(mypy . 2>&1) || {
        echo "ITERATION $count/$MAX_ITERATIONS - Type errors:" >&2
        echo "$TYPE_OUTPUT" | tail -20 >&2
        exit 2
    }
fi

rm -f "$ITERATION_FILE"
exit 0

品質を確保するための追加フック

PreToolUse フック:ファイル書き込み前に Lint を実行

Write/Edit が適用される前に Linter を実行します。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "scripts/pre-write-lint.sh",
            "timeout": 10,
            "statusMessage": "Checking code quality..."
          }
        ]
      }
    ]
  }
}
SessionStart フック:コンテキストを自動挿入

セッション開始時に実行され、プロジェクト情報を挿入します。

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'TDD loop active. Tests run automatically after each response. Fix failures to continue.'",
            "statusMessage": "Loading project context..."
          }
        ]
      }
    ]
  }
}

基本方針

┌─────────────────────────────────────────────────────────────┐
│  ITERATION > PERFECTION                                     │
│  ─────────────────────────────────────────────────────────  │
│  Don't aim for perfect on first try.                        │
│  Let the loop refine the work. Each iteration builds on     │
│  previous attempts visible in files and git history.        │
├─────────────────────────────────────────────────────────────┤
│  FAILURES ARE DATA                                          │
│  ─────────────────────────────────────────────────────────  │
│  Failed tests, lint errors, type mismatches are signals.    │
│  The Stop hook feeds them directly to Claude as context.    │
├─────────────────────────────────────────────────────────────┤
│  CLEAR COMPLETION CRITERIA                                  │
│  ─────────────────────────────────────────────────────────  │
│  The hook defines "done": tests pass, lint clean, types ok. │
│  No ambiguity about when to stop.                           │
└─────────────────────────────────────────────────────────────┘

エラーの分類

すべての失敗でループを続けるべきではありません。フックスクリプトでは、次のように区別する必要があります。

種類例対応
コードエラーロジックのバグ、誤ったアサーション、型の不一致終了コード 2 → ループを続行
アクセスエラーAPI キーがない、DB への接続が拒否された終了コード 0 → 停止してユーザーに報告
環境エラーパッケージがない、ランタイムのバージョンが違う終了コード 0 → 停止してユーザーに報告

上記のサンプルスクリプトでは、この処理が行われます。終了コード 2 を返すのはテスト、Lint、型の失敗のみで、環境の問題ではありません。


TDD ループを使う場面

適している場面
ユースケース理由
機能開発テストにより合格/不合格が明確に分かる
バグ修正失敗するテストを書き、修正して、成功するまでループする
リファクタリング既存のテストでリグレッションを検出できる
API 開発各エンドポイントを個別にテストできる
適していない場面
ユースケース理由
UI/UX 作業人による判断が必要
一度限りの操作繰り返す必要がない
要件が不明確な場合明確な「完了」の基準がない
主観的なデザイン客観的な成功指標がない

ループを無効にする

セッション中に TDD ループを一時的に無効にするには、次のいずれかを行います。

  1. .claude/settings.json の Stop フックを削除するか、名前を変更します
  2. またはスクリプトで MAX_ITERATIONS=1 を設定します
  3. または scripts/tdd-loop-check.sh を削除します

スクリプトが存在し、設定されている場合にのみフックが実行されます。


Gitignore への追加

# TDD loop state
.claude/.tdd-iteration-count

コメント