RPC ソケットトランスポート
デーモンは、ローカルIPCストリーム(Unixではドメインソケット、Windowsでは名前付きパイプ)上でJSON-RPC 2.0インターフェースを公開します。これは、zerocodeのようなローカルクライアントの主要なトランスポートです。HTTP/WSゲートウェイは、Webhook、Webダッシュボード、およびリモートRESTコンシューマー向けに引き続き利用できます。
エンドポイントの解決
各データディレクトリには独自のエンドポイントが割り当てられるため、同一マシン上で複数のデーモンインスタンスが衝突することはありません。データディレクトリは設定ディレクトリ(--config-dir / ZEROCLAW_CONFIG_DIR、または ZEROCLAW_DATA_DIR)から導出されます。
| OS | デフォルトエンドポイント |
|---|---|
| Linux | <data_dir>/daemon.sock(Unix ドメインソケット) |
| macOS | <data_dir>/daemon.sock(Unix ドメインソケット) |
| Windows | \\.\pipe\zeroclaw-<hash>(<hash> は data_dir から導出されます) |
どちらのプラットフォームでも ZEROCLAW_SOCKET 環境変数で上書きできます:
sh
export ZEROCLAW_SOCKET=/tmp/my-zeroclaw.sock
zeroclaw daemon
PowerShell
$env:ZEROCLAW_SOCKET = '\\.\pipe\my-zeroclaw'
zeroclaw daemon
ワイヤープロトコル
NDJSON(改行区切りJSON)。各行は完全なJSON-RPC 2.0メッセージです。HTTPフレーミングや長さプレフィックスはありません。フレーミングはすべてのプラットフォームで同一です。名前付きパイプはUnixソケットと同じバイトストリームを伝送します。
{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":1},"id":1}\n
{"jsonrpc":"2.0","result":{"protocolVersion":1,"serverVersion":"0.8.6"},"id":1}\n
接続数の上限
このローカルエンドポイントが、1つのクライアントが保持できる量に上限を設けています:
| |Limit 上限| |-| | 値 | クライアントに表示される内容 |
|---|---|---|
| フレームサイズ | 8 MiB/行 | |One -32600 error with id: null and data: {"reason": "frame_too_large", "limit_bytes": 8388608}, then end of stream. The rest of the oversized line is never read, so the connection cannot continue. |
Wait, that’s not what I should output. Let me translate properly.
ストリームの終端まで、id: null と data: {"reason": "frame_too_large", "limit_bytes": 8388608} を含む -32600 エラーが1件返されます。超過したラインの残りは読み取られないため、接続は継続できません。|
||Initialize 初期化| |-||接続から30秒|接続が確立されてから30秒以内にinitializeを完了しなかった場合、その接続は応答なしで切断されます。そのため、接続して何も送信しないクライアントが接続スロットを占有し続けることはありません。この期限は認証処理にも適用されます。期限内に送信されたinitializeであっても、期限を過ぎた時点で認証(たとえばOIDCの確認処理に時間がかかる場合)がまだ実行中であれば、その接続は遅れて受け入れられるのではなく、切断されます。|
||Unfinished frame 未完成のフレーム| |-||30秒、フレームの最初のバイトから||Once a frame starts, the whole line must arrive within 30 s of its first byte, however steadily the rest arrives. Past that the client receives one -32600 error with id: null and data: {"reason": "frame_timeout", "limit_ms": 30000}, then end of stream. The wait between frames is not bounded, so an initialized client may stay idle.
Wait—that’s the source text, which is English. Translating it:
フレームが開始されると、行全体は最初のバイトから30秒以内に到着しなければならず、残りがどれほど安定して届いていてもこの制限は変わりません。この時間を過ぎると、クライアントはid: nullとdata: {"reason": "frame_timeout", "limit_ms": 30000}を含む-32600エラーを1つ受け取り、その後ストリームが終了します。フレーム間の待機時間には上限がないため、初期化済みのクライアントは無期限にアイドル状態のままになることがあります。|
|書き込みストール|30 s/フレーム|クライアントが、デーモンに送信待ちの出力がある状態で30秒間読み取りを止めると、そのクライアントは切断されます。他の接続には影響しません。切断されると、その接続が開始したターンはすべて終了します。これは他の切断の場合と同じです。中断されたクライアントも対象になります。Ctrl-Zで停止された、またはCtrl-Sで凍結された zerocode で、ストリーミング中のターンがある場合、そのターンは30秒後にキャンセルされます。以前は、クライアントが再開すると完了していました。|
|接続を開く|rpc.max_local_connections、デフォルト 512|接続が上限を超えると、id: null と data: {"reason": "connection_limit", "limit": N} を含む -32004 エラーが1件返され、その後ストリームが終了します。デーモンは接続の受け付けを拒否し始めたときに警告を1件ログに記録します。この値はリスナーの起動時に読み込まれます。|
フレームより大きいペイロードは、1行で送信されるのではなく、チャンク分割アップロードとして送信されます。詳しくは Chunked uploads を参照してください。
ハンドシェイク
最初のRPC呼び出しは必ず initialize でなければなりません。デーモンは initialize が成功するまで、他のすべてのメソッドを拒否します。プロトコルバージョンの不一致は、コード -32011 の構造化エラーを生成します。
{
"jsonrpc": "2.0",
「method」: 初期化,
"params": {
protocolVersion: 1
},
"id": 1
}
エンドポイントはペアリングトークンを必要としません。アクセス制御はオペレーティングシステムによって処理されます:
- Unix: ソケットは
0o600、親ディレクトリは0o700。 - Windows: 名前付きパイプの ACL は、作成したユーザーと
SYSTEMがデフォルトになります。
メソッド
| 方法 | 方向 | 説明 |
|---|---|---|
initialize | client -> daemon | 認証してプロトコルバージョンをネゴシエートする |
session/new | client -> daemon | エージェントセッションを作成します(agentAlias は必須、cwd と sessionId は省略可能)。sessionId がすでに稼働中のIDの場合、エージェント履歴を置き換えるのではなく、呼び出し元を正規のインメモリセッションに再バインドします。呼び出し元が現在の権限のもとで利用できる転送環境が、そのセッションの作成時のものと異なる場合は、FORBIDDEN で拒否されます。省略可能な keep_siblings を指定すると、セッションのライフサイクルを自ら管理するマルチセッションクライアント向けに、アイドル状態の同一モードの兄弟セッションの退避を行わないようにします。 |
session/close | client -> daemon | ライブセッションの所有者を削除しても、ACPの永続的な履歴は再開可能なまま残ります |
session/kill | client -> daemon | ライブセッションを削除し、その ACP の永続履歴にトゥームストーンを付与する |
session/delete | client -> daemon | ライブセッションと、選択された永続履歴を削除 |
session/prompt | client -> daemon | ターンを実行(session/update 通知経由でストリーミング) |
session/cancel | client -> daemon | 進行中のターンをキャンセルする |
session/state | client -> daemon | |Read live session lifecycle state, active turn identity, and the optional current plan; active or queued work is represented by state: "running" so recovery clients can confirm terminal status before releasing retained work ライブセッションのライフサイクル状態、アクティブなターンの識別情報、およびオプションの現在のプランを読み取ります。アクティブまたはキュー待ちの作業は state: "running" で表され、リカバリクライアントが保持中の作業を解放する前に終了状態を確認できるようにします。| |-| |
status | client -> daemon | サーバーバージョン、プロトコルバージョン、アクティブセッション一覧 |
file/upload/begin, file/upload/chunk, file/upload/commit | client -> daemon | 順番に分割して1つのファイルをアップロードします。チャンクアップロードを参照してください。 |
session/update | デーモン → クライアント | ターン中のストリーミング通知(テキストチャンク、ツール呼び出し、承認) |
elicitation/create | デーモン → クライアント | ask-user と poll フローの対話型入力を要求する |
アトミックな設定の書き込み
config/set-many は、1〜256 個のオブジェクトを含む順序付きの sets 配列を受け付けます。各オブジェクトは prop と value を持ちます。config/set と同じプロパティ構文と値の規則を使用します。たとえば、operator という名前の権限プロファイルを作成した後、管理者は 1 回のリクエストで完全なユーザーを作成できます:
{"jsonrpc":"2.0",「method」:config/set-many,"params":{sets:[{prop:users.example.uid,"value":1001},{prop:users.example.permission_profiles,"value":[演算子]}]},"id":2}
成功時は {"props":["users.example.uid","users.example.permission_profiles"],"set":true} を返します。すべてのフィールドは1つの候補にステージングされ、1回の永続的なコミットの前に検証されます。同じプロパティに対する後のエントリが優先されます。ステージングまたはコミットの失敗時には、永続化された設定とライブ設定はいずれも変更されません。無効なエントリのエラーでは、0始まりのインデックスが示されます。
呼び出し元にはConfig:Update権限と、要求されたすべてのパスに対する認可が必要です。デーモンは設定の書き込みロックを保持した状態で、いずれのエントリもステージングする前に現在の権限を解決します。いずれかのパスが禁止されている場合、先行するパスが許可されていても、エントリのインデックスを含めてバッチ全体がFORBIDDENで拒否されます。そのロックの待機中に権限が取り消された場合も、バッチは拒否されます。Provider/modelビューは完全な候補から準備され、コミットが成功した後にインストールされます。削除およびマップキー操作は、このメソッドの対象外です。
双方向リクエスト
どちらの側からでも、確立済みのソケット上でリクエストを送信できます。受信側は同じ id を使用し、result または error のいずれか一方だけで応答する必要があります。各ピアは送信リクエストに対して独自の zc-out-<number> シーケンスを使用します。このプレフィックスはグローバルに一意な名前空間ではありません。相関は方向ごとに行われます。各ピアは自身の保留中リクエストのマップに対してのみ応答を照合するため、同じ文字列の ID が反対方向で独立して処理中になる可能性があります。
{"jsonrpc":"2.0",「method」:"elicitation/create","params":{"message":"続行しますか?"},"id":zc-out-0}
{"jsonrpc":"2.0","result":{"action":"accept","内容":{回答:"はい"}},"id":zc-out-0}
明示的な "result": null は成功応答であり、保留中の呼び出し元も解決されます。error オブジェクトの場合は、失敗として解決されます。ピアが応答しない場合、開始した ask-user または poll 操作では、従来のタイムアウト動作が維持されます。
すべてのフレームは、"jsonrpc": "2.0" を含む JSON オブジェクトでなければなりません。リクエストには文字列の method が必要です。params が存在する場合は、オブジェクトまたは配列でなければなりません。レスポンスには文字列、数値、または null の id と、レスポンスメンバーが正確に 1 つ必要です。無効な JSON では -32700(解析エラー)が生成されます。不正なリクエスト形式のエンベロープでは -32600(無効なリクエスト)が生成され、復元できる場合は有効なリクエスト ID が使用されます。不正なレスポンス形式のエンベロープは、フレームの内容をログに記録せずに破棄され、返信も行われません。これは、その ID をエコーすると、反対方向にある無関係なリクエストを完了させてしまう可能性があるためです。方向を判別できないエンベロープでは id: null を使用します。未知の有効なレスポンス ID も同様にログに記録して無視し、応答は返しません。これによりレスポンスループを防ぎます。
ストリーミングをオンにする
session/prompt はターンが完了すると最終結果を返します。実行中、デーモンは増分イベントを含む session/update 通知を送信します。
{"jsonrpc":"2.0",「method」:"session/update","params":{"sessionId":"...","type":agent_message_chunk,"text":こんにちは}}
{"jsonrpc":"2.0",「method」:"session/update","params":{"sessionId":"...","type":"ツール呼び出し","toolCallId":tc_1,"name":bash,rawInput:{...}}}
{"jsonrpc":"2.0",「method」:"session/update","params":{"sessionId":"...","type":"ツール結果","toolCallId":tc_1,"name":bash,rawOutput:"..."}}
イベントタイプ: agent_message_chunk、agent_thought_chunk、tool_call、tool_result、approval_request。
ACP durable lifecycle
ネイティブRPCは、元の表示用トランスクリプトを、保持されたプロバイダーコンテキストから分離して管理します。自動トリミングでは、元のトランスクリプトの行を削除したり、番号を振り直したりしません。トリミング通知は、保持コンテキストのスナップショットと対象となるチェックポイント境界が一緒にコミットされた後にのみ送信されます。書き込みに失敗した場合、通知は抑制されます。スナップショットには、ランタイムのシステムプロンプト、想起されたメモリの注入、非表示の推論は含まれません。中断時には、回復処理で表示可能なチェックポイントの進捗を1回だけ追記しつつ、最新の保持スナップショットとその後のチェックポイントイベントからモデルを復元します。明示的に空の保持スナップショットも有効な状態として扱われます。スナップショットが存在しないセッションでは、従来のプロバイダーに安全なリプレイ経路を引き続き使用します。
ACP セッションは、終端状態に達する前に永続的な履歴を保持できます。インメモリのオーナーが回収されると、RPC プロンプトのリカバリは、永続化された interaction_surface がサポートされている永続行のみを対象とします。サポートされていない surface は変更されずに残されるため、後の直接リカバリで元のチェックポイントを確認できます。
Recovery は、未完了のターンに対してクライアントに表示される中断マーカーを追加します。プロバイダーへのリプレイではこの合成マーカーを除外し、永続化されたツール出力は既存のトランスクリプトの上限の対象となります。
ライフサイクル操作には、それぞれ異なる永続的な意味があります:
session/closeは、再開可能な履歴を永続的に保持する場合があります。session/killは履歴を保持しますが、行を tombstone としてマークするため、ランタイムでの再ハイドレーションの対象にはなりません。session/deleteは、対象が稼働中の ACP セッションである場合、または稼働中のモードが存在せず ACP の永続行が選択されている場合に、稼働中のセッションを登録解除して削除する前に、ACP の行と復元可能なチェックポイントを削除します。同じ ID を持つ稼働中の Chat セッションは ACP のストレージから分離されたままです。
「kill」および「delete」のシグナルキャンセルを、失敗する可能性のある SQLite 操作を試行する前に実行します。その操作がアイドル状態の対象に対して失敗した場合、RPC は内部エラーを報告し、生存している owner と channel 登録は維持されます。ハードキャンセルによってアクティブな owner がすでに削除されている場合、RPC はその生存している generation を復元できません。ただし、ストレージが再び利用可能になれば、永続化された行と復旧可能なチェックポイントは引き続き利用できます。
チャンクアップロード
file/attach は1つのフレームでファイル全体を送信するため、base64エンコード後のサイズを含めると、ファイルごとの上限よりかなり手前で制限に達します。file/upload/begin、file/upload/chunk、file/upload/commit は同じアップロードを分割して送信し、file/attach と同じく、セッションエージェントのワークスペースに、そのコンテンツハッシュの下、セッションごとに重複排除された状態で保存されます。結果には同じマーカーが付与されます。
file/upload/beginにsession_id、size_bytes、および任意でfilenameとsha256(16進数)を渡します。結果としてupload_id、chunk_bytes(1 MiB)、max_bytes(ファイルごとの上限10 MB)が返されます。file/upload/chunkにupload_id、offset、data_b64を、この順序で渡します。offsetは、これまでに受信済みのバイト数と一致している必要があります。結果ではreceived_bytesが報告されます。受理済みのチャンクを同じバイト列で再送すると、変更なしとして確認応答されるため、応答が失われた場合にクライアントは再試行できます。file/upload/commitを、宣言されたすべてのバイトが到着した後にupload_idとともに呼び出します。宣言されたsha256が一致している必要があります。結果はfile/attachのファイルエントリになります。
An upload belongs to the connection that began it: no other connection can name it, and it is discarded when that connection closes. The limits:
Wait, I need to translate this into Japanese, not repeat the source. Here is the translation:
アップロードは、それを開始した接続に属します。他の接続がそのアップロードを指定することはできず、その接続が閉じられると破棄されます。制限は次のとおりです:
-
接続は一度に4つのアップロードをステージできます。
-
デーモンは全接続を合わせて最大256 MiBまでステージングします。この上限への計上は、各アップロードのペイロードと、それが保持するメタデータ(セッションID、所有者、エージェント、ファイル名、宣言されたハッシュ)の両方を対象とするため、空のペイロードでメモリを無料で占有することはできません。
filenameが255バイトを超える場合は拒否されます。 -
An upload idle for five minutes is discarded. When a new upload does not fit in the budget, the daemon first reclaims every upload idle past that deadline, even one whose connection is still open, so a silent client cannot hold the budget.
Wait, I should be careful: the system prompt says to translate to ja, and the source is English technical documentation. So translation is the task. Here is the Japanese translation.
5分間アイドル状態が続いたアップロードは破棄されます。新しいアップロードが予算に収まらない場合、デーモンはまず、その期限を過ぎてアイドル状態にあるすべてのアップロードを回収します。接続がまだ開いているものも対象です。これにより、無言のクライアントが予算を占有し続けることを防ぎます。
3つのメソッドはローカル接続でのみ提供されます。WSS ピアが呼び出すと -32012 を受け取ります。これらには files:create の付与が必要です。また begin は、プリンシパルがセッションの所有者であること(admin を持たないプリンシパルの場合)と、セッションのエージェントを使用できることを確認します。
アップロードは、開始時に対象としたセッションに厳密に紐づけられます。具体的には、そのIDを持つ稼働中のセッション、そのオーナー、そのエージェントです。commit は、セッションロックの下で一度の処理によってアップロードを保存します。まず、そのセッションが依然として同一であることを確認し、次にその時点で有効なポリシーに照らして、呼び出し元の認証情報、files:create、セッションの所有権、エージェントの利用権限を検証します。その後にのみファイルを書き込み、インデックスに登録します。アップロードの処理中に権限付与が取り消された場合、または同じIDのセッションが終了もしくは再作成された場合、何も書き込まれる前に commit は失敗します。検証と書き込みの間は、受理済みの認可ポリシーとペアリング済みトークンの集合を固定します。そのため、検証の完了後に到着したポリシー変更またはペアリング解除は、ファイルが保存された後にのみ反映されます。つまり、アップロードはそれより前に順序付けられ、検証と書き込みの間に割り込むことはありません。file/attach も同じ手順を通じて保存され、同じ所有権の要件が課されます。
アップロードされたファイルが既にインデックス済みの場合、その再送は、ディスク上のファイルと照合されます。ファイルが編集・削除・リンクによって置き換えられていた場合、返却前にアップロードされたバイト列がインデックス済みのパスに書き戻されます。
一時モード
zeroclaw daemon --ephemeral は接続中のクライアントを追跡し、最後のクライアントが切断されると自身を終了します(1秒の猶予期間の後)。猶予期間中に再接続するとシャットダウンはキャンセルされます。デーモンは少なくとも1つのクライアントが接続するまで終了しません。
--ephemeral を指定せずに起動したデーモンは、クライアント数を無視し、明示的に停止されるまで実行され続けます。
セキュリティ
- Unixソケットディレクトリ:
0o700(所有者のみ) - Unixソケットファイル:
0o600(所有者のみ) - Windows 名前付きパイプ: デフォルトの ACL は作成ユーザーと
SYSTEMにアクセス権を付与します SO_PEERCREDは Linux において、監査ログ用に接続元プロセスの PID と UID を提供します。Windows ではピアラベルとしてpipe:localがログに記録されます
クイックテスト
デーモンを1つのターミナルで起動します:
sh
zeroclaw daemon
2 つ目のターミナルで Unix を使用している場合は、socat で接続します:
sh
socat READLINE UNIX-CONNECT:~/.zeroclaw/data/daemon.sock
行を1行ずつ貼り付けてください:
{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":1},"id":1}
{"jsonrpc":"2.0","method":"status","params":{},"id":2}
Windowsでは、任意の名前付きパイプクライアント(PowerShellの[System.IO.Pipes.NamedPipeClientStream]、WSL経由のnc、または単にzerocodeを実行)を使用してください。
内部構造
ディスパッチ層は crates/zeroclaw-runtime/src/rpc/ にあります:
| ファイル | 役割 |
|---|---|
transport.rs | RpcTransport トレイト |
turn.rs | execute_turn() 共有ターン実行プログラム |
session.rs | RpcSession, SessionStore |
dispatch.rs | RpcDispatcher メソッドルーティング |
local.rs | LocalTransport + リスナー(Unix ソケット / Windows 名前付きパイプ) |
wss.rs | WSS (WebSocket Secure) トランスポート + TLS アクセプター |
attachments.rs | ファイルアップロード処理、重複排除、マーカー生成 |
upload.rs | Chunked upload のステージング: 順序保証、接続ごとの上限、プロセス全体の上限 |
RpcTransportトレイトは、追加のトランスポート(vsock、カスタムIPC)をディスパッチやセッションのロジックに手を加えることなく組み込めるように設計されています。local.rsモジュールは、tokio::io::splitを使用して、UnixとWindowsのプリミティブを単一のLocalTransport構造体の背後にラップするため、読み取り/書き込みループは両プラットフォーム間で共有されます。