claude-spotter 1.2.5 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/README.ja.md +101 -27
  3. package/README.md +103 -31
  4. package/bin/spotter.mjs +37 -6
  5. package/package.json +2 -2
  6. package/scripts/postinstall.mjs +4 -1
  7. package/src/cli/auditor-cmd.mjs +359 -0
  8. package/src/cli/codex-cmd.mjs +254 -0
  9. package/src/cli/codex-hook-cmd.mjs +752 -0
  10. package/src/cli/db-cmd.mjs +46 -12
  11. package/src/cli/diagnostics-cmd.mjs +120 -0
  12. package/src/cli/doctor.mjs +94 -19
  13. package/src/cli/install.mjs +23 -9
  14. package/src/core/auditor-backend.mjs +230 -0
  15. package/src/core/auditor-error.mjs +16 -0
  16. package/src/core/auditor-response.mjs +96 -0
  17. package/src/core/codex-cli-backend.mjs +342 -0
  18. package/src/core/codex-risk-dispatch.mjs +93 -0
  19. package/src/core/codex-sidecar-auditor-backend.mjs +310 -0
  20. package/src/core/codex-sidecar-policy.mjs +194 -0
  21. package/src/core/codex-sidecar-runner.mjs +740 -0
  22. package/src/core/codex-transcript.mjs +65 -0
  23. package/src/core/daemon-log-diagnostics.mjs +407 -0
  24. package/src/core/host-agent.mjs +18 -0
  25. package/src/core/judgment.mjs +86 -0
  26. package/src/core/sidecar-context.mjs +117 -0
  27. package/src/daemon/daemon.mjs +90 -97
  28. package/src/daemon/haiku-caller.mjs +107 -95
  29. package/src/daemon/transport.mjs +10 -2
  30. package/src/hooks/lib.mjs +8 -2
  31. package/src/hooks/session-start.mjs +9 -4
  32. package/src/hooks/spawn-daemon.mjs +2 -2
  33. package/src/hooks/user-prompt.mjs +16 -10
  34. package/src/index.mjs +70 -1
  35. package/src/tool-db/frontmatter.mjs +66 -3
  36. package/src/tool-db/investigate-codex.mjs +241 -0
  37. package/src/tool-db/investigate-mcp-http.mjs +3 -1
  38. package/src/tool-db/investigate-mcp.mjs +73 -10
  39. package/src/tool-db/loader.mjs +16 -3
  40. package/src/tool-db/refresh.mjs +16 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,127 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.4.0
4
+
5
+ **Codex native hooks を npm 配布可能な完成状態へ昇格する minor bump**。`npm install -g claude-spotter@1.4.0` で `spotter` CLI を global install し、各プロジェクトでは `spotter install`、Codex を使う場合は追加で `spotter codex-hook install` を実行するだけで動く状態にした。手書き tool list や install 時の Codex seed は不要で、Codex 側 catalog は SessionStart hook が自動更新する。
6
+
7
+ ### 主要変更
8
+
9
+ - **Codex native hooks**: `spotter codex-hook install|uninstall|diagnostics|session-start|user-prompt-submit|stop` を npm 配布対象として整備。Codex `SessionStart` は `spotter db refresh --host-agent codex` を detached 起動し、Codex tool catalog を `.spotter/tool-db.codex.json` に更新する。Claude `.spotter/tool-db.json` には触れない
10
+ - **Codex primary auditor backend**: Codex host の既定 backend を Codex CLI (`codex exec`) にした。`UserPromptSubmit` / `Stop` は Codex local DB だけを読み、Codex CLI unavailable / schema invalid / non-zero exit / timeout は structured error として surface する。Haiku への hidden fallback はしない
11
+ - **Codex CLI safety**: 子 Codex は read-only sandbox、stdin `ignore`、`model_reasoning_effort="low"`、hook auditor timeout 20s、bounded stderr diagnostics、`--output-schema` / `--output-last-message` を使う。timeout 時も last-message file に schema-valid final JSON があれば `completionReason=last_message_before_process_close` として success 扱いし、process close 遅延による誤 timeout を避ける
12
+ - **再帰 / セッション増殖ガード**: Codex CLI / `codex-sidecar` 子プロセスに `SPOTTER_PARENT_PID`、`SPOTTER_BACKEND`、`SPOTTER_CHILD_BACKEND` を入れ、hook 共通入口 `isChildCall()` がこれらを stdin 読み取り前に検知して return する。Claude 時代に経験した sub-agent / child session 増殖事故の再発を避ける
13
+ - **host-local tool-db 分離**: Claude は `.spotter/tool-db.json`、Codex は `.spotter/tool-db.codex.json` を使う。`spotter db refresh --host-agent codex` は Codex MCP / skills discovery だけを反映し、Claude refresh と相互に prune / overwrite しない
14
+ - **`codex-sidecar` の位置づけ整理**: primary auditor としては明示 override (`SPOTTER_AUDITOR_BACKEND=codex-sidecar`) で使えるが、Codex host default は Codex CLI。`codex-sidecar` は durable result / diagnostics / worktree / MCP boundary を持つ second-pass (`risk-check`, `review`, `explore`, `opinion`) と approved `work` workflow の基盤として残す
15
+ - **diagnostics / docs**: `spotter doctor` に Codex CLI / Codex hooks / `codex-sidecar` readiness を追加。README / README.ja / CLAUDE.md / contract docs / open issues / migration TODO を v1.4.0 の完成条件へ更新
16
+ - **packaging hardening**: npm publish 時に bin が消える罠を避けるため `package.json` の `bin.spotter` を `bin/spotter.mjs` に正規化。package-lock も `1.4.0` に更新。MCP initialize の `clientInfo.version` は `src/version.mjs` 由来にして package version drift を解消
17
+
18
+ ### 実測 / 検証
19
+
20
+ - `npm test`: 272 tests, 271 pass, 1 skip
21
+ - Codex native hook smoke: `UserPromptSubmit Completed` / `Stop Completed`
22
+ - Codex hook latency smoke: normal `UserPromptSubmit` 約 7.4s、short `Stop` skip 約 0.08s
23
+ - 4 象限 primary auditor matrix: `claude.codex-cli=10041ms`, `claude.codex-sidecar=12863ms`, `codex.codex-cli=10383ms`, `codex.codex-sidecar=13983ms`
24
+ - `spotter codex risk-check --host-agent codex`: durable `.spotter/sidecar-results/*-codex-risk-check.json` を保存
25
+ - `spotter codex work --dry-run --approve-work --allowed-path ... --remove-worktree --host-agent codex`: scoped work workflow success
26
+
27
+ ### ユーザー側で必要な手順
28
+
29
+ 1. `npm install -g claude-spotter@1.4.0` で global update
30
+ 2. Claude Code で使う各プロジェクトで `spotter install` を実行する。これは `.claude/settings.json` と `.spotter/marker.json` を作り、Claude catalog の初回 seed も実行する
31
+ 3. Codex native hooks を使う場合は一度だけ `spotter codex-hook install` を実行する。以後、Codex `SessionStart` が `.spotter/tool-db.codex.json` を自動 refresh する
32
+ 4. `spotter doctor` と `spotter codex-hook diagnostics` で global CLI / Codex hooks / tool-db 状態を確認できる
33
+
34
+ ## 1.3.0
35
+
36
+ **Haiku spawn 時に user/project の MCP server を一切 load しないよう強制 — WSL2 で観測された CPU 100% 飽和 + 孤児 `npm exec` プロセス累積 + チャット入力無反応 の根本原因を断った minor bump**。修正は `claude -p` 起動引数に `--strict-mcp-config --mcp-config <empty>` を必ず付けるだけの最小実装、副作用なし。
37
+
38
+ ### 観測した症状 (2026-05-04 WSL2 実環境)
39
+
40
+ WSL2 の CPU 使用率が 100% に張り付き、何かがプロセスを「無限増殖」させている — というユーザー報告から調査開始。`ps -eo pid,ppid,pcpu,etime,cmd --sort=-pcpu` の上位に **etime 3〜10 秒の `npm exec @modelcontextprotocol/server-*` / `@playwright/mcp` / `@upstash/context7-mcp` / `homework-mcp` / `caveat mcp` / `mcp-server-github` / `mcp-server-memory` 等が大量並走** し、親 PID は `claude -p --resume <uuid> --model claude-haiku-4-5-20251001` (= Spotter daemon の Haiku caller)。Spotter daemon が 3 並走、各々の Haiku 起動ごとに 60+ 個の MCP server を spawn → 終了 → 再 spawn のサイクルで CPU を食いつぶしていた。隣接プロジェクト ([Chime](file:///home/kite/projects/Chime)) で「VSCode 拡張のチャット入力が無反応」体感症状の真因も同根 (WSL2 全体の CPU 飽和で拡張側の入力処理がドロップ)。
41
+
42
+ ### 真因
43
+
44
+ `sanitizeHaikuEnv` (v1.1.6) は `CLAUDE_CONFIG_DIR` を strip して Haiku をデフォルト `~/.claude/` で起動するが、**デフォルト config dir には User scope MCP (`~/.claude.json` 直下 `mcpServers`) と plugin MCP がフルで登録されている**。claude CLI 2.1.x は `--print` モード起動時に config dir 内の全 MCP server を eager に spawn するため、Haiku 1 回呼出ごとに数十個の `npm exec` 子プロセスが立つ。Haiku は `{name, description}` カタログ監査しかしない (= MCP server は不要) のに、起動コストとして user/project の MCP がフル load されていた構造的欠陥。
45
+
46
+ 加えて `daemon-702a677d-...log` で同 sessionId の `tool-db loaded` が 15 分間に 8 回記録 = sudden death + auto-resurrect が高頻度発生していた。WSL2 cgroup OOM kill が daemon プロセスごと巻き込んでいた可能性が高く、[docs/open-issues.md](docs/open-issues.md) P0 「daemon プロセスが shutdown ログなしに死ぬ」 (v0.13.2 から残置) の主因もこれと推定。
47
+
48
+ ### 変更点
49
+
50
+ - **編集 [src/daemon/haiku-caller.mjs](src/daemon/haiku-caller.mjs)**:
51
+ - 定数 `EMPTY_MCP_CONFIG_PATH = ~/.spotter/workdir/empty-mcp.json` と `EMPTY_MCP_CONFIG_BODY = '{"mcpServers":{}}'` を追加
52
+ - `ensureWorkdir` を拡張し、空 MCP config ファイルを idempotent に書き出す
53
+ - 新 named export `emptyMcpConfigPath()` (テストから参照)
54
+ - `buildSpawnArgs({ ...args, mcpConfigPath })` のシグネチャを拡張、`mcpConfigPath` を必須化 (TypeError on missing/empty)、出力に `--strict-mcp-config --mcp-config <path>` を必ず含める。Windows `cmd.exe /c` 経路でも同様に
55
+ - `createHaikuCaller` 内 `spawn` 直前で `mcpConfigPath: EMPTY_MCP_CONFIG_PATH` を渡す
56
+ - **編集 [test/haiku-caller.test.mjs](test/haiku-caller.test.mjs)**: 回帰ガード 5 件追加 + 既存 `buildSpawnArgs` 2 件を新シグネチャに追従
57
+ - 新規: first call と resumed call の両方で `--strict-mcp-config` と `--mcp-config <path>` を含む
58
+ - 新規: `mcpConfigPath` 欠落 / 空文字 / null で TypeError
59
+ - 新規: `ensureWorkdir` で `empty-mcp.json` が `{"mcpServers":{}}` で書かれる
60
+ - 新規: `ensureWorkdir` の idempotent 性 (3 連呼出で破綻しない)
61
+ - **編集 [src/cli/install.mjs](src/cli/install.mjs)**: `HOOK_EVENTS` の Stop/UserPromptSubmit timeout を 15s/30s から **60s に統一**。v0.13.1 で daemon 側 Haiku timeout を 30s→45s に緩和したのに settings.json に書く Claude Code 本体側の hook timeout が旧値のままで、Chime 等の preamble が大きい (93 KB / 357 件) 環境で daemon が 24-32s かけて正常応答を返している最中に Claude Code 側 hook が timeout kill されて「チャット入力無反応」を誘発していた既存バグの hot-fix。`docs/open-issues.md` の P0「install.mjs の hook timeout が v0.13.1 緩和を反映していない」項目を closing
62
+ - **package.json**: `1.2.6` → `1.3.0` (公開 API シグネチャ変更 = `buildSpawnArgs` の新引数を伴うため minor bump)
63
+ - **編集 [docs/open-issues.md](docs/open-issues.md)**: 解決済みリストに 2 件追加、P0「daemon が shutdown ログなしに死ぬ」節に v1.3.0 で根因が大半解消した可能性を追記
64
+
65
+ ### なぜ `--strict-mcp-config --mcp-config <empty>` が正解か
66
+
67
+ - **Anthropic auth は影響なし** — credentials は `~/.claude/.credentials.json` 等から従来どおり読まれる (`--bare` を使うと keychain skip で OAuth が壊れるが、`--strict-mcp-config` は MCP config を制限するだけで auth とは独立)
68
+ - **副作用ゼロ** — Haiku は `{name, description}` カタログ監査しか必要としない、MCP server を呼ばない。Spotter のカタログ収集 (`investigate-mcp.mjs`) は別経路 (`claude mcp list` + `.mcp.json` 直読み) で行うので Haiku 側に MCP は要らない
69
+ - **クロスプラットフォーム** — `--strict-mcp-config --mcp-config <path>` は Linux/macOS/Windows 全てで動作、`--mcp-config` は v0.x 時代から claude CLI に存在
70
+ - **既存の v1.1.6 `sanitizeHaikuEnv` と直交** — Bell の isolated `CLAUDE_CONFIG_DIR` 継承防止 (auth 失敗回避) は引き続き必要、本修正は MCP load 防止という別軸で重ねがけ
71
+
72
+ ### Chime / Spotter ユーザー側で必要な手順
73
+
74
+ 1. `npm install -g claude-spotter@1.3.0` で global update
75
+ 2. Haiku spawn の MCP-disable は次の SessionStart から自動的に新コードが効く
76
+ 3. 既 install プロジェクトでも `spotter install` を再実行して、`.claude/settings.json` の UserPromptSubmit / Stop hook timeout を 60s に更新する (旧 settings の 15s/30s は global update だけでは書き換わらない)
77
+ 4. 既存の孤児 daemon があれば `kill <pid>` + `rm ~/.spotter/runtime/session-*.pid` で掃除 (今後は v1.3.0 の MCP-disable で sudden death 自体が大幅減少見込み)
78
+
79
+ ## 1.2.6
80
+
81
+ **チャット入力が無視される実害バグの根治**。実プロジェクト ([Chime](file:///home/kite/projects/Chime)) のセッションで Spotter daemon が UserPromptSubmit / Stop hook を Haiku 呼び出しで何度も `E_INTERNAL: haiku exited with code 1` させ、Claude Code 側 hook timeout (30s) に貼り付いて入力が応答しない状態が頻発していた。原因は Haiku を起動する `claude -p` への stdin 引き渡し方式と、claude CLI 2.1.x の stdin 取扱いの仕様の組合せで、推測ではなく実プロジェクト同条件 (`tools=357 件 / preamble=93 KB`) の最小再現で確定した。
82
+
83
+ ### 観測された stderr
84
+
85
+ ```
86
+ Warning: no stdin data received in 3s, proceeding without it.
87
+ If piping from a slow command, redirect stdin explicitly: < /dev/null to skip, or wait longer.
88
+ Error: Input must be provided either through stdin or as a prompt argument when using --print
89
+ ```
90
+
91
+ ### 真因 (推測ではなく実測で確定)
92
+
93
+ claude CLI 2.1.126 は `--print` モードで stdin の最初の read attempt が **約 3 秒** 以内に readable にならないと「stdin 無し」と判定して引数モードに切替えようとし、prompt が無いので exit 1 する。一方 Spotter は v0.7.0 の tool-db 化で preamble (role + schema + few-shot + 全カタログの JSON) を初回 1 回送信しているが、Chime のように `MCP × スキル × サブエージェント = 357 件` ある環境では preamble が **93 KB** 程度に達する。Linux の kernel pipe buffer (デフォルト 64 KB) を超えるため、Node 側 `child.stdin.end(buf)` の write が drain 待ちになり、claude CLI が起動 (auth + config + plugin 探索) を 3 秒以内に終えて最初の read syscall を発行しないと「3 秒間 no stdin data」と CLI 側で判定 → stdin 放棄 → exit 1。CLI は "Warning" を出して続行するふりをするが、実際は `--print` 引数も無いので "Input must be provided" で死ぬ。
94
+
95
+ 実測 (2026-05-04, /home/kite/projects/Chime での Spotter セッション + WORKDIR 隔離環境):
96
+
97
+ | stdin 経路 | duration | exit code | stderr |
98
+ |---|---|---|---|
99
+ | `child.stdin.end(prompt)` (pipe) | 17 秒 | 1 | "no stdin data received in 3s" + "Input must be provided" |
100
+ | **tempfile fd を `stdio[0]` に渡す (本修正)** | **24-32 秒** | **0** | (空) — 正常 JSON 応答 |
101
+
102
+ このバグの可視結果は、daemon log の以下メッセージが繰り返し出る現象として観測されていた:
103
+ - `user_input: haiku invocation failed (E_INTERNAL), rotating session before rethrow: haiku exited with code 1: Warning: no stdin data received in 3s ...`
104
+ - 当該 turn は session を rotate して `mode=first` の cold-start に逆戻り (preamble 再送 → ますます重い) → 30s hook timeout に貼り付き → ユーザー視点で「チャット入力が無視される」
105
+
106
+ ### 変更点
107
+
108
+ - **編集 [src/daemon/haiku-caller.mjs](src/daemon/haiku-caller.mjs)**: 新規 `preparePromptFile(wirePrompt)` を named export として追加。`os.tmpdir()` 配下にユニーク tempfile (`spotter-prompt-<pid>-<uuid>.txt`) を作って prompt を書き込み、read-only fd と `close()` ハンドラ (fd close + unlink、両方 best-effort) を返す。`createHaikuCaller` 内 `callHaiku` の `spawn` を `stdio: ['pipe', 'pipe', 'pipe']` + `child.stdin.end(prompt)` から `stdio: [promptFile.fd, 'pipe', 'pipe']` に切替え (child.stdin が null になるので関連 noop listener も削除)。close / error / timeout の各 settle 経路で `promptFile.close()` を呼んでから resolve/reject する `settleAfterCleanup` ヘルパで cleanup を一元化、tempfile leak を防止
109
+ - **編集 [test/haiku-caller.test.mjs](test/haiku-caller.test.mjs)**: 回帰ガード 6 件追加 — (1) tempfile が書かれて読める (2) 100 KB (= pipe buffer 超え) でも全 byte 届く (3) `close()` で unlink される (4) `close()` 二重呼び出し可 (timeout-vs-close race の安全性) (5) 非 string 入力で `TypeError` (6) 並列呼び出しで tmpPath が衝突しない (UUID 保証)
110
+ - **package.json**: `1.2.5` → `1.2.6`
111
+
112
+ ### なぜ tempfile fd 方式が正解か
113
+
114
+ - **file は kernel が即時 readable と判定** — pipe と違い「writer 側の進捗」を待たないので、CLI 起動が遅くても 3 秒タイマーに引っかからない
115
+ - **pipe buffer の制約から完全に独立** — 64 KB / 1 MB / 10 MB どんな payload でも file 経由なら一発で届く
116
+ - **クロスプラットフォーム** — Windows でも `os.tmpdir()` は機能、`stdio[0]` への numeric fd 受け渡しも Node が抽象化済み
117
+ - **CLI 引数モード (`-p "<prompt>"`) と違い ARG_MAX に縛られない** — Windows の CommandLineW 32K 制限を回避
118
+
119
+ ### Chime で「無反応」が消えるまでに必要な手順 (ユーザー側)
120
+
121
+ 1. `npm install -g claude-spotter@1.2.6` で global update
122
+ 2. Chime 側の既 install プロジェクトでは hook 設定 (`~/.claude.json` の per-project hooks) は変わらない (`spotter.mjs` のパスは固定) ので **再 install 不要**、次の SessionStart から自動的に新コードが効く
123
+ 3. 既存の孤児 daemon があれば `rm ~/.spotter/runtime/session-*.pid` で掃除 (生存 daemon 0 件確認後のみ)
124
+
3
125
  ## 1.2.5
4
126
 
5
127
  **ECC プラグイン経由の MCP サーバー 6 件 (context7 / exa / github / memory / playwright / sequential-thinking) のツール群 (61 件) が Spotter のカタログから silent に欠落していた **二重構造バグ**を修正**。実プロジェクト (Web) で `spotter install` 実行時のログに ``mcp investigate failed for "plugin": Command failed: cmd.exe /c claude mcp get plugin`` が **6 連発** で出ていたのを契機に発見。これらのプラグイン MCP の呼び忘れを Spotter が検出できない状態だった (Web プロジェクトで rebuild すると 309 → 370 件、プラグイン由来 61 件が追加されることを確認)。
package/README.ja.md CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  > **気づく役と実行する役を分離する。** Claude Code の横で並走し、Bell (主役の Claude) が**ツールを呼び忘れたとき**だけ静かに指摘する監査役。
15
15
 
16
- Claude には「使えるツールがあるのに、使うべきタイミングで使わない」という構造的な弱点があります。現在時刻を推測で答える、`web_search` を呼ばずに古い情報で応答する、`read_file` を使わずにファイルの中身を推測する — **「分からないと自覚できない」から、ツールを取りに行けない**。
16
+ Claude には「使えるツールがあるのに、使うべきタイミングで使わない」という構造的な弱点があります。記録すべき決定を memory / caveat MCP に残さない、docs lookup MCP を呼ばずに古い知識で応答する、ブラウザ自動化 MCP で確認せず UI 状態を推測する — **「分からないと自覚できない」から、ツールを取りに行けない**。
17
17
 
18
18
  Spotter はツールカタログを完全に把握した別エージェント (Claude Haiku 4.5) をセッション毎に常駐させ、Bell の発話予定と応答を並走監査します。見落としを検出すると透明化された指摘として Bell に届け、補正応答を促します。**Bell が自覚して呼ぶ**設計は本プロダクトの存在意義を破壊するため、Bell から呼ぶのではなく hook 経由で Bell の意思と独立に検出する構造を取っています。
19
19
 
@@ -23,14 +23,16 @@ Spotter が拾うのは、たとえばこういう瞬間です。
23
23
 
24
24
  | 状況 | Bell の応答 | Spotter の指摘 |
25
25
  |---|---|---|
26
- | 「今日の天気を教えて」 | 推測で答えようとする | `web_search` の使用機会 |
27
- | 「この設定ファイルの中身は?」 | 名前から推測で説明 | `read_file` の使用機会 |
28
- | 「今何時?」 | 学習時点の情報で答える | `current_time` の使用機会 |
26
+ | 「この OAuth の落とし穴を覚えて」 | 了解だけして進める | memory / caveat MCP の使用機会 |
27
+ | 「このパッケージの最新版 API は?」 | 学習時点の知識で答える | docs lookup MCP の照会機会 |
28
+ | 「この危ない patch をレビューして」 | 自分だけで見直す | reviewer sub-agent の使用機会 |
29
29
  | 事実の断定 | 裏付けなしで「〜です」 | 検証用ツールの差し込み余地 |
30
+ | 「この UI 今もちゃんと動く?」 | コード読みだけで結論 | ブラウザ自動化 MCP の使用機会 |
31
+ | 「以前何を決めたっけ?」 | 推測 / 失念のまま回答 | メモリ / ノート系 MCP の照会機会 |
30
32
 
31
33
  判定軸は 2 段階:
32
34
 
33
- - **入力時 (`stage=user_input`)**: ユーザー要請に対し、`when_to_use` の条件に明確に該当するツールを列挙する **要請充足チェック**
35
+ - **入力時 (`stage=user_input`)**: ユーザー要請に対し、ローカルカタログの description から用途が明確に該当するツールを列挙する **要請充足チェック**
34
36
  - **応答後 (`stage=turn_end`)**: Bell の最終応答に対し、事実の断定 / 記録すべき新情報 / 既知情報の参照それぞれに、カタログ上のツール (検証 / 登録 / 照会) を差し込める余地がないかを問う **ツール適用機会の監査**
35
37
 
36
38
  ## インストール
@@ -39,9 +41,14 @@ Spotter が拾うのは、たとえばこういう瞬間です。
39
41
  npm install -g claude-spotter
40
42
  cd your-project
41
43
  spotter install
44
+ # 任意: Codex native hooks を使う場合
45
+ spotter codex-hook install
42
46
  ```
43
47
 
44
48
  `v0.3.0` 以降は**プロジェクト単位の明示的 install** を採用しています (v0.2 までの `postinstall` 自動登録はデーモン増殖の主因だったため撤回)。各プロジェクトの `.claude/settings.json` に hook を登録し、そのプロジェクトでの Claude Code セッションのみで有効になります。
49
+ Codex 対応は `spotter codex-hook install` で別途有効化します。Codex hook は user-level に登録されますが、実際に動くプロジェクトは `spotter install` が作る `.spotter/marker.json` で制限されます。
50
+
51
+ Spotter を upgrade した後、release note で hook 設定変更が案内されている場合は、各 install 済みプロジェクトで `spotter install` を再実行してください。global package update でコード経路は変わりますが、既存 `.claude/settings.json` の timeout 値は自動では書き換わりません。
45
52
 
46
53
  ```bash
47
54
  spotter uninstall # このプロジェクトの hook 登録を解除
@@ -51,27 +58,54 @@ spotter uninstall # このプロジェクトの hook 登録を解除
51
58
 
52
59
  - **Node.js 22.5 以上**
53
60
  - **Claude Code 2.0 以上**
54
- - **Claude Max プラン** (`claude -p` で Haiku を起動するため)
61
+ - **現行 Claude-backed auditor path では Claude Max プラン** (`claude -p` で Haiku を起動するため)
62
+ - **Codex native hooks では Codex CLI**。Codex host の監査は既定で `codex exec` を使い、Haiku へ fallback しません
55
63
 
56
64
  ## アーキテクチャ
57
65
 
66
+ ### 1 ターンの監査フロー
67
+
68
+ ```mermaid
69
+ flowchart TD
70
+ U([User 発話]) --> UPH[UserPromptSubmit hook<br/>Spotter が発話とカタログから一次判定]
71
+ UPH --> BT[Bell Thinking<br/>Spotter の推奨を<br/>additionalContext で受信]
72
+ BT --> BA([Bell の最初の応答])
73
+ BA --> SH[Stop hook<br/>応答と使用済みツールから最終チェック]
74
+ SH --> DEC{見落とし<br/>あり?}
75
+ DEC -->|なし| DONE([完了])
76
+ DEC -->|あり| SB[差し戻し<br/>max 1 回<br/>stop_hook_active で自動担保]
77
+ SB --> BA2([Bell の補正応答]) --> DONE
58
78
  ```
59
- User 発話
60
-
61
- UserPromptSubmit hook → Spotter がカタログと発話を見て一次判定
62
-
63
- Bell Thinking (Spotter の推奨を additionalContext で受け取る)
64
-
65
- Bell 最終応答
66
-
67
- Stop hook → Spotter が応答と使用済みツールを見て最終チェック
68
-
69
- 見落としあれば差し戻し (max 1 回、Claude Code の stop_hook_active で自動担保)
79
+
80
+ ### カタログの収集経路
81
+
82
+ ```mermaid
83
+ flowchart LR
84
+ subgraph SRC[収集ソース]
85
+ direction TB
86
+ MCP[MCP サーバー<br/>claude mcp list で列挙]
87
+ SK[スキル<br/>SKILL.md frontmatter]
88
+ AG[サブエージェント<br/>agent .md frontmatter]
89
+ BL[claude.ai baseline<br/>Gmail / Calendar / Drive<br/>存在時のみ注入]
90
+ end
91
+ subgraph SCOPES["MCP の env / headers — 4 スコープ、上位が衝突に勝つ"]
92
+ direction TB
93
+ L["Local — projects.&lt;root&gt;.mcpServers in ~/.claude.json"]
94
+ P["Project — &lt;root&gt;/.mcp.json"]
95
+ US["User — mcpServers in ~/.claude.json"]
96
+ LG["Legacy — ~/.claude/.mcp.json"]
97
+ end
98
+ SCOPES -. merge .-> MCP
99
+ MCP --> DB[(ホスト別ローカル tool-db<br/>name + description<br/>プロジェクト単位)]
100
+ SK --> DB
101
+ AG --> DB
102
+ BL --> DB
103
+ DB --> H[Haiku 監査<br/>session-scoped, preamble-once]
70
104
  ```
71
105
 
72
- 監査対象のツール (name + description) は `<project>/.spotter/tool-db.json` (ローカル) に格納されます。**daemon が監査に使うのはローカル DB のみ** (v1.2.0 以降) で、グローバル DB `~/.spotter/tool-db.json` は他プロジェクトでの description 再利用キャッシュとしてのみ機能します (live fetch コスト削減のため初回 refresh で参照、結果は local に write-through)。各プロジェクトの local DB は **そのプロジェクトの現時点の discovery 結果と一致** (refresh 時に prune される) ため、過去にインストールしていた MCP / スキル / サブエージェントが他プロジェクトに混入することはありません。
106
+ 監査対象のツール (name + description) は host-local に分離されます。Claude は `<project>/.spotter/tool-db.json`、Codex は `<project>/.spotter/tool-db.codex.json` を使います。**daemon が監査に使うのは Claude local DB のみ**で、Codex native hooks Codex local DB を読みます。グローバル DB `~/.spotter/tool-db.json` は他プロジェクトでの description 再利用キャッシュとしてのみ機能し、監査入力には混ぜません。各 host-local DB は **その host の現時点の discovery 結果と一致** (refresh 時に prune される) するため、別プロジェクトや別 host のツールリストで上書きされることはありません。
73
107
 
74
- **v1.1.0 以降、`spotter install` が初回 seed を自動実行し、Claude Code セッション起動ごとに SessionStart hook が bg で `spotter db refresh` を走らせる**ため、通常の運用で手動コマンドを叩く必要はありません。収集経路は (1) MCP サーバー: `claude mcp list` で集合を確定し、env / headers Claude Code 公式 3 スコープ User (`~/.claude.json` 直下 `mcpServers`) / Project (`<projectRoot>/.mcp.json`) / Local (`~/.claude.json` `projects[<root>].mcpServers`) precedence Local > Project > User merge して取得 (v1.2.1 以降、互換のため legacy `~/.claude/.mcp.json` も最下位で参照)、各サーバーの `tools/list` JSON-RPC で取得、HTTP/SSE transport にも対応、(2) スキル: user/project/プラグインの SKILL.md frontmatter から `{name, description}` を抽出、(3) サブエージェント: user/project/プラグインの agent .md frontmatter から抽出、(4) claude.ai baseline: OAuth proxy 経由の Gmail/Calendar/Drive 25 件は手書き baseline で補完 (v1.1.4 以降、`claude mcp list` に該当サーバーが存在する環境でのみ注入)。**手書きでツールリストを管理する必要はありません**。
108
+ **`spotter install` Claude catalog の初回 seed を自動実行し、Claude Code セッション起動ごとに SessionStart hook が bg で `spotter db refresh` を走らせる**ため、Claude 通常運用で手動コマンドを叩く必要はありません。Codex native hooks も同じ考え方で、`spotter codex-hook install` Codex `SessionStart` hook を登録し、Codex セッション開始時に `spotter db refresh --host-agent codex` bg 起動して `.spotter/tool-db.codex.json` を更新します。Claude catalog には書き込みません。Claude discovery は `claude mcp list` Claude skills / sub-agents、Codex discovery `codex mcp list/get` Codex skills を読むため、両 host の利用可能ツール差分を別 DB として保持できます。各 MCP サーバーの `tools/list` JSON-RPC で取得 (HTTP / SSE / stdio transport 対応)、スキルとサブエージェントは frontmatter から直接抽出、claude.ai baseline (OAuth proxy 経由の Gmail / Calendar / Drive 25 件) Claude 側でのみ `claude mcp list` に該当サーバーが存在する環境で注入されます。**手書きでツールリストを管理する必要はありません**。
75
109
 
76
110
  ## Throughline との関係
77
111
 
@@ -88,19 +122,54 @@ Stop hook → Spotter が応答と使用済みツールを見て最終チェッ
88
122
  ## よく使うコマンド
89
123
 
90
124
  ```bash
91
- spotter db list # 現在のローカル tool-db (daemon が実際に audit に使う) を表示
92
- spotter db refresh # MCP / スキル / サブエージェントから description を収集して DB 更新
93
- # (v1.1.0 以降、install 時と SessionStart 時に自動実行されるので通常は不要)
94
- spotter db rebuild # local + global DB を両方消してから refresh (カタログ設計変更時のクリーン用)
125
+ spotter db list # 現在の Claude local tool-db を表示
126
+ spotter db list --host-agent codex
127
+ # 現在の Codex local tool-db を表示
128
+ spotter db refresh # Claude MCP / スキル / サブエージェントから description を収集して Claude DB 更新
129
+ spotter db refresh --host-agent codex
130
+ # Codex MCP / スキルから description を収集して .spotter/tool-db.codex.json を更新
131
+ # (Claude は install + Claude SessionStart、Codex は codex-hook install 後の
132
+ # Codex SessionStart で自動実行されるので通常は不要)
133
+ spotter db rebuild # Claude local + global DB を両方消してから refresh (カタログ設計変更時のクリーン用)
95
134
  spotter status # 稼働中の daemon 一覧
96
- spotter doctor # 環境診断 (Node / claude CLI / tool-db 整合性)
135
+ spotter doctor # 環境診断 (Node / claude CLI / Codex readiness / tool-db 整合性)
136
+ spotter diagnostics logs # daemon log から pass=false / backend latency / anomaly signal を集計
137
+ spotter codex risk-check --findings findings.json --host-agent claude
138
+ # Spotter finding を codex-sidecar に渡して read-only risk analysis
139
+ spotter codex review|explore|opinion --findings findings.json --host-agent claude
140
+ # その他の read-only codex-sidecar second-pass workflow
141
+ spotter codex work --findings findings.json --instruction "docs 更新" --approve-work \
142
+ --allowed-path docs/ --preserve-worktree
143
+ # 承認済み codex-sidecar work を isolated worktree で実行
144
+ spotter codex-hook install
145
+ # Codex native SessionStart / UserPromptSubmit / Stop hook を登録
146
+ spotter codex-hook diagnostics
147
+ # Codex hooks feature と Spotter hook 登録を診断
97
148
  spotter uninstall # hook 登録を解除 (~/.spotter は残す)
98
149
  ```
99
150
 
151
+ Codex risk dispatch を daemon から非同期に流す場合:
152
+
153
+ ```bash
154
+ SPOTTER_CODEX_RISK_CHECK=1 spotter daemon start --session-id ... --project-root ...
155
+ ```
156
+
157
+ 有効時は daemon が `pass:false` finding を detached process の
158
+ `spotter codex risk-check` に渡します。hook 応答は Codex を待ちません。
159
+ 配線だけ確認する場合は `SPOTTER_CODEX_RISK_CHECK_DRY_RUN=1` を併用します。
160
+
161
+ Primary auditor backend policy: Claude hooks は現行の Haiku compatibility path を既定のまま維持します。
162
+ Codex native hooks は Codex CLI を既定 backend とし、Haiku へ fallback しません。
163
+ Codex 側の SessionStart hook は `.spotter/tool-db.codex.json` を bg refresh し、Claude DB には触れません。
164
+ 明示 smoke には `SPOTTER_AUDITOR_BACKEND=codex-sidecar` も使えます。
165
+
100
166
  ## 設計ドキュメント
101
167
 
102
168
  - **現行設計 (カタログ / 収集経路 / 分類軸)**: [docs/catalog-design.md](docs/catalog-design.md) — v1.0.0 以降の真実源
103
169
  - **現時点で塞がっていない穴 + 実測未検証の懸念**: [docs/open-issues.md](docs/open-issues.md) — 新規作業に入る前に必読
170
+ - **Claude contract capture**: [docs/SPOTTER_CLAUDE_CONTRACT.md](docs/SPOTTER_CLAUDE_CONTRACT.md) — Codex 作業で維持すべき hook / daemon / Haiku の現行契約
171
+ - **Claude / Codex 両対応ブリーフ**: [docs/SPOTTER_CODEX_DUAL_SUPPORT.md](docs/SPOTTER_CODEX_DUAL_SUPPORT.md) と完了済み [TODO](docs/SPOTTER_CODEX_DUAL_SUPPORT_TODO.md) — second-pass `codex-sidecar` workflow
172
+ - **Primary auditor backend migration**: [docs/SPOTTER_PRIMARY_BACKEND_TODO.md](docs/SPOTTER_PRIMARY_BACKEND_TODO.md) — Codex CLI / `codex-sidecar` auditor backend の rollout 状況
104
173
  - **実装規範と不変条件 (§0)**: [CLAUDE.md](CLAUDE.md) — フォールバック禁止 / silent fallback 禁止 / 暫定コード禁止
105
174
  - **歴史記録 (v0.1 時点の設計議事録)**: [docs/spotter-plan.md](docs/spotter-plan.md) — 作成時点で固定された議論過程のスナップショット、現行設計は上記 3 点を参照
106
175
 
@@ -110,11 +179,16 @@ spotter uninstall # hook 登録を解除 (~/.spotter は残す)
110
179
  - **JSON スキーマ違反は v0.5.0 以降「想定済み異常」として silent pass + session renew で回復**します (role collapse 検知パス、daemon ログに `role_collapse_reset` を残す)。一方 **Haiku timeout は引き続き throw** され、UserPromptSubmit がブロックされてユーザー入力が Bell に届かない症状として顕在化します (timeout は v0.5.0 で 30s、v0.13.1 で 45s に拡張)。timeout の fail-open 化 (pass 扱い) は §0 改訂とセットで今後検討
111
180
 
112
181
  <details>
113
- <summary><strong>📋 v1.2.0 リリースノート (2026-04-26)</strong></summary>
182
+ <summary><strong>📋 最近のハイライト</strong></summary>
114
183
 
115
- **当該プロジェクトで使えないツールが提案される回帰を構造的に修正**。daemon が監査に使うカタログを**ローカル DB のみ**に変更し、グローバル DB は他プロジェクトでの description 再利用キャッシュに役割を限定。`resolveAll` 末尾に prune ループ追加で、現プロジェクトの discovery 結果に含まれない既存ローカルエントリを削除 (= 過去の別プロジェクトで discover された MCP / スキル / サブエージェントが居座る経路を遮断)。既 install プロジェクトは npm global update 後、次の SessionStart で自動 refresh が走り、次の次のセッションから幽霊が消える (即時反映は `spotter db refresh` 手動)。v1.1.0 からの柱 (install 時 tool-db 自動構築 + SessionStart での drift 自動追従) は継続。監査対象は v1.0.0 でユーザー追加分 (MCP / スキル / サブエージェント) に絞り込み済み。
184
+ - **プラグイン形式の MCP サーバー対応** `plugin:everything-claude-code:context7` のように名前に内部コロンを含むサーバーを正しくパースし、配下のツールをカタログに取り込めるようになった (旧版はこの形式のサーバーをすべて単一の `"plugin"` に潰して、Bell の監査から silent に脱落させていた)
185
+ - **プロジェクト単位の監査隔離** — daemon が監査に使うのはローカル DB のみ。グローバル DB は description 再利用キャッシュに役割限定。**他プロジェクト**でインストールしたツールが現プロジェクトの監査に混入することはない
186
+ - **手放しでカタログ維持** — `spotter install` が Claude DB を自動 seed、Claude / Codex それぞれの SessionStart が host-local DB を bg refresh する。手書き管理は一切不要
187
+ - **Codex native hooks** — Codex host は primary auditor backend として Codex CLI を使い、`.spotter/tool-db.codex.json` を Claude DB と分離し、backend failure は Haiku fallback ではなく明示 error として扱う
188
+ - **監査対象** — ユーザー追加分 (MCP / スキル / サブエージェント) のみ。Claude Code 本体側のツールは意図的に対象外 (Bell は元から自発率が高いため)
189
+ - **実装規範** — フォールバック禁止 / silent fallback 禁止 / 暫定コード禁止 ([CLAUDE.md §0](CLAUDE.md))
116
190
 
117
- 詳細は [CHANGELOG](CHANGELOG.md) を参照。
191
+ リリース履歴の全文は [CHANGELOG](CHANGELOG.md) を参照。
118
192
 
119
193
  </details>
120
194
 
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  > **Separate the spotter from the doer.** Spotter runs alongside Claude Code and quietly flags the moments when Bell (your primary Claude) **forgets to use a tool it has access to**.
15
15
 
16
- Claude has a structural blind spot: **it can't reach for a tool it doesn't realize it needs**. It will guess the current time instead of calling `current_time`, answer with stale knowledge instead of `web_search`, describe a config file from its name instead of `read_file`. The model can't always tell when it doesn't know — so the tool stays unused.
16
+ Claude has a structural blind spot: **it can't reach for a tool it doesn't realize it needs**. It may skip a project memory MCP when a decision should be recorded, answer from stale memory instead of a docs-lookup MCP, or reason about UI state without a browser-automation MCP. The model can't always tell when it doesn't know — so the tool stays unused.
17
17
 
18
18
  Spotter pins a second agent (Claude Haiku 4.5) next to Bell. The second agent has the full tool catalog memorized and audits both the user's prompt and Bell's reply in parallel. When it spots a missed tool, it injects a transparent recommendation into Bell's context and, if needed, asks Bell to amend its answer. **Bell is never asked to self-audit** — that would defeat the entire premise. Detection happens through hooks, independent of Bell's intent.
19
19
 
@@ -23,14 +23,16 @@ Examples of what Spotter catches:
23
23
 
24
24
  | Situation | What Bell would do | What Spotter flags |
25
25
  |---|---|---|
26
- | "What's the weather today?" | Guess from training data | Missed call to `web_search` |
27
- | "What's in this config file?" | Describe based on the filename | Missed call to `read_file` |
28
- | "What time is it?" | Answer from training-time knowledge | Missed call to `current_time` |
29
- | Asserting a fact | Stating it without verification | Opportunity to call a verification tool |
26
+ | "Please remember this OAuth gotcha" | Acknowledge and move on | Missed call to a memory / caveat MCP |
27
+ | "How does this package API work in the latest version?" | Answer from training-time knowledge | Missed call to a docs-lookup MCP |
28
+ | "Review this risky patch" | Self-review only | Missed call to a reviewer sub-agent |
29
+ | Asserting a fact | State it without verification | Opportunity to call a verification tool |
30
+ | "Does this UI still render correctly?" | Reason from source code alone | Missed call to a browser-automation MCP |
31
+ | "What did we decide about X earlier?" | Guess or admit forgetting | Missed call to a memory / notes MCP |
30
32
 
31
33
  Spotter audits in two stages:
32
34
 
33
- - **`stage=user_input`** — given the user's prompt, list any tools whose `when_to_use` clearly applies. A *prompt-fulfillment* check
35
+ - **`stage=user_input`** — given the user's prompt, list any local catalog tools whose description clearly applies. A *prompt-fulfillment* check
34
36
  - **`stage=turn_end`** — given Bell's final reply, look for places where a catalog tool (verification / recording / lookup) could plug in. A *missed-opportunity* audit. Zero findings is fine; tools already used in this turn are not re-flagged
35
37
 
36
38
  ## Install
@@ -39,9 +41,14 @@ Spotter audits in two stages:
39
41
  npm install -g claude-spotter
40
42
  cd your-project
41
43
  spotter install
44
+ # Optional, for Codex native hooks:
45
+ spotter codex-hook install
42
46
  ```
43
47
 
44
48
  Since `v0.3.0`, Spotter requires **explicit per-project install** (the earlier `postinstall` auto-registration was the leading cause of orphan daemons). `spotter install` writes hooks into the project's `.claude/settings.json`; the audit is then active only in Claude Code sessions for that project.
49
+ Codex support is enabled separately by `spotter codex-hook install`, which writes user-level Codex hooks; project activation still depends on the same per-project `.spotter/marker.json` created by `spotter install`.
50
+
51
+ After upgrading Spotter, re-run `spotter install` in each installed project when release notes mention hook setting changes. The global package update changes the code path, but existing `.claude/settings.json` timeout values are not rewritten automatically.
45
52
 
46
53
  ```bash
47
54
  spotter uninstall # remove hooks from this project
@@ -51,27 +58,54 @@ spotter uninstall # remove hooks from this project
51
58
 
52
59
  - **Node.js 22.5+**
53
60
  - **Claude Code 2.0+**
54
- - **Claude Max plan** (Spotter spawns Haiku via `claude -p`)
61
+ - **Claude Max plan** for the current Claude-backed auditor path (Spotter spawns Haiku via `claude -p`)
62
+ - **Codex CLI** for Codex native hooks. Codex host auditing uses `codex exec` by default and does not fall back to Haiku
55
63
 
56
64
  ## Architecture
57
65
 
66
+ ### Audit flow per turn
67
+
68
+ ```mermaid
69
+ flowchart TD
70
+ U([User prompt]) --> UPH[UserPromptSubmit hook<br/>Spotter audits prompt against catalog]
71
+ UPH --> BT[Bell thinking<br/>receives Spotter's recommendations<br/>as additionalContext]
72
+ BT --> BA([Bell's first answer])
73
+ BA --> SH[Stop hook<br/>Spotter re-audits answer + tools used]
74
+ SH --> DEC{Missed<br/>tool?}
75
+ DEC -->|No| DONE([Done])
76
+ DEC -->|Yes| SB[Send-back to Bell<br/>max 1 round<br/>guarded by stop_hook_active]
77
+ SB --> BA2([Bell's amended answer]) --> DONE
58
78
  ```
59
- User prompt
60
-
61
- UserPromptSubmit hook → Spotter does a first pass against the catalog
62
-
63
- Bell thinking (receives Spotter's recommendations as additionalContext)
64
-
65
- Bell's final answer
66
-
67
- Stop hook → Spotter re-audits the answer + tools actually used
68
-
69
- If something was missed: send-back (max 1 round, guaranteed by Claude Code's stop_hook_active)
79
+
80
+ ### Catalog discovery
81
+
82
+ ```mermaid
83
+ flowchart LR
84
+ subgraph SRC[Discovery sources]
85
+ direction TB
86
+ MCP[MCP servers<br/>via claude mcp list]
87
+ SK[Skills<br/>SKILL.md frontmatter]
88
+ AG[Sub-agents<br/>agent .md frontmatter]
89
+ BL[claude.ai baseline<br/>Gmail / Calendar / Drive<br/>injected when present]
90
+ end
91
+ subgraph SCOPES["MCP env / headers — 4 scopes, top wins on collision"]
92
+ direction TB
93
+ L["Local — projects.&lt;root&gt;.mcpServers in ~/.claude.json"]
94
+ P["Project — &lt;root&gt;/.mcp.json"]
95
+ US["User — mcpServers in ~/.claude.json"]
96
+ LG["Legacy — ~/.claude/.mcp.json"]
97
+ end
98
+ SCOPES -. merged into .-> MCP
99
+ MCP --> DB[(Host-local tool-db<br/>name + description<br/>per project)]
100
+ SK --> DB
101
+ AG --> DB
102
+ BL --> DB
103
+ DB --> H[Haiku audit<br/>session-scoped, preamble-once]
70
104
  ```
71
105
 
72
- The audited tool catalog (name + description) lives in `<project>/.spotter/tool-db.json`. **Since v1.2.0 the daemon audits against the local DB only**; the global DB at `~/.spotter/tool-db.json` is a description-reuse cache shared across projects, not an audit source. Each project's local DB always matches the **current** discovery snapshot for that project (entries are pruned on refresh), so MCP servers, skills, or sub-agents installed in *other* projects can never bleed into this project's audit.
106
+ The audited catalog is host-local: Claude uses `<project>/.spotter/tool-db.json`, while Codex uses `<project>/.spotter/tool-db.codex.json`. **The daemon audits against the Claude local DB only**, and Codex native hooks read the Codex local DB. The global DB at `~/.spotter/tool-db.json` is a description-reuse cache shared across projects, not an audit source. Each host-local DB matches that host's **current** discovery snapshot for the project (stale entries are pruned on refresh), so tools from another project or another host cannot overwrite this session's audit catalog.
73
107
 
74
- **Since v1.1.0, `spotter install` runs the initial seed automatically, and the SessionStart hook triggers a background `spotter db refresh` on every Claude Code session start** — so you don't need to invoke catalog commands by hand. The discovery sources are: (1) **MCP servers** enumerated from `claude mcp list` (membership) and merged with all three official Claude Code scopes for env / headers: User (`~/.claude.json` direct `mcpServers`) / Project (`<projectRoot>/.mcp.json`) / Local (`~/.claude.json` `projects[<root>].mcpServers`), with precedence Local > Project > User (v1.2.1+); a legacy `~/.claude/.mcp.json` source is also read at the lowest priority for backward compatibility. Each server's `tools/list` is fetched via JSON-RPC (HTTP/SSE transport supported); (2) **skills** — `{name, description}` extracted from SKILL.md frontmatter at user / project / plugin scope; (3) **sub-agents** same pattern from agent `.md` frontmatter; (4) **claude.ai baseline** Gmail / Calendar / Drive (25 entries via OAuth proxy) injected from a hand-maintained baseline only when `claude mcp list` confirms the server is present (v1.1.4+). **You never have to maintain the tool list by hand.**
108
+ **`spotter install` seeds the Claude catalog automatically, and the SessionStart hook runs a background `spotter db refresh` on every Claude Code session start** — so you don't need to invoke Claude catalog commands by hand. Codex native hooks do the same for Codex: `spotter codex-hook install` registers a Codex `SessionStart` hook that starts `spotter db refresh --host-agent codex` in the background, updating `.spotter/tool-db.codex.json` without touching the Claude catalog. Claude discovery reads `claude mcp list` plus Claude skills / sub-agents; Codex discovery reads `codex mcp list/get` plus Codex skills. Each MCP server's `tools/list` is fetched via JSON-RPC (HTTP / SSE / stdio transports supported); skill and sub-agent metadata comes straight from frontmatter; the claude.ai baseline (25 hand-curated entries for Gmail / Calendar / Drive over OAuth proxy) is injected only for Claude when `claude mcp list` confirms the server is present. **You never have to maintain the tool list by hand.**
75
109
 
76
110
  ## Spotter and Throughline
77
111
 
@@ -88,21 +122,56 @@ Both share the principle of **"don't rely on the primary agent (Bell) to do it i
88
122
  ## Common commands
89
123
 
90
124
  ```bash
91
- spotter db list # show the current local tool-db (what the daemon actually audits against)
92
- spotter db refresh # rediscover MCP / skills / sub-agents and update the DB
93
- # (run automatically on install and on SessionStart since v1.1.0,
94
- # so this is rarely needed by hand)
95
- spotter db rebuild # wipe both local + global DBs and refresh from scratch
125
+ spotter db list # show the current Claude local tool-db
126
+ spotter db list --host-agent codex
127
+ # show the current Codex local tool-db
128
+ spotter db refresh # rediscover Claude MCP / skills / sub-agents and update the Claude DB
129
+ spotter db refresh --host-agent codex
130
+ # rediscover Codex MCP / skills and update .spotter/tool-db.codex.json
131
+ # (Claude refresh is automatic on install + Claude SessionStart;
132
+ # Codex refresh is automatic on Codex SessionStart after codex-hook install)
133
+ spotter db rebuild # wipe Claude local + global DBs and refresh from scratch
96
134
  # (use after catalog-shape changes)
97
135
  spotter status # list running daemons
98
- spotter doctor # environment check (Node / claude CLI / tool-db integrity)
136
+ spotter doctor # environment check (Node / claude CLI / Codex readiness / tool-db integrity)
137
+ spotter diagnostics logs # summarize daemon logs for pass=false / backend latency / anomaly signals
138
+ spotter codex risk-check --findings findings.json --host-agent claude
139
+ # run read-only codex-sidecar risk analysis for Spotter findings
140
+ spotter codex review|explore|opinion --findings findings.json --host-agent claude
141
+ # run other read-only codex-sidecar second-pass workflows
142
+ spotter codex work --findings findings.json --instruction "Update docs" --approve-work \
143
+ --allowed-path docs/ --preserve-worktree
144
+ # run approved codex-sidecar work in an isolated worktree
145
+ spotter codex-hook install
146
+ # register Codex native SessionStart / UserPromptSubmit / Stop hooks
147
+ spotter codex-hook diagnostics
148
+ # check Codex hooks feature and Spotter hook entries
99
149
  spotter uninstall # remove hooks from this project (leaves ~/.spotter intact)
100
150
  ```
101
151
 
152
+ Optional async Codex risk dispatch:
153
+
154
+ ```bash
155
+ SPOTTER_CODEX_RISK_CHECK=1 spotter daemon start --session-id ... --project-root ...
156
+ ```
157
+
158
+ When enabled, the daemon dispatches `pass:false` findings to `spotter codex risk-check`
159
+ in a detached process. Hook responses do not wait for Codex. Add
160
+ `SPOTTER_CODEX_RISK_CHECK_DRY_RUN=1` to exercise the wiring without calling Codex.
161
+
162
+ Primary auditor backend policy: Claude hooks keep the current Haiku-compatible path by
163
+ default. Codex native hooks use Codex CLI by default and do not fall back to Haiku;
164
+ their SessionStart hook refreshes `.spotter/tool-db.codex.json` in the background
165
+ without touching the Claude DB.
166
+ `SPOTTER_AUDITOR_BACKEND=codex-sidecar` is available for explicit sidecar auditor smoke.
167
+
102
168
  ## Design docs
103
169
 
104
170
  - **Current design** (catalog, discovery, classification axes): [docs/catalog-design.md](docs/catalog-design.md) — source of truth from v1.0.0
105
171
  - **Open issues + unverified concerns**: [docs/open-issues.md](docs/open-issues.md) — read this before starting new work
172
+ - **Claude contract capture**: [docs/SPOTTER_CLAUDE_CONTRACT.md](docs/SPOTTER_CLAUDE_CONTRACT.md) — current hook / daemon / Haiku behavior that Codex work must preserve
173
+ - **Claude / Codex dual-support brief**: [docs/SPOTTER_CODEX_DUAL_SUPPORT.md](docs/SPOTTER_CODEX_DUAL_SUPPORT.md) and completed [TODO](docs/SPOTTER_CODEX_DUAL_SUPPORT_TODO.md) — second-pass `codex-sidecar` workflows
174
+ - **Primary auditor backend migration**: [docs/SPOTTER_PRIMARY_BACKEND_TODO.md](docs/SPOTTER_PRIMARY_BACKEND_TODO.md) — Codex CLI / `codex-sidecar` auditor backend rollout status
106
175
  - **Implementation invariants (§0)**: [CLAUDE.md](CLAUDE.md) — no fallbacks, no silent failures, no provisional code
107
176
  - **Historical record (v0.1 design discussion)**: [docs/spotter-plan.md](docs/spotter-plan.md) — frozen design-discussion snapshot
108
177
 
@@ -112,13 +181,16 @@ spotter uninstall # remove hooks from this project (leaves ~/.spotter int
112
181
  - **Since v0.5.0, JSON schema violations from Haiku are treated as expected-anomalies** (silent pass + session renew, logged as `role_collapse_reset`) — this is the role-collapse recovery path. **Haiku timeouts still throw**, which surfaces as `UserPromptSubmit` blocking the user's prompt from reaching Bell. Timeouts have been raised twice (30s in v0.5.0, 45s in v0.13.1); making timeouts fail-open is deferred until §0 is revisited
113
182
 
114
183
  <details>
115
- <summary><strong>📋 v1.2.0 release notes (2026-04-26)</strong></summary>
116
-
117
- **Structural fix for a regression that suggested tools the current project can't actually use.** The catalog the daemon audits against is now **local-only**. The global DB has been demoted to a cross-project description-reuse cache. A prune step was added to the end of `resolveAll`: any local entry not present in the current project's discovery snapshot is removed. This closes the path through which MCP servers / skills / sub-agents discovered in other projects used to linger in this project's audit set.
184
+ <summary><strong>📋 Recent highlights</strong></summary>
118
185
 
119
- For projects that already have Spotter installed, the next SessionStart after the npm global upgrade triggers an auto-refresh; the ghosts disappear from the session-after-next (immediate cleanup: run `spotter db refresh` by hand). The pillars introduced in v1.1.0 (auto-build of the tool DB at install, automatic drift tracking on SessionStart) are unchanged. The audit scope set in v1.0.0 (user-added MCP / skills / sub-agents) is unchanged.
186
+ - **Plugin-scoped MCP servers** names like `plugin:everything-claude-code:context7` (with internal colons) are now parsed correctly and their tools enter the catalog. Earlier versions silently collapsed all plugin MCP servers into a single literal `"plugin"`, dropping their tools from Bell's audit
187
+ - **Per-project audit isolation** — the daemon audits against the local DB only; the global DB has been demoted to a description-reuse cache. Tools discovered in *other* projects can never bleed into this project's audit set
188
+ - **Zero-touch catalog** — `spotter install` seeds the Claude DB automatically; Claude and Codex SessionStart hooks keep their host-local DBs fresh in the background. You never have to maintain the tool list by hand
189
+ - **Codex native hooks** — Codex host uses Codex CLI as the primary auditor backend, keeps a separate `.spotter/tool-db.codex.json`, and surfaces backend failures explicitly instead of falling back to Haiku
190
+ - **Audit scope** — only user-added surface (MCP servers / skills / sub-agents). Claude Code's built-in tools are intentionally out of scope; Bell already uses those reliably
191
+ - **Implementation invariants** — no fallbacks, no silent failures, no provisional code (see [§0 in CLAUDE.md](CLAUDE.md))
120
192
 
121
- Full notes: [CHANGELOG](CHANGELOG.md).
193
+ Full release history: [CHANGELOG](CHANGELOG.md).
122
194
 
123
195
  </details>
124
196