diff --git a/BACKLOG.md b/BACKLOG.md index 9a76183..a55238d 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -52,7 +52,7 @@ CC-001/CC-002 were consumed by PR #24 fix bundle inline, with no standalone entr | CC-273 | ⏸ deferred | arch: unified lifecycle hook event spec(`.pm-dispatch/hooks/.sh`);activate when second hook point beyond gate pre/post emerges | arch/gate | 2026-05-28 | — | P3 | — | | CC-286 | ⏸ deferred | **[pmctl: prefix-generic next-id derivation]** `scripts/pm-prep-snapshot.sh` derives `backlog_next_id` CC-only (it emits `CC-NNN`); under the working-set contract it scans BACKLOG.md + BACKLOG-ARCHIVE.md for the max, but only `CC-` IDs. A cross-repo next-id (other prefixes: JS-, PA-) must be prefix-derived and centralized in pmctl, scanning both working-set and archive. Retire pm-prep-snapshot's CC-hardcoded derivation when `pmctl backlog`/next-id lands. Surfaced by pr-gate critic+architecture on #186. | arch | 2026-05-30 | — | P3 | design | | CC-306 | ⏸ deferred | **[arch: extend CC-233 layer enforcer to runtime-named data paths in scripts/]** Guard against re-introducing `.codex-*`/`.claude-*` DATA directories under scripts/ (the optional follow-up deferred from CC-298). | arch | 2026-06-01 | — | P3 | design | -| CC-333 | 🔵 active | arch: pm-dispatch runtime 解耦合(v0.6.0 umbrella);layer 2/3/5/6 已交付(v0.6.0);layer 1(CC-412)+layer 4(CC-381)排入 v0.8.0;layer 7 待評估;open sub-tickets: CC-381/390/393/412 | arch | 2026-06-07 | — | P2 | design | +| CC-333 | 🔵 active | arch: pm-dispatch runtime 解耦合(v0.6.0 umbrella);layer 2/3/5/6 已交付(v0.6.0);layer 1(CC-412)已交付、layer 4 spike(CC-381)已收斂為 CC-436/437/438;layer 7 待評估;open sub-tickets: CC-390/393/412/436/437/438 | arch | 2026-06-07 | — | P2 | design | | CC-340 | ⏸ deferred | knowledge index: embeddings/semantic-backend remainder(FTS/LIKE MVP 已由 CC-403 接管;本票保留 Khoj-class semantic accelerator,待 FTS ranking 不足時 resume) | memory | 2026-06-08 | — | P3 | retrieval | | CC-342 | 🟢 someday | agent: debt-auditor — proactive tech-debt health scan(`agents/debt-auditor.md`;`pmctl audit ` 呼叫;PR-free 主動健康掃描,有別於現有 PR-focused reviewers) | process/DX | 2026-06-05 | — | P3 | design | | CC-346 | ⏸ deferred | repo-index: cross-file ref tracking `file_refs` table(paused 2026-06-10;resume trigger: reuse-scan 進過 ≥2 份真 brief 且缺 ref 資料為瓶頸;屆時先 Phase a bash source) | ops | 2026-06-09 | — | P3 | design | @@ -67,11 +67,14 @@ CC-001/CC-002 were consumed by PR #24 fix bundle inline, with no standalone entr | CC-369 | ⏸ deferred | Windows state store 真實 ACL via icacls(parked: CC-370;border case relative to profile ACL protection) | ops/portability | 2026-06-13 | — | — | hygiene | | CC-370 | ⏸ deferred | **[native Windows support deferred to post-core platform phase]** 核心功能開發期間正式只支援 Linux + WSL2(WSL2 視為 Linux);原生 Windows Git Bash 非官方支援,使用者走 WSL2。理由是專注:開發期同時扛多平台會排擠核心功能(CI 只測 Linux,每次碰 Windows 都要人工驗證 + gate churn,見 #272/#273)。已合併的 portability 程式碼保留(綠且成本低),但不再新增 Windows 分支,直到核心定型(v0.5.0+)後的專屬平台階段。Parks: CC-038, CC-104d/e/f/g/j/k/r/s, CC-369。**See**: DECISIONS.md 2026-06-13 defer-native-windows-support-during-core-dev | ops/portability | 2026-06-13 | — | — | design | | CC-377 | ⏸ deferred | adapter: Google Antigravity(`agy`)executor(DEFERRED:headless CLI 1.0.8 不成熟;resume: newer agy with `--output-format stream-json`;umbrella: CC-333) | arch/portability | 2026-06-13 | — | P2 | design | -| CC-381 | 🔵 active | arch: install host-PM-aware(host runtime axis:codex/opencode host PM 設定面;排在 CC-373..377 之後;umbrella: CC-333)。v0.8.0 Phase 3 spike-only:縮小為 read-only host-profile-detection / doctor 擴充切片,不動 installer write path | arch/install | 2026-06-14 | — | P2 | design | +| CC-381 | ✅ done | arch: install host-PM-aware(host runtime axis:codex/opencode host PM 設定面;umbrella: CC-333)。v0.8.0 Phase 3 spike 已收斂(`docs/spikes/CC-381.md`):guard 落點不確定性已解——codex native PreToolUse hook 可行;後續拆為 CC-436/437/438 | arch/install | 2026-06-14 | pr:#359 | P2 | design | | CC-390 | ⏸ deferred | codex dispatch trace-capture 強化(FD inheritance cold-start flake;fail-closed safe;resume: stable repro;umbrella: CC-333) | arch/portability | 2026-06-15 | — | P3 | design | | CC-393 | 🟢 someday | design: portable-skill-substrate — CLI-agnostic skill 控制層(design seed after v0.6.0 N≥2;3 control skills + Portable Skill v0 frontmatter;umbrella: CC-333) | arch | 2026-06-16 | — | — | design | | CC-431 | 🟢 someday | **[test-e2e.sh + release-verify.sh: opencode adapter support]** `--adapter` 目前只接受 `claude\|codex\|auto`;opencode 在 v0.6.0 加入後未同步更新 e2e 驗證路徑。需:(1) 將 opencode 加入兩腳本的 adapter 驗證清單;(2) Phase B dispatch 支援 opencode;(3) Phase C pr-gate smoke 評估是否可用 opencode executor(目前硬碼 codex)。觸發:release-verify --e2e --adapter opencode 被拒(exit 2)。 | ops/test | 2026-06-30 | — | P3 | — | | CC-435 | 🟢 someday | **[poll→通知機制 single-waiter guard:條件觸發,非既定後續票]** 只有在真正出現多個 waiter 需要同時等待同一個 run_id/gate_id 的場景時才拿出來討論;候選設計見 `docs/spikes/CC-433.md` Open risks(方案 A:`flock` 搶鎖+敗者退回輪詢;方案 B:per-waiter 專屬 fifo+supervisor 廣播)。CC-434 完成後重新盤點成本效益:輪詢 vs blocking read 在單一 waiter/數分鐘等待場景下資源消耗差距趨近於零,延遲改善(≤2s→近乎即時)對人在等 gate 結果無感,而兩個方案都要在安全敏感的 supervisor 檔案引入新 race condition,投資報酬率目前不足,故不排入既定實作,僅記錄設計供未來觸發條件成立時起步。 | arch/gate | 2026-07-02 | — | P3 | design | +| CC-436 | 🔵 active | codex-host PreToolUse payload 驗證 probe(唯讀,驗證 CC-381 guard binding 可行性;umbrella: CC-333) | arch/install | 2026-07-02 | — | P2 | spike | +| CC-437 | 🔵 active | doctor 擴充切片:host-aware capability check(`doctor.sh` 拆出 host module 介面;umbrella: CC-333,承接 CC-381) | arch/install | 2026-07-02 | — | P2 | design | +| CC-438 | 🔵 active | host manifest schema v1:codex-host 設定面宣告化(`hosts/codex/host.yaml` + format handler;依賴 CC-436;umbrella: CC-333,承接 CC-381) | arch/install | 2026-07-02 | — | P2 | design | --- @@ -101,7 +104,7 @@ _Terminal_ (CC-378: swept OUT to `BACKLOG-ARCHIVE.md` by `scripts/archive-closed -## CC-381 — arch: install host-PM-aware 🔵 active +## CC-381 — arch: install host-PM-aware ✅ 2026-07-02 **Problem**: `install.sh` / `install-hooks.sh` 把整個安裝面寫死成 claude harness:PreToolUse/SessionEnd 等 hook 接進 `~/.claude/settings.json`、reviewer 與 dispatch 的 `permissions.allow`、statusline、以及 `agents/` `commands/` 的 PM 介面,全部假設「claude 是 host PM」。一旦 codex(或未來 host)當主 PM,這些都不對:codex 的設定面是 `~/.codex/` + `AGENTS.md` +自有 sandbox/approval 模型,沒有 `~/.claude` 那套 PreToolUse hook。[[CC-334]]/[[CC-380]] 把 reviewer guard 與 allow-list 寫進 `~/.claude/settings.json`——在 codex-host 下根本不載入,等於 codex-PM 安裝拿不到任何 gate/guard plumbing。 @@ -117,7 +120,59 @@ _Terminal_ (CC-378: swept OUT to `BACKLOG-ARCHIVE.md` by `scripts/archive-closed **Sequencing**: 排在 v0.6.0 executor-abstraction 核心([[CC-373]]..[[CC-377]])之後;可能落在 v0.7.0(與 [[CC-333]] layer 1/7、MCP 同期評估)。 -**See**: [[CC-333]] umbrella(layer 4 install-path)、關聯 [[CC-380]](暴露 install 的 claude-host 中心性)、[[guard-role-runtime]](role×runtime 兩軸)、[[CC-375]](manifest 衍生接線)。 +**Outcome**: v0.8.0 Phase 3 spike 完成並收斂(`docs/spikes/CC-381.md`)——三方獨立分析(主線程 BACKLOG/決策脈絡視角、codex read-only 對自身 hook runtime 的實測、chatgpt 外部架構視角)。guard 落點的最大不確定性已解:codex `PreToolUse` hook 經 codex 自己實測(`codex features list`/`codex doctor --json`/binary 字串)證實 stable 且 fail-closed,足以承接 write/bash guard,不必退回 cli-only fallback。本票收斂為三張後續票:[[CC-436]](payload 驗證 probe,唯讀,第一刀)、[[CC-437]](doctor 擴充切片,可與 CC-436 並行)、[[CC-438]](host manifest schema v1 draft,依賴 CC-436)。`install.sh` write path 仍不動,留給後續票。 +**See**: pr:#359 + +--- + +## CC-436 — codex-host PreToolUse payload 驗證 probe 🔵 active + +**Problem**: [[CC-381]] spike(`docs/spikes/CC-381.md`)已用唯讀證據(`codex features list`/`codex doctor --json`/binary 字串反查)確認 codex `PreToolUse` hook 是 stable 且會 fail-closed 阻擋,但尚未實際跑過一次 end-to-end 的 hook 阻擋,也不知道 payload 內容能否映射到 `pmctl guard check --file/--command` 需要的欄位。 + +**Why**: 這是 [[CC-381]] 收斂矩陣認定的「最小風險、最高信號」第一刀——payload 欄位不足會直接限制 codex-host guard binding 的設計空間(例如只能擋 command 不能擋 file path),必須在寫 host manifest schema([[CC-438]])前確認。 + +**Requirement**: +- 在 throwaway `CODEX_HOME`(`/tmp`)配置最小 `PreToolUse` hook,對一個明確 command(如 `echo blocked`)與一個 file change/apply patch 動作分別觸發,驗證 hook 是否真的 fail-closed 阻擋。 +- 確認 hook payload 是否包含可映射到 `pmctl guard check --file ` / `--command ` 的欄位;若不足,明確記錄缺口而非停在「可能不夠」。 +- 唯讀性質:不修改 repo 任何 install/doctor write path,不影響現有 codex executor adapter(`write_guard_mode: cli-only`)行為。 +- 結果寫回 `docs/spikes/CC-381.md`(追加 angle 或新增 `docs/spikes/CC-436.md`,由執行時決定)。 + +**Dependencies**: 承接 [[CC-381]] spike 建議「第一刀」。umbrella [[CC-333]]。 +**See**: `docs/spikes/CC-381.md` §Recommendation 步驟 1。 + +--- + +## CC-437 — doctor 擴充切片:host-aware capability check 🔵 active + +**Problem**: `scripts/doctor.sh` 目前四處寫死 claude-host 路徑(`check_settings_file`/`check_hooks`/`check_dispatch_allowlist`/`check_manifest`),無法回答「目前 host 是 claude/codex/opencode?哪些能力有 wiring?哪些只能透過 pmctl 手動使用?」。 + +**Why**: [[CC-381]] spike 三方一致收斂:doctor 應以 capability(`command_guard`/`session_lifecycle`/`pm_command_interface`/`statusline` 等)為檢查單位,而非以 host 為單位;核心跑通用檢查、host-specific 邏輯外移,未來加新 host 才不必改 doctor 核心。此切片唯讀、風險最小,可與 [[CC-436]] 並行。 + +**Requirement**: +- `doctor.sh`(或 `pmctl doctor`)拆出通用核心檢查與 host-specific 檢查模組介面,新增 host 時只加模組、不改核心邏輯。 +- 檢查結果以 capability 為單位呈現(provider/enforcement/coverage/stability 等,具體結構由實作時的 `/pre-impl` 收斂),而非「這個 host 設定對不對」的二元判斷。 +- 至少涵蓋 claude-host 既有檢查(回歸不遺漏)與 codex-host 的對應能力探測。 +- 唯讀:不改變 install 的 write path。 + +**Dependencies**: 承接 [[CC-381]] spike 建議,可與 [[CC-436]] 並行(不互相阻塞)。umbrella [[CC-333]]。 +**See**: `docs/spikes/CC-381.md` §Angle 1/2/3 doctor 段落、§Recommendation 步驟 3。 + +--- + +## CC-438 — host manifest schema v1:codex-host 設定面宣告化 🔵 active + +**Problem**: install 目前把 codex-host 的設定 target/format 假設寫死在程式碼常數(若日後實作),而非宣告在 manifest;[[CC-381]] spike 已收斂出應與既有 executor adapter manifest([[CC-372]] `runner_kind`)分離、互為姊妹結構的 host manifest 方向,但尚未有 schema v1 draft。 + +**Why**: 沒有 schema,[[CC-437]] 的 host-specific 檢查模組與未來 install write path 都無所依附;schema 需要先確認 [[CC-436]] 的 payload 驗證結果,才能把 `guard_bindings` 欄位定案。 + +**Requirement**: +- 產出 `hosts/codex/host.yaml` schema v1 draft:至少涵蓋 install target/format、hook surface、guard bindings、permissions surface、doctor/uninstall module 指標。 +- 與 [[CC-372]] executor adapter manifest(`runner_kind`/`write_guard_mode`)保持姊妹結構,不合併語意——host manifest 描述「host PM 自身」軸,adapter manifest 描述「PM→executor」軸。 +- schema 欄位需能表達「能力尚在演進」的狀態(例如 declared/probed/effective 或等價分層),不得假設所有 host 能力恆定。 +- 不落地實際 `install.sh` write path 改動(留給後續票)。 + +**Dependencies**: 依賴 [[CC-436]](payload 驗證結果決定 `guard_bindings` 欄位能表達什麼)。承接 [[CC-381]] spike。umbrella [[CC-333]]。 +**See**: `docs/spikes/CC-381.md` §Angle 2 manifest YAML 草案、§Recommendation 步驟 2。 --- diff --git a/MILESTONES.md b/MILESTONES.md index cfb04a8..29c8a25 100644 --- a/MILESTONES.md +++ b/MILESTONES.md @@ -11,7 +11,7 @@ ## v0.8.0 — memory substrate 跨工具可攜 + gate DX(規劃中 2026-07-01) -> 最後排程更新:2026-07-01 +> 最後排程更新:2026-07-02 **主題**:延續 v0.6.0(executor abstraction)與 v0.7.0(retrieval-base:memory 成為 `pmctl context` 可檢索 source)兩版已交付的抽象工作,補上最後兩個 Claude 專屬耦合點——**memory 位置 resolver** 與 **注入機制**(CC-412,headline);並行做兩張範圍小、風險低、彼此檔案面不重疊的 gate DX 票(CC-276、CC-423);另起一個 spike-only phase 把 CC-381(host-PM-aware install)從「設計問題陳述」推進到「有具體 Requirement 的實作票」,為下一版鋪路。 @@ -45,11 +45,13 @@ > CC-433 排入 Phase 2 作為 CC-423 的後續收斂項,非阻塞本 Phase 其餘票的完成。CC-432 為 CC-423 pr-gate 迭代中發現並記錄的衍生票,同樣併入 Phase 2。CC-425 原評估「需重構 gate result key schema,範圍比 CC-276/423 大一截」暫不排入,2026-07-02 使用者確認排入本 Phase 處理;實作前盤點發現 result key 已在 CC-423 detached lifecycle 重構中改為 gate_id-keyed,範圍縮小為僅需新增 `--head `,`/pre-impl` 的向下相容顧慮已不適用,見 pr:#355。 -### Phase 3 — CC-381 spike-only(P3;design 收斂,非完整實作) +### Phase 3 — CC-381 spike-only(P3;design 收斂,非完整實作)✅ spike done pr:#359 | 票 | 摘要 | 狀態 | |----|------|------| -| CC-381 | install host-PM-aware — 縮小為 read-only host-profile-detection / doctor 擴充切片:讓 `doctor.sh`/`pmctl doctor` 能回答「目前 host 是 claude/codex/opencode?哪些能力有 wiring?哪些只能透過 pmctl 手動使用?」不動 installer write path。前置票 CC-372/374/375/380 已全數 done,本 Phase 目標是把 CC-381 從設計陳述推進為有明確 Requirement 的實作票 | 🔵 active | +| CC-381 | install host-PM-aware — 縮小為 read-only host-profile-detection / doctor 擴充切片:讓 `doctor.sh`/`pmctl doctor` 能回答「目前 host 是 claude/codex/opencode?哪些能力有 wiring?哪些只能透過 pmctl 手動使用?」不動 installer write path。前置票 CC-372/374/375/380 已全數 done,本 Phase 目標是把 CC-381 從設計陳述推進為有明確 Requirement 的實作票 | ✅ spike done pr:#359 | + +> **Phase 3 結果**:2026-07-02 三方獨立分析(主線程/codex read-only 實測/chatgpt 外部視角)收斂於 `docs/spikes/CC-381.md`。最大不確定性(codex hook 機制是否足以承接 write/bash guard)已由 codex 自身唯讀實測解答:`PreToolUse` hook stable 且 fail-closed,足以承接,不必退回 cli-only fallback。CC-381 從設計陳述推進為三張有明確 Requirement 的後續票:**CC-436**(codex PreToolUse payload 驗證 probe,第一刀,唯讀)、**CC-437**(doctor 擴充切片,可與 CC-436 並行)、**CC-438**(host manifest schema v1 draft,依賴 CC-436)。三票排入下一版(v0.9.0 候選,待排程)評估,`install.sh` write path 仍不動。 ### Phase 4 — CC-014 repo 通用 worktree 平行開發工具(P3;低風險並行;與 Phase 1-3 檔案面不重疊) @@ -66,7 +68,7 @@ - **CC-216 MCP**——2026-06-18 已拍板不排入任何 milestone,維持排除。 - **CC-340 embeddings**——維持排除,同既有立場,待 FTS/LIKE ranking 證明不足再 resume。 - **CC-377 agy adapter**——等待 agy headless CLI 版本更新,不排入。 -- **CC-381 完整實作**(installer write path、多 host 設定面改寫)——Phase 3 只做 spike/doctor 切片,完整改寫留給 spike 收斂後的下一版評估。 +- **CC-381 完整實作**(installer write path、多 host 設定面改寫)——Phase 3 spike 已收斂為 CC-436/437/438 三張後續票(見上方 Phase 3 結果),installer write path 仍留給這三票驗證完成後的下一版評估。 --- diff --git a/docs/spikes/CC-381.md b/docs/spikes/CC-381.md new file mode 100644 index 0000000..1c5aa4e --- /dev/null +++ b/docs/spikes/CC-381.md @@ -0,0 +1,150 @@ +# CC-381 — install host-PM-aware(spike result) + +**Status**: complete +**Date**: 2026-07-02 +**Ticket**: BACKLOG.md CC-381(umbrella: CC-333 layer 4) + +## Investigation scope + +`install.sh` / `install-hooks.sh` 目前把整個安裝面寫死成 claude-host(`~/.claude/settings.json` +的 PreToolUse hook、`permissions.allow`、statusline、`agents/`/`commands/` PM 介面)。CC-381 要回答 +「install 該怎麼變成 manifest-driven、host-PM-aware,讓 codex(或未來的 opencode)當主 PM 時也能取得 +等價的 guard/gate plumbing」。本輪 spike 用三個獨立視角並行分析,再由主線程收斂: + +1. **Claude(主線程)**——熟悉本 repo 既有決策脈絡(CC-372/375/380/333)的內部視角。 +2. **Codex(dispatch,read-only isolation)**——對 codex CLI 自身行為有第一手資訊的執行者視角, + brief 見 `/tmp/brief-cc381-analysis-*.md`(run-20260702T063729Z-7c423f,`.dispatch-results/` + 已記錄,`final_state: ok`)。 +3. **ChatGPT(外部第三方)**——不帶專案內部脈絡、用通用架構語彙給的獨立設計判斷,提問稿見對話附件 + `~/github/temp/chatgpt.md`。 + +四個要回答的子問題:host-profile-detection 設計、doctor 擴充切片介面、codex-host 的 guard 落點、 +對 CC-372(runner_kind)/CC-375(manifest 衍生接線)的對齊建議。 + +## Angles + +### Angle 1 — Claude(主線程內部視角) + +- host-profile-detection:顯式旗標優先、`command -v` 只當 fallback;偵測結果寫進 manifest 新欄位 + `host_runtime:`,與 CC-372 `runner_kind` 保持姊妹欄位(正交,不合併)。 +- doctor:核心跑通用檢查+dispatch 到 `doctor-host-.sh` 模組,核心不含 host-specific 邏輯。 +- guard 落點:判斷力最弱的一塊——對 codex 原生 hook 現況沒有第一手資訊,票面本身也標註「可能不完全」, + 這正是該讓 Codex 自己回答的部分。 +- manifest 對齊:延伸 CC-375,加一個 `host_configs:` 區塊,每個 host 描述自己的 target/format。 +- 建議切入順序:先切 doctor 擴充切片(唯讀、風險最小),guard 落點與 manifest schema 留到確認 + codex 原生 hook 能力後再動。 + +### Angle 2 — Codex(dispatch,read-only isolation,第一手技術調查) + +Codex 在唯讀 sandbox 下對本機 codex CLI 做了實測(非單純覆述票面文字): + +- `codex features list` 顯示 `hooks` feature flag 為 **stable 且 enabled**。 +- `codex --help` / `codex exec --help` 暴露 `--dangerously-bypass-hook-trust`,代表 hook 執行是 + CLI runtime 的受信任執行面,不只是文件概念。 +- `codex doctor --json` 顯示 `CODEX_HOME`、`config.toml`、enabled feature flags 含 `hooks`。 +- native binary 字串反查出 hook runtime 事件面:`PreToolUse`、`PostToolUse`、`PermissionRequest`、 + `SessionStart`、`UserPromptSubmit`、`Stop`、`PreCompact`、`PostCompact`,以及 fail-closed 阻擋證據 + 字串 `Command blocked by PreToolUse hook` / `Tool call blocked by PreToolUse hook`。 + +**結論**:codex 原生 hook 足以承接 write/bash guard 的「阻擋型 pre-tool enforcement」,不必退回 +cli-only fallback 當唯一手段。cli-only fallback(`pmctl guard check`)在實務上有三個落差:覆蓋率 +不足(只保護記得呼叫它的 path)、非原子(check 與 exec 分離,`pmctl safe bash` 才是 atomic 版本)、 +無法表達 host trust 狀態(codex 有 hook trust gate,cli-only 無法替代這個 doctor 訊號)。 + +Codex 也不應把「host guard」和「executor adapter guard」混為一談:codex-host 的 PM 自身 action guard +應走 native `PreToolUse`;PM→codex executor 的 dispatch guard 仍維持既有 `write_guard_mode: cli-only` +(`runner_kind: cli-subprocess`),兩條軸正交,不因 codex-host 有 native hook 就改掉 executor adapter +語意。 + +Codex 並給出可直接落地的 host manifest YAML 草案(`install_targets` / `hook_surface` / +`guard_bindings` / `permissions_surface` / `doctor_module` / `uninstall_module`),format handler 為 +少量核心插件:`claude-settings-json`、`codex-config-toml`、`codex-hooks-json`、 +`markdown-managed-block`、`symlink-tree`、`copy-tree`。 + +Doctor 擴充給出具體現況耦合點(`scripts/doctor.sh` 的 `check_settings_file` / `check_hooks` / +`check_dispatch_allowlist` / `check_manifest` 四處寫死 Claude 路徑)與 9 個建議 check slug: +`host..binary` / `.auth` / `.config-file` / `.command-interface` / `.hooks` / `.hook-trust` / +`.permissions-policy` / `.install-manifest` / `.uninstall-parity`。 + +### Angle 3 — ChatGPT(外部第三方,通用架構視角) + +核心設計原則:「installer 核心不理解 A/B/C host 的設定細節,只理解『需要哪些語義能力』;host adapter +負責把能力落地成該 host 的檔案/hook/policy」。 + +- host 偵測:偵測結果應是 confidence model(`high/medium/low` + evidence),而非布林;非互動環境無 + 高信心候選時應 fail 並要求顯式 `--host`。CLI 存在性偵測的坑:只能證明 binary 在 PATH 上,不能證明 + 使用者現在想安裝給它。 +- doctor:借鑑 LSP 的 capability negotiation 精神——doctor 應以 **capability 為中心**(`是否提供 + command_guard?guard 是 blocking/approval/advisory?是否支援 session_end?`),而不是以 host 為中心 + (「A 對不對/B 對不對」)。這特別適合 codex 這種能力還在演進中的 host。 +- guard 落點:不要只用 `guard_mode: hook | cli_fallback` 單一 flag,改用結構化 capability object + (`provider: host_hook | host_policy | cli_wrapper | doc_instruction | none`、 + `enforcement: blocking | approval | advisory | none`、`coverage:`、`stability:`、`confidence: + observed | declared | assumed`)。對「能力不確定/演進中」的 host,用 `declared` / `probed` / + `effective` 三層能力表示,讓能力變好時可以無痛升級、能力不足時優雅降級且明確揭露安全邊界(strong / + medium / limited / advisory 分級)。 +- manifest:manifest 描述靜態事實(路徑/格式/樣板/owned-block marker),複雜判斷(偵測策略、能力 + probe、install plan、doctor checks、migration)留在 adapter code——manifest 不該變成小型程式語言。 + 建議 schema 版本化並用 fixture 測試(`render install plan → apply to temp dir → doctor → uninstall + → doctor again`)。 +- 建議第一刀:不要先做完整 auto-detection 或外部 plugin registry,先做 **A(claude)+B(codex)垂直 + 切片**——定義 4 個核心 desired capability(`command_guard` / `session_lifecycle` / + `pm_command_interface` / `statusline`),把現有 claude installer 包成 `AHostAdapter`,新增 + `BHostAdapter` 但故意先做到 degraded。驗證標準:B host 不需要在 installer 核心加任何 + `if host == B`,且 doctor 能清楚顯示「哪些能力 OK、哪些 degraded、哪些 unsupported」。 + +## Findings + +三方在四個子問題上高度收斂,且互補而非重複: + +| 議題 | 收斂結論 | +|---|---| +| host-profile-detection | 不可沿用 `--profile minimal\|full`(那是「本機有沒有 codex CLI」,不是「現在誰是 host PM」)。需要獨立偵測旗標/env(優先序:旗標 > env > host 自我訊號 > CLI 存在性),非互動環境無高信心候選時應 fail,不可靜默猜錯。 | +| doctor 擴充 | 核心通用檢查 + host-specific 模組,且應以 **capability** 為檢查單位(而非「這個 host 設定對不對」),具體落地用 Codex 給的 9 個 check slug。 | +| guard 落點(最大不確定性) | **已解掉**:Codex 實測證明其 `PreToolUse` hook 是 stable 且會 fail-closed 阻擋,足以承接 write/bash guard;codex-host 應走 native hook,不必退回 cli-only fallback 當主要手段。用 ChatGPT 的 capability object 結構(`provider`/`enforcement`/`coverage`/`stability`/`confidence`)宣告這個結論,比單一 `guard_mode` flag 更誠實,也更適合表達「能力仍在演進」的狀態。 | +| manifest schema | host manifest 必須與 executor adapter manifest(`runner_kind`/`write_guard_mode`)分離、互為姊妹結構,不可合併語意;manifest 存靜態事實(target/format),複雜判斷留在 adapter code。Codex 的 YAML 草案可直接當 schema v1 起點。 | + +最有價值的新發現:Codex 用唯讀 sandbox 做的第一手技術調查,直接解掉了 CC-381 票面標註的「Codex hook +機制可能不完全」這個最大不確定性——不再是停留在猜測,而有具體 CLI 版本、feature flag 狀態、binary +字串證據支撐。 + +## Recommendation + +**Adopt**,並將 CC-381 的下一步從「codex hook 到底行不行」的探索性 spike,收斂為「PreToolUse payload +夠不夠用」的驗證性 spike——因為前者已由 Codex 的唯讀調查回答完畢。 + +第一刀(最小風險、最高信號,唯讀、不動 `install.sh` write path): + +1. 在 `/tmp` 建 throwaway `CODEX_HOME`,配置最小 `PreToolUse` hook 拒絕一個明確 command(例如 + `echo blocked`),用 `codex exec --cd --sandbox workspace-write --ask-for-approval + never` 觸發,確認 payload 中可取得可映射到 `pmctl guard check --file/--command` 的欄位。 +2. 若 payload 足夠 → 產出 `hosts/codex/host.yaml`(以 Codex 給的 YAML 草案為起點,欄位對齊 + ChatGPT 的 capability object 結構:`guard_bindings` 每項附 `provider`/`enforcement`/`coverage`/ + `stability`)。 +3. Doctor 擴充切片可與此並行(風險最低,唯讀性質),用上表 9 個 check slug 當骨架,`scripts/doctor.sh` + 拆出 `check_settings_file`/`check_hooks`/`check_dispatch_allowlist`/`check_manifest` 四處 Claude + 耦合點,改為 host manifest 驅動。 +4. 兩者都驗證完,才動 `install.sh` 的 write path(本票 Non-goals 本就排除這步)。 +5. host manifest 與既有 executor adapter manifest(CC-372 `runner_kind`)保持姊妹結構,不合併; + `write_guard_mode` 繼續只描述 PM→executor 軸語意,不因 codex-host 有 native hook 而改變。 + +## Open risks + +- Codex 的調查是唯讀 sandbox 下的靜態證據(`features list`/`--help`/`doctor --json`/binary 字串), + 尚未實際跑過一次 end-to-end 的 hook 阻擋 + payload 檢視(步驟 1)。第一刀的目的就是把這個剩餘不確定 + 性收斂掉。 +- `--dangerously-bypass-hook-trust` 的存在暗示有 hook trust gate;doctor 的 `host..hook-trust` + check slug 需要先搞清楚 trust 狀態的預設值與使用者互動流程,否則實際安裝後 hook 可能被 trust gate + 擋下而不生效。 +- host-profile-detection 的「非互動環境 fail」策略需要與現有 CI/dispatch 呼叫路徑(`pmctl dispatch + run` 等)核對,避免既有自動化流程因為新增的顯式 host 要求而 regress。 +- opencode 作為第三個 host,本輪三方分析都只用 claude/codex 當具體案例(A/B),opencode 的設定面 + (`opencode.json`)尚未實測,capability object 的 `provider`/`coverage` 欄位可能需要為它新增值。 + +## Next tasks + +- 開一張聚焦的驗證性子 spike/任務:codex PreToolUse payload 欄位驗證(上方「第一刀」步驟 1), + 唯讀、不碰 repo write path。 +- doctor 擴充切片可平行排入(不依賴 guard 落點的驗證結果)。 +- host manifest schema v1 draft(`hosts/codex/host.yaml`)待步驟 1 驗證通過後產出。 +- `install.sh` write path 的實作留待前述都驗證完成後才排期,對齊 CC-381 現有 Non-goals。