起動runtimeはADR 0003、状態管理はADR 0004、互換性境界はADR 0005、ACP versionはADR 0006に記録しています。この文書はそれらの判断を実装するcomponent、状態遷移、data flowを示します。
zcode-acp はprotocol proxyではなく、異なる状態機械を接続するadapterです。外側のACP JSON-RPCを内側のZCode private RPC envelopeへ付け替えるだけでは、prompt完了、permission、cancel、session replayの意味が一致しません。
設計では次を優先します。
- ACP clientからZCode private RPCを隠蔽する
- ZCode official host serviceを公式配布物と同じruntimeで起動する
- capabilityを実装事実から生成する
- 未知の状態やversionを推測で変換しない
- process、workspace、session、promptのライフサイクルを分離する
- 再送による二重ツール実行を防ぐ
flowchart TB
subgraph ClientSide["Client processes"]
Client["Generic ACP Client"]
end
subgraph Adapter["zcode-acp process"]
Acp["ACP v1 server"]
Session["Protocol-neutral session coordinator"]
Mapper["Event / error / permission mapper"]
PM["Official host bridge"]
Discovery["Runtime discovery + compatibility gate"]
Diag["stderr diagnostics"]
end
subgraph Native["Installed ZCode"]
P1["host worker<br/>multi-workspace"]
State["~/.zcode state"]
end
Client <-->|"ACP v1 over stdio"| Acp
Acp <--> Session
Session <--> Mapper
Session <--> PM
Discovery --> PM
PM <-->|"ZCode service RPC"| P1
P1 --- State
Adapter --> Diag
責務:
- stdinからJSON-RPC 2.0 frameを読む
- connection initializationとprotocol version negotiation
- ACP request/notificationのschema validation
- client callback requestの相関
- stdoutへACP frameだけを直列化
責務:
- install rootを一意に解決
- runtime executable、CLI entry、metadataの組を検証
- metadata semanticsとprocess platformを照合
- app versionと
zcode.cjs versionのCLI versionをcurrent manifestと照合 - app buildとmetadata raw SHA-256は診断情報として保持
- CLI SHA-256は公式artifactとの差分として診断するが、host互換性の選択条件にはしない
- artifact固有descriptorからhost index/RPC moduleを解決し、install root内であること、SHA-256、必要な
g/i/jexportを検証 - 起動前の軽量doctor smoke
不一致時はprocessを起動しません。システムNodeや別install rootのCLIへfallbackしません。
責務:
- 公式host workerとRPC channelを一connectionにつき一つ起動
- Electron utility-processのMessagePort shapeをNode workerへ適合
- service method allowlistとstrict result schema
- protocol descriptorのservice channelと意味ベース操作をnative RPCへ変換
- child stdout/stderrをACP stdoutから隔離
- graceful shutdownとforce cleanup
workspace keyは最低でもcanonical absolute cwdから導出します。symlink解決、大文字小文字、存在しないpathの扱いはplatformごとのテストで固定します。
中立コアがbridgeへ渡す操作はcancelGeneration、respondStructuredInput、respondPermissionです。zcode-task-v1 adapterはzcode-task上のstopGeneration / respondElicitation / respondPermissionへ変換します。native taskIdは公開session IDと同じopaque IDですが、parameter名の変換はadapter内だけで行います。
責務:
- private RPC request IDの採番
- 30秒を基準にしたrequest timeout。ただし長時間operationはmethod別timeoutを定義
- response/error/reverse request/notificationの分類
- schema validation
- parse failure時のtransport close
ACP request IDとZCode request IDを同一視せず、相関mapで結びます。
責務:
- 外側protocolのsession IDとして公開するnative ZCode session IDとworkspace keyのbinding
- promptごとの状態機械
- subscribe開始とevent sequenceの管理
- cancel、permission、user inputのpending state
- ACP responseを返せる終端条件の判定
責務:
- native eventからACP
session/updateへの意味変換 - native終端理由からACP StopReasonへの変換
- permission optionsのlossless bridge
- native errorからACP JSON-RPC errorへの変換
_meta.zcodeに入れてよい非secret metadataの選別
| 属性 | 外側: ACP v1 | 内側: ZCode Protocol |
|---|---|---|
| transport | stdio | stdio |
| framing | UTF-8、1 JSON value/line | UTF-8、1 JSON object/line |
| envelope | JSON-RPC 2.0 | 独自RPC、jsonrpcなし |
| request ID | JSON-RPC ID | 数値、native clientが採番 |
| server callback | ACP client methods | interaction/* reverse request |
| schema | 公開・versioned | private・app version依存 |
| completion | v1 prompt responseのStopReason | native session events/state |
同じNDJSONであることは互換性を意味しません。transport reader/writer、schema、pending request mapを両側で完全に分離します。
- ACP clientが
zcode-acpをspawnする initializeを受信する- ACP versionを選択し、実装済みcapabilityだけを返す
session/newのabsolute cwdを検証する- runtime discoveryとcompatibility gateを実行する
- host bridgeがなければ公式host workerを起動する
- native workspace/sessionを作成する
- subscription確立後にACP sessionを返す
childをinitialize時に無条件起動しないことで、version mismatchのconnectionではZCodeを起動せずに済みます。ただしdoctorで事前検証できるようにします。
sequenceDiagram
participant C as ACP Client
participant A as zcode-acp
participant Z as ZCode host service
C->>A: session/prompt
A->>Z: dynamic event subscribe
Z-->>A: backlog/snapshot + live boundary
A->>Z: sendPrompt
loop Native events
Z-->>A: session event
A-->>C: session/update
end
opt Permission required
Z->>A: permission.request
A->>C: session/request_permission
C-->>A: selected option
A-->>Z: native response
end
Z-->>A: terminal event/state
A-->>C: session/prompt response with StopReason
dynamic subscriptionをsendPromptより先に確立し、send直後のeventを取りこぼさないことが必須です。snapshotとlive eventは公式hostのdelivery boundaryを保持します。
ACP session/cancel はnotificationです。受信後は意味操作cancelGenerationを一度だけ送り、選択済みhost protocolが対応するnative stop methodへ変換します。pending permission/user input callbackもcancelします。native eventが既にpipe上にある可能性があるため、終端eventまでは順序を保って処理し、その後prompt responseを cancelled で完了します。
- 新規ACP request受付を停止
- pending ACP requestを規定error/cancelで完了
- native stdinを閉じる
- child exitを待つ
- timeout時にprocess group/treeを終了
- stdout writerをflushして終了
active promptを新childへ自動再送しません。ツールが既に実行済みか判定できず、二重変更を起こすためです。
created -> initialized -> shutting_down -> closed
initialize 前のsession method、二重initialize、closed後のrequestはprotocol errorです。
absent -> starting -> ready -> stopping -> absent
\-> failed
failed childはactive sessionへ透過再接続しません。次の明示操作で新childを作る場合も、native resumeが成功してからsessionをreadyへ戻します。
idle -> subscribing -> sending -> running -> completing -> idle
| |
| +-> cancelling -> completing
+-> awaiting_permission
+-> awaiting_user_input
同一sessionにつきactive promptは一つです。second promptはqueueせずrejectします。暗黙queueはclientのcancel/ordering期待を曖昧にするためです。
native createSession が返すopaqueなZCode session IDをACP session IDとしてそのまま返します。load/resumeでも同じIDをZCode hostへ渡すため、process再起動を越えるadapter mappingは不要です。loadは履歴をreplayし、resumeは履歴をreplayしません。
adapterは常に sessionId -> workspaceKey bindingを保持し、別cwdからのresumeやpromptを拒否します。
- ACP stdout writerは一つのqueueでserializeする
- native stdout frameは受信順に処理する
- session内eventはsequence/event IDで順序検証する
- 異なるworkspaceの処理は並行可能
- 同一sessionのpromptは直列
- reverse request responseはrequest ID単位でexactly once
- timeout後に届いたresponseはlate responseとして破棄し、別requestへ再利用しない
- unsupported ACP version: initialize応答後に明示終了
- invalid cwd: session/new error
- unauthenticated ZCode: action付きerror
- client permission cancel: promptのcancelled終端
- native stdout parse/schema error
- child unexpected exit
- 未知のevent type/schema
- reverse requestの未知method
- provider runtime headersを正しく適用できない
これらを「空応答」や end_turn に丸めません。
推奨module依存は次です。
cli
└─ acp-server ── session-coordinator
└─ zcode-runtime
├─ zcode-protocol
└─ runtime-discovery
zcode-protocol はACP型へ依存させず、acp-server はZCode bundle pathを直接扱いません。private protocol更新とACP更新を別々にテストできる境界にします。
製品を特定clientから分離する理由はADR 0002に記録しています。agentclientprotocol/codex-acp は、外部app-serverをACPへ変換するTypeScript実装として構造上の参考にしました。特に次の分離を参照しています。
- app-server client
- ACP session connection
- event/tool/approval mapper
- JSON-RPC connection
- fake/e2e tests
ただしCodex app-serverとZCode private RPCのmethod・event・approval semanticsは異なります。クラス名や変換ロジックを機械的に移植しません。