Claude Codeに実装を任せ始めると、次のような悩みが出てきます。「Claudeが書いたコードがlintを通っていない」「PRコメントへの返信が”後で対応します”ばかり」「レビュー通過後にマージし忘れる」。これらは個々のプロンプトを工夫しても解決しません。仕組みとして品質を担保する設計が必要です。
この考え方をハーネスエンジニアリングと呼びます。プロンプトで出力品質を上げる「狩り」から、仕組みで品質を担保する「稲作」へ、という転換です。本記事では、PR作成からマージまでの開発フローを4層防衛で自動化する実践的な設計をまとめます。
各コンポーネントの基礎は関連記事で確認できます。Claude Code Hooks完全ガイド・Skills・コマンドガイド・GitHub Actions自動化ガイド・Claude Code レビューループ設計も参照してください。
4層防衛モデルの全体像
品質担保の仕組みを速度と網羅性で4層に分けます。ローカルで速く動く検証と、リモートで網羅的に動く検証を組み合わせるのが設計の要点です。
| 層 | タイミング | 主体 | 役割 | ツール例 |
|---|---|---|---|---|
| 第1層 | Claude Code操作前後 | Claude Code hooks | AIの行動をリアルタイム制御 | pre-bash-guard, post-edit-lint |
| 第2層 | git操作時 | Lefthook | コミット・プッシュ前ゲート | Clippy, ast-grep, Biome |
| 第3層 | 任意タイミング | Claude Code skills | 複雑な検証をコマンドで実行 | /pre-push-review |
| 第4層 | push後 | GitHub Actions + CodeRabbit | 最終防衛・網羅的チェック | CodeRabbit, jscpd |
重要なのは「速いローカル検証と網羅的なリモート検証を分離する」という思想です。すべてをCIに任せると待ち時間が長く、Claudeのフィードバックループが遅くなります。逆にローカルだけでは見落としが生じます。両者を組み合わせることで、速さと確実性を両立します。
第1層:Claude Code Hooksによるリアルタイム制御
Claude Code hooksは、AIがツールを実行する直前(PreToolUse)・直後(PostToolUse)に任意のシェルコマンドを差し込める仕組みです。ここに「守らせたいルール」を実装することで、Claudeが破れない制約を作ります。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-bash-guard.sh"
}
]
},
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-edit-guard.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-edit-lint.sh"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-push-monitor.sh"
}
]
}
]
}
}
pre-bash-guard:AI先送り返信を防ぐ
ハーネスエンジニアリングで最も重要なhookの一つがpre-bash-guardです。Claudeはレビューコメントへの返信で「後で対応します」「次のPRで修正します」といった先送り返信を書きがちです。これをBashコマンド実行前に検出してブロックします。
#!/bin/bash
# Bashコマンドに渡す内容を標準入力から受け取る
INPUT=$(cat)
# 先送り表現の検出
if echo "$INPUT" | grep -qE "後で対応|次回対応|別のPRで|追って修正|TODO.*後で"; then
echo "先送り返信を検出しました。以下の2択で対応してください:" >&2
echo " 1. その場で修正してからコメントに返信する" >&2
echo " 2. GitHub Issueを作成し、Issue番号を添えて返信する" >&2
exit 2 # exit 2 でClaudeへのフィードバックとして返す
fi
# 危険なコマンドのブロック
if echo "$INPUT" | grep -qE "git push --force|--no-verify|rm -rf /"; then
echo "危険なコマンドが検出されました。実行を中止します。" >&2
exit 2
fi
# PRゲート(pre-push-reviewを通していなければgh pr createをブロック)
if echo "$INPUT" | grep -q "gh pr create"; then
if [ ! -f ".claude/tmp/.review-passed" ]; then
echo "/pre-push-review を先に実行してください。" >&2
echo "レビューを通過するまでgh pr createはブロックされます。" >&2
exit 2
fi
fi
pre-edit-guard:設定ファイルの意図しない変更を防ぐ
Claudeが「効率化」のつもりで.claude/settings.jsonやlefthook.ymlを書き換えてしまうことがあります。pre-edit-guardでこれを防ぎます。
#!/bin/bash
FILE=$(echo "$CLAUDE_TOOL_INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('file_path',''))")
# 保護対象ファイル
PROTECTED=(".claude/settings.json" "lefthook.yml" ".github/workflows")
for p in "${PROTECTED[@]}"; do
if [[ "$FILE" == *"$p"* ]]; then
echo "保護対象ファイル ($p) の編集は禁止されています。" >&2
echo "変更が必要な場合は人間に確認してください。" >&2
exit 2
fi
done
post-edit-lint:編集後に即時フィードバック
ファイル編集の直後にlint/formatを走らせ、問題をすぐにClaudeへ返します。CIを待たずにフィードバックループを高速化できます。
#!/bin/bash
FILE=$(echo "$CLAUDE_TOOL_INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('file_path',''))")
case "$FILE" in
*.ts|*.tsx) npx biome check --apply "$FILE" 2>&1 ;;
*.rs) cargo clippy -- -D warnings 2>&1 ;;
*.py) ruff check "$FILE" 2>&1 ;;
esac
第2層:Lefthookによるgit前ゲート
Lefthookはgit hooksをYAMLで管理するツールです。コミット・プッシュ前に複数のチェックを並列実行できるのが特徴で、AIも人間も同じ制約を受けるゲートとして機能します。
pre-commit:
parallel: true
commands:
fmt:
run: cargo fmt --check
fail_text: "フォーマットが崩れています。cargo fmt を実行してください。"
clippy:
run: cargo clippy -- -D warnings -D clippy::pedantic
fail_text: "Clippyエラーがあります。"
biome:
run: npx biome check .
fail_text: "Biomeのチェックが失敗しました。"
ast-grep:
run: sg scan --config .ast-grep/rules/
fail_text: "アーキテクチャ制約違反があります。"
pre-push:
commands:
test:
run: cargo test --workspace
ast-grepでアーキテクチャ制約を強制する
ast-grepはASTベースの構造検索ツールで、「domainレイヤーからinfrastructureをimportしてはいけない」といったアーキテクチャ制約をコードとして定義できます。lintルールでは検出できない設計違反を機械的に止められます。
id: no-infra-in-domain language: rust rule: kind: use_declaration regex: "infrastructure" files: - "src/domain/**/*.rs" severity: error message: | domainレイヤーからinfrastructureをimportしてはいけません。 WHY: DDDのレイヤー依存ルール違反。domainは外部依存を持たない。 FIX: domainにトレイトを定義し、infrastructureで実装してください。
第3層:/pre-push-reviewスキルによるPR前レビュー
第3層は/pre-push-reviewカスタムスラッシュコマンドです。PR作成前に4つのレビューを並列実行し、重大な問題は自動修正、それ以外は人間に確認を求めます。このスキルを通過するまでgh pr createはpre-bash-guardにブロックされます。
--- name: pre-push-review description: PR作成前の並列レビュー(セキュリティ・品質・複雑度) --- 以下の4つのレビューを並列で実行してください。 ## 実行内容 1. **code-simplifier**(サブエージェント) - 過剰な抽象化・重複コード・テストされていないコードを検出 - 自動で単純化できるものは修正する 2. **security-auditor**(サブエージェント) - 認証漏れ・OWASP Top 10・入力バリデーション不備を確認 - HIGH以上の問題は即時修正 3. **coderabbit-cli**(スキル実行) - PR作成前にCodeRabbit CLIでレビューを実行 - 重大な指摘は修正してから次へ進む 4. **security-review**(スキル実行) - HIGH CONFIDENCE と判定された脆弱性のみ抽出 ## 完了後 すべてのチェックが通過したら `.claude/tmp/.review-passed` を作成してください。 gh pr create が解除されます。
ポイント:このフラグファイル方式(.review-passed)がハーネスとして機能します。pre-bash-guardがフラグの存在を確認するため、レビューをスキップしてPRを作ることをAIも人間もできなくなります。フラグはpost-push-monitorがプッシュ後に自動で削除します。
第4層:GitHub Actions + CodeRabbitによる最終防衛
ローカルの3層を通過したコードが最終的にGitHub Actionsで検証されます。ここでは時間のかかる包括的なテスト・CodeRabbitによる自動コードレビューを行います。
name: CI
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --workspace
- name: Check duplicate code
run: npx jscpd --min-lines 10 --reporters json
- name: CodeRabbit review
uses: coderabbitai/ai-pr-reviewer@latest
with:
openai_light_model: gpt-4o-mini
post-push-monitor:push後の自動監視
pushが成功した後、post-push-monitor hookが起動します。CronCreateツールを使って1分間隔のポーリングを設定し、CodeRabbitのレビュー完了を待ちます。完了したらレビュー内容を取得し、Claudeに自動で対応を開始させます。
# post-push-monitor hook が起動すると以下を実行
1. gh pr view --json number で最新PRを取得
2. CronCreate で1分間隔の監視を設定:
"/check-ci-coderabbit PR番号を確認し、CodeRabbitのレビューが
完了していれば指摘内容を取得して対応を開始してください"
3. CodeRabbitのレビューコメントを取得
4. 指摘への返信前に pre-bash-guard が先送り表現を検出・ブロック
5. その場で修正 or Issue作成してから返信
6. 全コメントに返信完了 → /merge-and-cleanup を実行
Rules と Hooks の役割分担
CLAUDE.mdやrulesファイルとhooksの使い分けは、「破ろうと思えば破れるか」で判断します。
| 仕組み | 強制力 | 使うべき場面 | 例 |
|---|---|---|---|
| CLAUDE.md | なし(ガイドライン) | コンテキスト・背景の説明 | プロジェクトの目的・設計思想 |
| rules | 弱い(読まれれば従う) | ファイルパス別のガイドライン | 「domainにはインフラを書かない」 |
| hooks | 強い(物理的にブロック) | 絶対に守らせたいこと | 先送り返信・危険コマンドの禁止 |
| Lefthook | 強い(commit/pushできない) | コード品質の最低基準 | lint・formatエラーがあればコミット不可 |
よくある失敗:「絶対に守ってほしいこと」をrules(Markdownファイル)に書いても、Claudeがそのファイルを読まなければ守られません。本当に強制したいことはhooksかLefthookに昇格させてください。rulesはあくまで「破ろうと思えば破れる」ガイドラインです。
自動化できること vs 人間が判断すべきこと
ハーネスエンジニアリングは人間を排除するものではありません。AIに任せる部分と、人間が価値を出す判断を明確に分けることが目的です。
| 自動化できること | 人間が判断すること |
|---|---|
| 編集時のlint/format実行 | 設計・実装方針の承認 |
| コミット時の品質チェック | レビュー指摘を直すかどうか |
| PR作成前のセキュリティ・品質レビュー | 未解決コメントを解決済みにしてよいか |
| push後のCI/CodeRabbit監視 | アーキテクチャに関わる変更の判断 |
| レビューコメントへの返信・修正 | ビジネスロジックの優先度判断 |
| マージ・チケットクローズ・ブランチ削除 | リリースタイミングの決定 |
よくある質問
まとめ
ハーネスエンジニアリングの核心は、「プロンプトで頑張る(狩り)から、仕組みで品質を担保する(稲作)へ」という転換です。
- 第1層(hooks):AIの行動をリアルタイムで制御。先送り返信・危険コマンド・PRゲートを実装
- 第2層(Lefthook):git前ゲートで全員が同じ制約を受ける
- 第3層(skills):/pre-push-reviewで並列レビュー。通過しないとPR作成不可
- 第4層(GitHub Actions/CodeRabbit):最終防衛で網羅的なチェック
人間が本当に価値を出す「設計承認・レビュー判断・リリース決定」に集中できる環境を、仕組みとして作るのがゴールです。
関連記事:Claude Code Hooks完全ガイド / Skills・コマンドガイド / レビューループ設計 / GitHub Actions自動化ガイド

