hookshot について
hookshotは、リポジトリのドキュメントからエージェント向けの案内やチェック用フックを生成する、Claude CodeとCodex向けのスキルです。既定では警告にとどまり、配信ゲートは記録を確認してからリポジトリ側で強制モードに切り替えられます。
主な機能
- 01ドキュメントから編集時の案内フックを生成
- 02追跡対象スキルの編集を警告
- 03変更されたMarkdownをLint
- 04セッション事前確認と配信ゲートを追加
- 05既存フックへ冪等にマージ
活用シーン
- 01重要なコードの変更前に関連ドキュメントを案内
- 02同期対象スキルの編集を上流反映向けに通知
- 03Markdown編集後にLint警告を表示
- 04成果条件に沿わないセッション終了を阻止するか判断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ fellowship-dev/ dogfooded-skills --skill hookshotインストール後、Claude Code で/hookshotを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/contract-format.mdshadow-log.mdscripts/gate.pypreflight.pytest_gate.py詳細
Hookshot
ドキュメントから強制適用フックへ。ドキュメントに書かれた内容を読み取り、エージェントに読ませるフックを生成します。
理念: Hookshot はデフォルトでは警告を出し、リポジトリが明示的に有効化したゲートに限ってブロックします。ファイルを変更したり、リントして修正したりすることはありません。生成するフックはすべてガイダンスを出力して終了コード 0 で終了します。唯一の例外はデリバリーゲートです。このゲートは、リポジトリがシャドウログを確認した後、シャドウ(ログのみ)からエンフォース(停止を拒否)へ切り替えられます。
モード
Hookshot は組み合わせて使用できます。1 つ以上のフラグを指定して実行します。デフォルトモード(フラグなし)では、ドキュメントカバレッジジェネレーターを実行します。
| フラグ | 追加されるもの |
|---|---|
| (フラグなし) | ドキュメントカバレッジ — 編集対象のファイルがカバーされている場合、編集前に関連する docs/ のセクションを読むようエージェントに促す PreToolUse Edit/Write フックです。(デフォルトの動作。以下に説明します。) |
--drift-warn | スキルのドリフト警告 — エージェントが skills-lock.json で追跡されているスキルの .claude/skills/<name>/ 内のファイルを編集したときに警告する PreToolUse Edit/Write フックです。編集内容は上流に反映する必要があります。 |
--md-lint | Markdown リント — 変更された *.md ファイルに対して npx markdownlint-cli2 を実行し、警告を表示する PostToolUse Edit/Write フックです。自動修正は行いません。 |
--preflight | セッションの事前確認 — エージェントにセッション ID とタスクの事前確認を実行するよう伝え、結果のコントラクトへのポインターを記録する場所を知らせる SessionStart フックです(起動、再開、クリア、コンパクト時)。scripts/preflight.py を同梱します。 |
--gate | デリバリーゲート — セッションの成果コントラクトと既存の状態を比較する Stop フックです。シャドウモードでは拒否する予定だった内容をログに記録し、エンフォースモードでは停止を拒否します。scripts/gate.py、references/contract-format.md、references/shadow-log.md を同梱します。 |
フラグは組み合わせられます。/hookshot --drift-warn --md-lint を実行すると、デフォルトのドキュメントカバレッジフックとともに 2 つの新しいフックがインストールされます。独自のスクリプトを同梱し、Claude Code と同様に Codex にもインストールされるのは --preflight --gate だけです。hookshot を再実行すると、既存のフックに冪等にマージされます。
npx でインストール:
npx skills add fellowship-dev/dogfooded-skills/ops/hookshot
使用するタイミング
- ナレッジレイヤー(
ARCHITECTURE.md、docs/)を作成した後 — hookshot がそれをエージェントのランタイムに接続します docs/code-structure.mdまたはdocs/code-guidelines.mdを更新した後 — フックを再生成して最新の状態に保ちます#1585-class bugが発生したとき:エージェントがドキュメントを読まずに重要なパスを変更した場合 — 再発を防ぐフックを追加します- 新しい FlowChad フローを追加した後 — その重要なパス向けのフックを生成します
Pylot との連携
- インストール:
boot-skills.shはnpx skills addを使って hookshot スキルをインストールします。ただし、スキルをインストールすることとフックを生成することは別です。アーティファクト(doc-coverage.json、check-docs.sh、settings.jsonのフック、docs/hooks.md)を生成するには、少なくとも一度/hookshotを実行する必要があります。 - 古さの確認:
entropy-checkは、PR のマージ時と週次の cron で hookshot のカバレッジが最新かどうかを監視します。古くなっていると指摘されたら、/hookshotを再実行してください。 - リポジトリごと: 各リポジトリに独自のフックが設定されます。複数のリポジトリにまたがるミッションでは、対象リポジトリのフックを使用します。
重要な洞察
「リントはカスタムなので、修正手順をエージェントのコンテキストに挿入できるよう、エラーメッセージを作成します。」 — OpenAI harness engineering
Hookshot を使えば、これを自動化できます。エージェントには「この領域を変更する前に、check_redirect
の仕組みを読んでください」と伝えられていたはずです。このスキルは、ドキュメントからそのメッセージを生成します。
生成されるもの
check-docs.sh— 編集中のファイルが docs/ の対象であれば、ドキュメントを確認するよう促すメッセージを標準エラー出力に表示します.claude/settings.jsonフック — すべての Edit/Write でcheck-docs.shを呼び出す PreToolUse フックです- ドメインカバレッジマップ —
$REPO_ROOT/.claude/doc-coverage.json— ファイルの glob とドキュメントのセクションを対応付けます - カスタムリントメッセージ — 特定のドキュメントセクションへのリンクを含む修正手順です
手順
0. リポジトリを特定する
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename $(git remote get-url origin) .git)
mkdir -p $REPO_ROOT/.claude
1. ナレッジレイヤーを解析する
すべてのドキュメントファイルを読み込み、カバレッジのマッピングを抽出します。
# Read all key docs
cat $REPO_ROOT/docs/code-structure.md 2>/dev/null
cat $REPO_ROOT/docs/code-guidelines.md 2>/dev/null
cat $REPO_ROOT/ARCHITECTURE.md 2>/dev/null
ls $REPO_ROOT/.flowchad/flows/ 2>/dev/null
docs/code-structure.md の各ドメインセクションについて、以下を抽出します。
- ドメイン名(セクション見出し)
- ディレクトリパス(「Directory:」の行)
- 主要ファイル(エントリーポイントの表から)
- 重要なパターン(「Don't Repeat」セクションから。最優先事項です)
.flowchad/flows/ の各 FlowChad フローについて、以下を抽出します。
- フロー名
- ドメイン
- エントリーポイントファイル(フロー定義から)
- 変更対象ファイル(フロー内のすべての
file:エントリー)
2. カバレッジマップを作成する
$REPO_ROOT/.claude/doc-coverage.json を作成します。
{
"version": "1",
"generated": "{DATE}",
"repo": "{REPO_NAME}",
"entries": [
{
"glob": "app/controllers/**/*.rb",
"domain": "Controllers",
"doc_section": "docs/code-structure.md#controllers",
"reminder": "Before modifying a controller, read how the controller pattern works: docs/code-structure.md#controllers. Key rule: controllers do not query the DB directly — use service objects.",
"criticality": "high"
},
{
"glob": "app/services/**/*.rb",
"domain": "Services",
"doc_section": "docs/code-structure.md#services",
"reminder": "Service objects in app/services/ follow the Command pattern. Read docs/code-structure.md#services for the interface contract.",
"criticality": "medium"
}
]
}
ドメインディレクトリのマッピングごとに1つのエントリーを作成します。FlowChad フロー内で見つかった重要なパスには、criticality: "high" を設定します。
リマインダーテキストのルール:
- 最初に、読むべき具体的なドキュメントセクションを記載します
- そのドメインの最も重要な「Don't Repeat」ルールを含めます
- 200文字未満にします。エージェントのコンテキストに表示されるため、長文は避けてください
- 実行可能な指示にします。「X を読む」のように記載し、「X を読むことを検討する」とはしません
3. check-docs.sh を生成する
$REPO_ROOT/.claude/check-docs.sh を作成します。
#!/usr/bin/env bash
# check-docs.sh — Generated by hookshot on {DATE}
# Usage: check-docs.sh <file_path_being_edited>
# Outputs doc reminders to stderr if the file is covered by docs/
set -euo pipefail
FILE_PATH="${1:-}"
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# Normalize path relative to repo root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COVERAGE_MAP="$SCRIPT_DIR/doc-coverage.json"
if [ ! -f "$COVERAGE_MAP" ]; then
exit 0
fi
# Check file against each glob in the coverage map
# Uses jq to parse coverage map and bash glob matching
REMINDERS=$(jq -r '.entries[] | "\(.glob)\t\(.reminder)\t\(.criticality)"' "$COVERAGE_MAP" 2>/dev/null)
FOUND_REMINDER=""
FOUND_CRITICALITY=""
while IFS=$'\t' read -r GLOB REMINDER CRITICALITY; do
# Normalize the file path
REL_PATH="${FILE_PATH#$REPO_ROOT/}"
# Normalize for bash [[ ]] pattern matching:
# 1. **/ → * (** has no special meaning; * already matches any char incl /)
# 2. Escape [ ] so Next.js routes like [locale] are literal, not char classes
GLOB="${GLOB//\*\*\//*}"
GLOB="${GLOB//\[/\\[}"
GLOB="${GLOB//\]/\\]}"
if [[ "$REL_PATH" == $GLOB ]]; then
FOUND_REMINDER="$REMINDER"
FOUND_CRITICALITY="$CRITICALITY"
break
fi
done <<< "$REMINDERS"
if [ -n "$FOUND_REMINDER" ]; then
if [ "$FOUND_CRITICALITY" = "high" ]; then
echo "⚠️ DOCUMENTATION REMINDER (high criticality)" >&2
echo "$FOUND_REMINDER" >&2
echo "" >&2
echo "This file is in a critical path. Read the doc section before proceeding." >&2
else
echo "📖 Doc reminder: $FOUND_REMINDER" >&2
fi
fi
exit 0
実行可能にします。
chmod +x $REPO_ROOT/.claude/check-docs.sh
4. フックを settings.json に書き込む
既存の .claude/settings.json があれば読み込みます。
既存のフックを上書きせずに、フック設定をマージします。
追加するフック:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash {REPO_ROOT}/scripts/check-docs.sh \"$(jq -r '.tool_input.file_path // empty')\""
}
]
}
]
}
}
マージ戦略:
PreToolUseがすでに存在する場合 → 置き換えずに配列へ追加します- 同一の
check-docs.shフックがすでに存在する場合 → スキップします(冪等性を保ちます) - 既存のフックエントリーはすべて保持します
マージした結果を .claude/settings.json に書き戻します。
5. カスタム lint メッセージを生成する
docs/code-guidelines.md の各ガイドラインについて、lint メッセージファイルを生成します。
$REPO_ROOT/.claude/lint-messages.md を作成します。
# Custom Lint Messages — {REPO_NAME}
Generated by hookshot on {DATE}. Used by PreToolUse hooks to inject remediation context.
## {Domain}: {Rule Name}
**Pattern detected:** {what triggers this message}
**Message injected into context:**
> {The exact message the agent will see}
**Doc reference:** docs/code-guidelines.md#{anchor}
---
{Repeat per rule}
重要なルール(例:「独自の認証を実装しない」「インライン条件式ではなく check_redirect を使う」)については、check-docs.sh に追加する明示的なチェックコマンドを生成します。
# Add to check-docs.sh after the glob check:
# Rule-based checks (pattern detection in file content)
if echo "$FILE_PATH" | grep -q "controllers/"; then
# Check if file being written contains a raw redirect without check_redirect
# (This is a hint — actual content checking happens post-edit)
echo "📖 Controllers reminder: Use check_redirect in lib/redirect_service.rb for all redirects." >&2
fi
これらのルールベースのチェックを、明確なマーカーを付けたセクションとして check-docs.sh に追加します。
5b. docs/hooks.md を生成する
対象リポジトリに、現在有効なフックを説明する docs/hooks.md ファイルを生成します。
# Hooks — {REPO_NAME}
> Auto-generated by [hookshot](https://github.com/fellowship-dev/dogfooded-skills). Safe to add notes — hookshot merges on update, it won't overwrite your additions.
## Active Hooks
### PreToolUse: Doc Reminders on Edit/Write
**Trigger:** Every `Edit` or `Write` tool call
**Script:** `scripts/check-docs.sh` (or `.claude/check-docs.sh`)
**Config:** `.claude/settings.json` → `hooks.PreToolUse`
**Coverage map:** `.claude/doc-coverage.json`
When an agent edits a file matching a covered glob, the hook injects a doc reminder into context before the edit proceeds. High-criticality files produce warnings; medium-criticality files produce reminders.
## Covered Domains
{For each entry in doc-coverage.json, list:}
| Domain | Glob | Criticality | Reminder |
|--------|------|-------------|----------|
| {domain} | `{glob}` | {criticality} | {reminder} |
## Maintaining Hooks
- **Quick tweaks:** Edit `.claude/doc-coverage.json` directly — add/remove entries, adjust criticality or reminder text. Changes take effect immediately.
- **Full regeneration:** Run `/hookshot` to rebuild coverage map from current `docs/code-structure.md`. This merges with your existing `doc-coverage.json` and `docs/hooks.md` — it won't overwrite manual additions.
- **Staleness detection:** `/entropy-check` monitors whether hooks are current vs docs. If it flags staleness, re-run `/hookshot`.
## Troubleshooting
### Glob doesn't match expected files
The hook uses bash `[[ ]]` pattern matching, which differs from gitignore globs:
- `**` has no special meaning — `*` already matches any character including `/`
- `[brackets]` are character classes, not literal — Next.js routes like `[locale]` need escaping
- The generated `check-docs.sh` normalizes both automatically. If you're writing manual globs, use `*` not `**/*` for recursive matching.
Test a glob: `bash scripts/check-docs.sh "/full/path/to/file.ts"`
### Hook breaks the agent or slows edits
Disable temporarily by removing the hook entry from `.claude/settings.json`. Re-run `/hookshot` to restore.
### settings.json got clobbered
Re-run `/hookshot` — it merges hooks into existing settings, never overwrites other config.
再実行時は既存の docs/hooks.md を読み込み、マージします。人が追加したセクションは保持し、「Covered Domains」表と「Active Hooks」セクションは現在の状態から再生成します。
6. 検証
生成したフックをテストします。
# Test with a file that should trigger a reminder
bash $REPO_ROOT/.claude/check-docs.sh "$REPO_ROOT/app/controllers/sessions_controller.rb"
# Test with a file that should NOT trigger
bash $REPO_ROOT/.claude/check-docs.sh "$REPO_ROOT/README.md"
# Verify settings.json is valid JSON
cat $REPO_ROOT/.claude/settings.json | jq . > /dev/null && echo "settings.json: valid JSON"
# Verify doc-coverage.json is valid JSON
cat $REPO_ROOT/.claude/doc-coverage.json | jq . > /dev/null && echo "doc-coverage.json: valid JSON"
7. サマリーレポート
## Hookshot Complete: {REPO_NAME}
### Coverage Map
- {N} domain entries in .claude/doc-coverage.json
- {N} high-criticality entries (will produce warnings)
- {N} medium-criticality entries (will produce reminders)
### Hooks Generated
- .claude/check-docs.sh — glob-based doc lookup
- .claude/settings.json — PreToolUse hook wired
- .claude/lint-messages.md — custom lint message catalog
- docs/hooks.md — human-readable hook documentation
### Coverage Gaps
{List any domains in ARCHITECTURE.md that have no glob coverage — need manual mapping}
### Manual Next Steps
- [ ] Review .claude/doc-coverage.json — adjust globs that are too broad or too narrow
- [ ] Test a real edit to a covered file and confirm the reminder appears
- [ ] Add rule-based checks for your most critical "Don't Repeat" patterns
- [ ] Run /entropy-check to verify grades reflect the new hook coverage
モード:ドリフト警告(--drift-warn)
skills-lock.json で追跡されているスキルの .claude/skills/<name>/ ディレクトリ内のファイルをエージェントが編集しようとしたときに警告します。実際の編集はブロックしません。これはガイダンスであり、アップストリームへ反映する前に、同期されたスキルに緊急修正を加える必要がある場合もあります。
.claude/check-skill-drift.sh を生成する
#!/usr/bin/env bash
# check-skill-drift.sh — Generated by hookshot (--drift-warn) on {DATE}
# Usage: check-skill-drift.sh <file_path>
# Warns to stderr if the file belongs to a skill tracked in skills-lock.json.
set -uo pipefail
FILE_PATH="${1:-}"
[ -z "$FILE_PATH" ] && exit 0
# Walk up from the file to find the nearest skills-lock.json
DIR="$(dirname "$FILE_PATH")"
LOCK_FILE=""
while [ "$DIR" != "/" ] && [ "$DIR" != "." ]; do
if [ -f "$DIR/skills-lock.json" ]; then
LOCK_FILE="$DIR/skills-lock.json"
break
fi
DIR="$(dirname "$DIR")"
done
[ -z "$LOCK_FILE" ] && exit 0
# Path must contain /.claude/skills/<name>/ or /.agents/skills/<name>/
SKILL_NAME="$(echo "$FILE_PATH" | sed -nE 's|.*/\.(claude|agents)/skills/([^/]+)/.*|\2|p')"
[ -z "$SKILL_NAME" ] && exit 0
# Look up in lockfile
SOURCE=$(python3 -c "
import json, sys
try:
data = json.load(open('$LOCK_FILE'))
entry = (data.get('skills') or {}).get('$SKILL_NAME')
if entry:
print(entry.get('source', ''))
except Exception:
pass
" 2>/dev/null)
if [ -n "$SOURCE" ]; then
echo "⚠️ SKILL DRIFT WARNING" >&2
echo "'$SKILL_NAME' is a remote skill synced from: $SOURCE" >&2
echo "Local edits will drift from upstream and may be overwritten on next 'npx skills update'." >&2
echo "Edit upstream at https://github.com/$SOURCE instead, or be prepared to PR the change back." >&2
fi
exit 0
実行可能にし、matcher Edit|Write を指定して .claude/settings.json の PreToolUse に設定します。既存の内容を上書きせずにマージします。デフォルトのドキュメントカバレッジフックと同じ戦略を使います。
検証
# Should warn — entropy-check is a tracked skill
bash .claude/check-skill-drift.sh "$PWD/.claude/skills/entropy-check/SKILL.md"
# Should be silent — file is outside any skills dir
bash .claude/check-skill-drift.sh "$PWD/README.md"
# Should be silent — skill isn't in lockfile (e.g. a local-only skill)
bash .claude/check-skill-drift.sh "$PWD/.claude/skills/local-thing/SKILL.md"
モード:Markdown lint(--md-lint)
Edit または Write の後に、変更された .md ファイルに対して npx markdownlint-cli2 を実行し、警告をエージェントに通知します。自動修正は行いません。修正するかどうかはエージェントが判断します。
初期設定用 .markdownlint.json
リポジトリのルートに .markdownlint.json または .markdownlint-cli2.jsonc がない場合は、初期状態でリンターが煩雑にならないよう、制限の緩い初期設定ファイルを配置します。
{
"default": true,
"MD013": false,
"MD033": false,
"MD041": false
}
MD013(行の長さ)— デフォルトでは無効です。ドキュメントやスキルファイルでは長い行がよく使われますMD033(インライン HTML)— 無効です。レポートでは HTML の details/summary を使いますMD041(最初の行は h1 であること)— 無効です。frontmatter から始まるドキュメントが多くあります
設定ファイルがすでに存在する場合は、そのままにします。上書きしないでください。
.claude/check-md-lint.sh を生成する
#!/usr/bin/env bash
# check-md-lint.sh — Generated by hookshot (--md-lint) on {DATE}
# Usage: check-md-lint.sh <file_path>
# Runs markdownlint-cli2 on the file if it's *.md. Warns only — never fixes.
set -uo pipefail
FILE_PATH="${1:-}"
[ -z "$FILE_PATH" ] && exit 0
# Only lint markdown files
case "$FILE_PATH" in
*.md|*.markdown) ;;
*) exit 0 ;;
esac
[ -f "$FILE_PATH" ] || exit 0
# Run markdownlint-cli2 — fast start via npx
OUTPUT=$(npx --yes markdownlint-cli2 "$FILE_PATH" 2>&1) || true
if [ -n "$OUTPUT" ] && echo "$OUTPUT" | grep -qE 'MD[0-9]{3}'; then
echo "📝 Markdown lint warnings for $(basename "$FILE_PATH"):" >&2
echo "$OUTPUT" | grep -E 'MD[0-9]{3}' | head -20 >&2
echo "(warnings only — no auto-fix. Run 'npx markdownlint-cli2 --fix <file>' manually if desired.)" >&2
fi
exit 0
matcher Edit|Write を指定して、.claude/settings.json の PostToolUse に設定します(ファイルが存在してからでないと lint を実行できないため、PreToolUse ではありません)。
検証
# Should print MD### warnings if the file has any lint issues
bash .claude/check-md-lint.sh README.md
# Should be silent — not a markdown file
bash .claude/check-md-lint.sh package.json
モード:セッションの事前チェックと完了ゲート(--preflight、--gate)
2 つのフックを 1 つの所有者が管理します。スクリプトはこのスキル内にあり(scripts/preflight.py、scripts/gate.py、Python 3 標準ライブラリ)、クライアント設定はそれらを参照するだけです。リポジトリにロジックのコピーを持たせることはなく、接続設定のみを持たせます。
- 事前チェック(起動、再開、クリア、圧縮時の SessionStart):セッション ID、最初のプロンプトがタスクの場合に事前チェックを実行するよう促すリマインダー、エージェントが契約のリポジトリ相対パスを記録するポインターパス
<state>/contracts/<session_id>を挿入します。<state>/contracts/を作成します。 - ゲート(Stop):ポインターを使って契約を見つけ、
references/contract-format.mdに従って確認し、references/shadow-log.mdに従ってシャドウログに行を追加します。強制モードでは、未達項目とともに{"decision": "block", "reason": …}を返します。stop_hook_activeが true の場合はブロックせず、内部エラーが発生した場合は必ず 0 で終了します。
どちらのクライアントも、stdin で session_id、cwd、source(SessionStart)、stop_hook_active、last_assistant_message(Stop)を渡し、同じ additionalContext と decision: block の形式を受け付けます。Codex は prompt/agent ハンドラーを解析してスキップするため、LLM ジャッジは Claude Code でのみネイティブに動作します。Codex ではゲートに judge: none が記録されます。
環境変数
| 変数 | デフォルト | 用途 |
|---|---|---|
HOOKSHOT_STATE_DIR | <cwd>/.state | ポインター、シャドウログ、ジャッジ用パケット。Gitignore に追加してください。 |
HOOKSHOT_GATE_MODE | shadow | shadow はログを記録し、enforce は拒否します。ログを読んでから切り替えてください。 |
HOOKSHOT_PREFLIGHT_DOC | 未設定 | 事前チェックのリマインダーでエージェントに読むよう指示する、リポジトリ相対のドキュメント |
HOOKSHOT_NO_NETWORK | 未設定 | URL と PR の確認をスキップします(unverifiable と記録されます)。 |
Claude Code へのインストール(プロジェクトレベルの .claude/settings.json)
{
"hooks": {
"SessionStart": [{"hooks": [{"type": "command",
"command": "HOOKSHOT_PREFLIGHT_DOC=docs/preflight.md python3 \"$CLAUDE_PROJECT_DIR/.agents/skills/hookshot/scripts/preflight.py\" --client claude-code"}]}],
"Stop": [{"hooks": [{"type": "command", "timeout": 20,
"command": "HOOKSHOT_GATE_MODE=shadow python3 \"$CLAUDE_PROJECT_DIR/.agents/skills/hookshot/scripts/gate.py\" --client claude-code"}]}]
}
}
SessionStart マッチャーを省略すると、すべての source で実行されます。Claude Code デスクトップと VS Code 拡張機能は同じファイルを読み込みます。他のモードと同様に、既存の設定を上書きせずマージしてください。
Codex へのインストール(プロジェクトレベルの .codex/hooks.json)
{
"hooks": {
"SessionStart": [{"hooks": [{"type": "command",
"command": "HOOKSHOT_PREFLIGHT_DOC=docs/preflight.md python3 .agents/skills/hookshot/scripts/preflight.py --client codex"}]}],
"Stop": [{"hooks": [{"type": "command", "timeout": 20,
"command": "HOOKSHOT_GATE_MODE=shadow python3 .agents/skills/hookshot/scripts/gate.py --client codex"}]}]
}
}
Codex はセッションの cwd からフックを実行します。Codex はハッシュによって各フック定義を信頼します。フックのインストールまたは変更後は、各マシンで対話型 Codex セッション中に /hooks を実行し、信頼してください。これを --dangerously-bypass-hook-trust で自動化しないでください。Codex Desktop と IDE 拡張機能では、フックが実行されない問題や Stop のブロックでエラーが発生する問題が未解決です。シャドウログで問題がないと確認できるまでは、そこでのゲートとして終了時の手順を使ってください。
非対話型セッション
たとえばユーザー設定を無視して codex exec を起動するランナーなど、クライアントがフックを実行しない場合は、セッション終了後にランナーから同じスクリプトを呼び出します。
python3 .agents/skills/hookshot/scripts/gate.py --client codex-exec \
--session-id "$RUN_ID" --last-message "$LAST_MESSAGE_FILE" --cwd "$REPO"
契約ポインターは引き続き <state>/contracts/<RUN_ID> です。ランナーがすでに契約の場所を把握している場合は、--contract PATH を渡してください。
検証
python3 .agents/skills/hookshot/scripts/test_gate.py
echo '{"session_id":"t","cwd":"'$PWD'","source":"startup"}' | python3 .agents/skills/hookshot/scripts/preflight.py --client claude-code
echo '{"session_id":"t","cwd":"'$PWD'","stop_hook_active":false,"last_assistant_message":"DELIVERED"}' | python3 .agents/skills/hookshot/scripts/gate.py --client codex
tail -1 .state/hookshot/gate-shadow.jsonl
カバレッジマップのリファレンス
doc-coverage.json 形式では、次のグロブスタイルを使用できます。
| パターン | 一致対象 |
|---|---|
app/controllers/**/*.rb | controllers/ 以下のすべての Ruby ファイル |
src/pages/**/*.tsx | pages/ 以下のすべての TSX ファイル |
lib/redirect_service.rb | 完全一致するファイル |
app/models/user.rb | 完全一致するファイル |
**/*_mailer.rb | 場所を問わず、すべてのメーラーファイル |
重要度の高いファイルには具体的なグロブを使用してください。ドメインディレクトリには広範なグロブを使用してください。