[design] エージェント活動 capture 機構 ── ACP / OTel / transcript を AgentRun に正規化 汎用評価層(n_01KT3C0Q…)の α(grounding 基盤)を「**どのレイヤーで活動を capture するか**」調査した結論(2026-06-02、user alignment 済 / 実装前。末尾に ① 反映追記)。 ## 核心: capture / usage / store は別レイヤー(混同しない) | 層 | 役目 | 手 | |---|---|---| | 行動 capture | 何をしたか(tool 呼び出し・plan・stop) | ACP(均一・full)/ Claude は transcript | | usage | token | OTel / Claude は transcript の `usage` | | cost | コスト | **token から自前計算**(ACP も OTel も標準化してない) | | store / 解析 | 永続 + post と join | quacker-native AgentRun | 前回 framing の「OTel vs 自前」は capture 層と store 層の混同だった。OTel は「行動 capture」でなく「usage」の答え。行動 capture の本命は ACP。 ## ACP(行動)findings - client↔agent の JSON-RPC/stdio。`session/update` に tool_call(`rawInput`/`rawOutput`/`kind`/`status`/触ったファイル位置)/ plan / thought / stopReason。 - **4 ランタイムを 1 client で均一駆動できる**: goose(native)/ Gemini(native)/ Claude(`@agentclientprotocol/claude-agent-acp`)/ Codex(`zed-industries/codex-acp`)。 - **取れない: token / cost / model**(RFD 止まり・主要ランタイム未実装)。 - driver-coupled。pre-1.0(v0.13.5)/ Zed 単独ガバナンス。 ## OTel(usage)findings - token / duration は取れるが ── cost 非標準 / tool I/O は opt-in + 截断 / 横断は方言バラバラ(Claude=独自 `claude_code.*`、Codex `exec` は metrics ゼロ)で正規化層要 / collector 要 / experimental。 ## 結論 = per-runtime best-available を 1 AgentRun に正規化する normalizer | ランタイム | 行動 | token | 組み合わせ | |---|---|---|---| | Claude(bg/main) | transcript | transcript `usage` | transcript 1 本で両方 | | goose | ACP tool_call | goose OTel | ACP + OTel | | Codex headless | ACP tool_call | ✗(codex exec metrics 無) | ACP のみ、token 穴 | | cost | — | token から計算 | 共通 | = Langfuse 型「多方言 ingest → 1 内部モデル」を独立に再導出。 ## 構成 - quacker-channel を**汎用 ACP client** 化(`goose_acp.rs` を一般化、既に goose ACP client、spawn コマンドを registry 化)。 - dispatcher(`acp_dispatch.rs`)が turn 前後で AgentRun event を emit。 - **`posts_read` = bridge --proxy chokepoint で捕る**(下記 ① 反映で更新 ── 旧「ACP tool_call rawOutput / transcript」より確実)。 - store = strand-3 ブループリント(`AgentRun` aggregate / event / projection)。 ## サポート範囲の境界 - ACP がきれいに統一するのは goose / Codex(ACP-native worker)。 - **Claude は ACP でフル機能で駆動できる(parity 確認済、`claude-agent-acp` が settingSources + claude_code preset で skills/hooks/MCP/CLAUDE.md ロード)。adapter スコープ外は auto-worktree + bg lifecycle のみ(quacker-channel が既に持つ orchestration)。** - **それでも Claude は transcript レーンが優(選択)**: transcript が行動 + token を 1 本でくれる。ACP の旨味は transcript 等価物が無い goose/Codex 側。 - = capture は 2 レーン(ACP worker / transcript Claude)、store は 1 つ(AgentRun)。 ## ① 反映:posts_read = proxy chokepoint / E2E は moot(2026-06-02 実コード検証) 未解決 (a)(posts_read が ACP tool_call として surface するか)を実コード検証 → **ACP tool_call に賭けなくてよい**と判明: - dispatched ACP agent も main session も **quacker を読むのは全部 `bridge --proxy` 経由**(`goose_acp.rs` が `<self> bridge --proxy` を MCP として渡す)。proxy は run_sql 結果の**全 row を iterate して `id` にアクセス**(`decrypt_row_if_encrypted`)。 - → **`posts_read` = proxy chokepoint で捕る**(run_id を env で渡す、`QUACKER_CHANNEL_DATA` と同じ inject)。ランタイム横断 uniform、ACP raw I/O 有無に非依存。 - ACP tool_call stream は**非 quacker 活動(file 編集 / bash / plan / stop)**の source として残す(「ACP raw I/O を運ぶか」は full-trace tier で実機検証、posts_read には非ブロッカー)。 - 未解決 (b)(E2E)も **moot**: `id` は暗号化 post でも平文(`body` のみ暗号化)→ 復号できなくても posts_read は surface。E2E 復号は dispatched agent が**本文**を読む必要がある場合の別 fix(`XDG_RUNTIME_DIR` を ACP env に inject、capture と分離)。 ## 実装上の注意 ACP stream と OTel trace を後で突合するには共通 `run_id`(駆動側 quacker-channel が振る)。 ## 由来 汎用評価層(n_01KT3C0Q…)の α grounding を「どこに保存するか」が log 方針一般化(n_01KT47S86…)に発展。本 note = capture(どう取るか)。