claude-spotter 1.3.0 → 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 +34 -2
  2. package/README.ja.md +57 -16
  3. package/README.md +58 -17
  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 +13 -8
  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 +23 -71
  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,36 @@
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
+
3
34
  ## 1.3.0
4
35
 
5
36
  **Haiku spawn 時に user/project の MCP server を一切 load しないよう強制 — WSL2 で観測された CPU 100% 飽和 + 孤児 `npm exec` プロセス累積 + チャット入力無反応 の根本原因を断った minor bump**。修正は `claude -p` 起動引数に `--strict-mcp-config --mcp-config <empty>` を必ず付けるだけの最小実装、副作用なし。
@@ -41,8 +72,9 @@ WSL2 の CPU 使用率が 100% に張り付き、何かがプロセスを「無
41
72
  ### Chime / Spotter ユーザー側で必要な手順
42
73
 
43
74
  1. `npm install -g claude-spotter@1.3.0` で global update
44
- 2. install プロジェクトでは hook 設定 (`spotter.mjs` のパス固定) は変わらないので **再 install 不要**、次の SessionStart から自動的に新コードが効く
45
- 3. 既存の孤児 daemon があれば `kill <pid>` + `rm ~/.spotter/runtime/session-*.pid` で掃除 (今後は v1.3.0MCP-disable sudden death 自体が大幅減少見込み)
75
+ 2. Haiku spawn MCP-disable は次の SessionStart から自動的に新コードが効く
76
+ 3. install プロジェクトでも `spotter install` を再実行して、`.claude/settings.json` UserPromptSubmit / Stop hook timeout を 60s に更新する ( settings15s/30s global update だけでは書き換わらない)
77
+ 4. 既存の孤児 daemon があれば `kill <pid>` + `rm ~/.spotter/runtime/session-*.pid` で掃除 (今後は v1.3.0 の MCP-disable で sudden death 自体が大幅減少見込み)
46
78
 
47
79
  ## 1.2.6
48
80
 
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,17 +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
- | 「このライブラリの最新版の使い方は?」 | 学習データから書き起こす | docs lookup MCP の照会機会 |
31
30
  | 「この UI 今もちゃんと動く?」 | コード読みだけで結論 | ブラウザ自動化 MCP の使用機会 |
32
31
  | 「以前何を決めたっけ?」 | 推測 / 失念のまま回答 | メモリ / ノート系 MCP の照会機会 |
33
32
 
34
33
  判定軸は 2 段階:
35
34
 
36
- - **入力時 (`stage=user_input`)**: ユーザー要請に対し、`when_to_use` の条件に明確に該当するツールを列挙する **要請充足チェック**
35
+ - **入力時 (`stage=user_input`)**: ユーザー要請に対し、ローカルカタログの description から用途が明確に該当するツールを列挙する **要請充足チェック**
37
36
  - **応答後 (`stage=turn_end`)**: Bell の最終応答に対し、事実の断定 / 記録すべき新情報 / 既知情報の参照それぞれに、カタログ上のツール (検証 / 登録 / 照会) を差し込める余地がないかを問う **ツール適用機会の監査**
38
37
 
39
38
  ## インストール
@@ -42,9 +41,14 @@ Spotter が拾うのは、たとえばこういう瞬間です。
42
41
  npm install -g claude-spotter
43
42
  cd your-project
44
43
  spotter install
44
+ # 任意: Codex native hooks を使う場合
45
+ spotter codex-hook install
45
46
  ```
46
47
 
47
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 値は自動では書き換わりません。
48
52
 
49
53
  ```bash
50
54
  spotter uninstall # このプロジェクトの hook 登録を解除
@@ -54,7 +58,8 @@ spotter uninstall # このプロジェクトの hook 登録を解除
54
58
 
55
59
  - **Node.js 22.5 以上**
56
60
  - **Claude Code 2.0 以上**
57
- - **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 しません
58
63
 
59
64
  ## アーキテクチャ
60
65
 
@@ -91,16 +96,16 @@ flowchart LR
91
96
  LG["Legacy — ~/.claude/.mcp.json"]
92
97
  end
93
98
  SCOPES -. merge .-> MCP
94
- MCP --> DB[(ローカル tool-db.json<br/>name + description<br/>プロジェクト単位)]
99
+ MCP --> DB[(ホスト別ローカル tool-db<br/>name + description<br/>プロジェクト単位)]
95
100
  SK --> DB
96
101
  AG --> DB
97
102
  BL --> DB
98
103
  DB --> H[Haiku 監査<br/>session-scoped, preamble-once]
99
104
  ```
100
105
 
101
- 監査対象のツール (name + description) は `<project>/.spotter/tool-db.json` (ローカル) に格納されます。**daemon が監査に使うのはローカル DB のみ**で、グローバル 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 のツールリストで上書きされることはありません。
102
107
 
103
- **`spotter install` が初回 seed を自動実行し、Claude Code セッション起動ごとに SessionStart hook が bg で `spotter db refresh` を走らせる**ため、通常の運用で手動コマンドを叩く必要はありません。各 MCP サーバーの `tools/list` は JSON-RPC で取得 (HTTP / SSE / stdio transport 対応)、スキルとサブエージェントは frontmatter から直接抽出、claude.ai baseline (OAuth proxy 経由の Gmail / Calendar / Drive 25 件) は `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` に該当サーバーが存在する環境で注入されます。**手書きでツールリストを管理する必要はありません**。
104
109
 
105
110
  ## Throughline との関係
106
111
 
@@ -117,19 +122,54 @@ flowchart LR
117
122
  ## よく使うコマンド
118
123
 
119
124
  ```bash
120
- spotter db list # 現在のローカル tool-db (daemon が実際に audit に使う) を表示
121
- spotter db refresh # MCP / スキル / サブエージェントから description を収集して DB 更新
122
- # (v1.1.0 以降、install 時と SessionStart 時に自動実行されるので通常は不要)
123
- 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 (カタログ設計変更時のクリーン用)
124
134
  spotter status # 稼働中の daemon 一覧
125
- 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 登録を診断
126
148
  spotter uninstall # hook 登録を解除 (~/.spotter は残す)
127
149
  ```
128
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
+
129
166
  ## 設計ドキュメント
130
167
 
131
168
  - **現行設計 (カタログ / 収集経路 / 分類軸)**: [docs/catalog-design.md](docs/catalog-design.md) — v1.0.0 以降の真実源
132
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 状況
133
173
  - **実装規範と不変条件 (§0)**: [CLAUDE.md](CLAUDE.md) — フォールバック禁止 / silent fallback 禁止 / 暫定コード禁止
134
174
  - **歴史記録 (v0.1 時点の設計議事録)**: [docs/spotter-plan.md](docs/spotter-plan.md) — 作成時点で固定された議論過程のスナップショット、現行設計は上記 3 点を参照
135
175
 
@@ -143,7 +183,8 @@ spotter uninstall # hook 登録を解除 (~/.spotter は残す)
143
183
 
144
184
  - **プラグイン形式の MCP サーバー対応** — `plugin:everything-claude-code:context7` のように名前に内部コロンを含むサーバーを正しくパースし、配下のツールをカタログに取り込めるようになった (旧版はこの形式のサーバーをすべて単一の `"plugin"` に潰して、Bell の監査から silent に脱落させていた)
145
185
  - **プロジェクト単位の監査隔離** — daemon が監査に使うのはローカル DB のみ。グローバル DB は description 再利用キャッシュに役割限定。**他プロジェクト**でインストールしたツールが現プロジェクトの監査に混入することはない
146
- - **手放しでカタログ維持** — `spotter install` が tool-db を自動 seed、SessionStart bg refresh が走る。手書き管理は一切不要
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 として扱う
147
188
  - **監査対象** — ユーザー追加分 (MCP / スキル / サブエージェント) のみ。Claude Code 本体側のツールは意図的に対象外 (Bell は元から自発率が高いため)
148
189
  - **実装規範** — フォールバック禁止 / silent fallback 禁止 / 暫定コード禁止 ([CLAUDE.md §0](CLAUDE.md))
149
190
 
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,17 +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` |
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
29
  | Asserting a fact | State it without verification | Opportunity to call a verification tool |
30
- | "How does this library API work in the latest version?" | Recite from training data | Missed call to a docs-lookup MCP |
31
30
  | "Does this UI still render correctly?" | Reason from source code alone | Missed call to a browser-automation MCP |
32
31
  | "What did we decide about X earlier?" | Guess or admit forgetting | Missed call to a memory / notes MCP |
33
32
 
34
33
  Spotter audits in two stages:
35
34
 
36
- - **`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
37
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
38
37
 
39
38
  ## Install
@@ -42,9 +41,14 @@ Spotter audits in two stages:
42
41
  npm install -g claude-spotter
43
42
  cd your-project
44
43
  spotter install
44
+ # Optional, for Codex native hooks:
45
+ spotter codex-hook install
45
46
  ```
46
47
 
47
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.
48
52
 
49
53
  ```bash
50
54
  spotter uninstall # remove hooks from this project
@@ -54,7 +58,8 @@ spotter uninstall # remove hooks from this project
54
58
 
55
59
  - **Node.js 22.5+**
56
60
  - **Claude Code 2.0+**
57
- - **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
58
63
 
59
64
  ## Architecture
60
65
 
@@ -91,16 +96,16 @@ flowchart LR
91
96
  LG["Legacy — ~/.claude/.mcp.json"]
92
97
  end
93
98
  SCOPES -. merged into .-> MCP
94
- MCP --> DB[(Local tool-db.json<br/>name + description<br/>per project)]
99
+ MCP --> DB[(Host-local tool-db<br/>name + description<br/>per project)]
95
100
  SK --> DB
96
101
  AG --> DB
97
102
  BL --> DB
98
103
  DB --> H[Haiku audit<br/>session-scoped, preamble-once]
99
104
  ```
100
105
 
101
- The audited catalog lives in `<project>/.spotter/tool-db.json`. **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 (stale entries are pruned on refresh), so tools 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.
102
107
 
103
- **`spotter install` seeds the 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 catalog commands by hand. 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 when `claude mcp list` confirms the server is present. **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.**
104
109
 
105
110
  ## Spotter and Throughline
106
111
 
@@ -117,21 +122,56 @@ Both share the principle of **"don't rely on the primary agent (Bell) to do it i
117
122
  ## Common commands
118
123
 
119
124
  ```bash
120
- spotter db list # show the current local tool-db (what the daemon actually audits against)
121
- spotter db refresh # rediscover MCP / skills / sub-agents and update the DB
122
- # (run automatically on install and on SessionStart since v1.1.0,
123
- # so this is rarely needed by hand)
124
- 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
125
134
  # (use after catalog-shape changes)
126
135
  spotter status # list running daemons
127
- 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
128
149
  spotter uninstall # remove hooks from this project (leaves ~/.spotter intact)
129
150
  ```
130
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
+
131
168
  ## Design docs
132
169
 
133
170
  - **Current design** (catalog, discovery, classification axes): [docs/catalog-design.md](docs/catalog-design.md) — source of truth from v1.0.0
134
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
135
175
  - **Implementation invariants (§0)**: [CLAUDE.md](CLAUDE.md) — no fallbacks, no silent failures, no provisional code
136
176
  - **Historical record (v0.1 design discussion)**: [docs/spotter-plan.md](docs/spotter-plan.md) — frozen design-discussion snapshot
137
177
 
@@ -145,7 +185,8 @@ spotter uninstall # remove hooks from this project (leaves ~/.spotter int
145
185
 
146
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
147
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
148
- - **Zero-touch catalog** — `spotter install` seeds the tool DB automatically, and SessionStart triggers a background refresh. You never have to maintain the tool list by hand
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
149
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
150
191
  - **Implementation invariants** — no fallbacks, no silent failures, no provisional code (see [§0 in CLAUDE.md](CLAUDE.md))
151
192
 
package/bin/spotter.mjs CHANGED
@@ -7,6 +7,10 @@ import { runUninstall } from '../src/cli/uninstall.mjs';
7
7
  import { runDoctor } from '../src/cli/doctor.mjs';
8
8
  import { runStatus } from '../src/cli/status.mjs';
9
9
  import { runDbList, runDbRefresh, runDbRebuild } from '../src/cli/db-cmd.mjs';
10
+ import { runCodexCommand } from '../src/cli/codex-cmd.mjs';
11
+ import { runCodexHookCommand } from '../src/cli/codex-hook-cmd.mjs';
12
+ import { runAuditorCommand } from '../src/cli/auditor-cmd.mjs';
13
+ import { runDiagnosticsCommand } from '../src/cli/diagnostics-cmd.mjs';
10
14
  import { runDaemonStart } from '../src/cli/daemon-cmd.mjs';
11
15
  import { runSessionStart } from '../src/hooks/session-start.mjs';
12
16
  import { runUserPrompt } from '../src/hooks/user-prompt.mjs';
@@ -26,11 +30,26 @@ Usage:
26
30
  spotter uninstall [-y] remove spotter hooks from <cwd>/.claude/settings.json
27
31
  and remove <cwd>/.spotter/marker.json
28
32
  spotter uninstall --user [-y] remove from ~/.claude/settings.json
29
- spotter db list show merged tool-db (local + global)
30
- spotter db refresh discover MCP / deferred tools and update DB
31
- spotter db rebuild wipe local DB then refresh
33
+ spotter db list [--host-agent HOST] show host-local tool-db (claude by default)
34
+ spotter db refresh [--host-agent HOST]
35
+ discover MCP / skills / sub-agents and update DB
36
+ spotter db rebuild [--host-agent HOST]
37
+ wipe host-local + global DBs then refresh
32
38
  spotter status show running daemons
33
39
  spotter doctor environment diagnostic
40
+ spotter diagnostics logs [--json] summarize daemon logs for precision diagnostics
41
+ spotter codex risk-check --findings FILE
42
+ run read-only codex-sidecar risk analysis
43
+ spotter codex review|explore|opinion --findings FILE
44
+ run read-only codex-sidecar second-pass workflows
45
+ spotter codex work --findings FILE --approve-work --allowed-path PATH
46
+ run approved codex-sidecar worktree workflow
47
+ spotter codex-hook install|uninstall|diagnostics
48
+ (experimental) manage Codex native hooks
49
+ spotter auditor judge --stage STAGE --input FILE
50
+ (experimental) run primary auditor backend once
51
+ spotter auditor matrix --stage STAGE --input FILE
52
+ (experimental) compare primary auditor backend matrix
34
53
  spotter daemon start --session-id ID (internal) run session daemon
35
54
  spotter hook <event> (internal) hook dispatch
36
55
  events: session-start | user-prompt |
@@ -67,9 +86,9 @@ async function main() {
67
86
  }
68
87
  case 'db': {
69
88
  const sub = rest[0];
70
- if (sub === 'list') { await runDbList(); return; }
71
- if (sub === 'refresh') { await runDbRefresh(); return; }
72
- if (sub === 'rebuild') { await runDbRebuild(); return; }
89
+ if (sub === 'list') { await runDbList({ argv: rest.slice(1) }); return; }
90
+ if (sub === 'refresh') { await runDbRefresh({ argv: rest.slice(1) }); return; }
91
+ if (sub === 'rebuild') { await runDbRebuild({ argv: rest.slice(1) }); return; }
73
92
  process.stderr.write(`unknown db subcommand: ${sub}\n${USAGE}`);
74
93
  process.exit(2);
75
94
  return;
@@ -80,6 +99,18 @@ async function main() {
80
99
  case 'doctor':
81
100
  await runDoctor();
82
101
  return;
102
+ case 'codex':
103
+ await runCodexCommand({ argv: rest });
104
+ return;
105
+ case 'codex-hook':
106
+ await runCodexHookCommand({ argv: rest });
107
+ return;
108
+ case 'auditor':
109
+ await runAuditorCommand({ argv: rest });
110
+ return;
111
+ case 'diagnostics':
112
+ await runDiagnosticsCommand({ argv: rest });
113
+ return;
83
114
  case 'daemon': {
84
115
  const sub = rest[0];
85
116
  if (sub === 'start') { await runDaemonStart({ argv: rest.slice(1) }); return; }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "claude-spotter",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Audit agent running alongside Claude Code that catches missed tool calls — 気づく役と実行する役の分離",
5
5
  "type": "module",
6
6
  "bin": {
7
- "spotter": "./bin/spotter.mjs"
7
+ "spotter": "bin/spotter.mjs"
8
8
  },
9
9
  "exports": {
10
10
  ".": "./src/index.mjs"
@@ -22,8 +22,11 @@ if (process.env.CI === 'true' || process.env.CI === '1') {
22
22
  }
23
23
 
24
24
  console.log('claude-spotter installed.');
25
- console.log(' Next step (per project you want audited):');
25
+ console.log(' Next step for Claude Code projects you want audited:');
26
26
  console.log(' cd <your-project>');
27
27
  console.log(' spotter install');
28
28
  console.log(' This writes hooks to <project>/.claude/settings.json and a .spotter/');
29
29
  console.log(' marker so unrelated `claude -p` invocations do not trigger Spotter.');
30
+ console.log(' Optional for Codex native hooks:');
31
+ console.log(' spotter codex-hook install');
32
+ console.log(' Codex hooks refresh .spotter/tool-db.codex.json on SessionStart.');