Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RPC Socket Transport

The daemon exposes a JSON-RPC 2.0 interface over a local IPC stream, a Unix domain socket on Unix and a named pipe on Windows. This is the primary transport for local clients like zerocode. The HTTP/WS gateway remains for webhooks, the web dashboard, and remote REST consumers.

Endpoint resolution

Each data directory gets its own endpoint, so multiple daemon instances on the same machine do not collide. The data dir is derived from the config dir (--config-dir / ZEROCLAW_CONFIG_DIR, or ZEROCLAW_DATA_DIR).

OSDefault endpoint
Linux<data_dir>/daemon.sock (Unix domain socket)
macOS<data_dir>/daemon.sock (Unix domain socket)
Windows\\.\pipe\zeroclaw-<hash> where <hash> is derived from data_dir

Override with the ZEROCLAW_SOCKET environment variable on either platform:

sh

export ZEROCLAW_SOCKET=/tmp/my-zeroclaw.sock
zeroclaw daemon

PowerShell

$env:ZEROCLAW_SOCKET = '\\.\pipe\my-zeroclaw'
zeroclaw daemon

Wire protocol

NDJSON (newline-delimited JSON). Each line is a complete JSON-RPC 2.0 message. No HTTP framing, no length prefix. The framing is identical across platforms; named pipes carry the same byte stream as Unix sockets.

{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":1},"id":1}\n
{"jsonrpc":"2.0","result":{"protocolVersion":1,"serverVersion":"0.8.1"},"id":1}\n

Handshake

The first RPC call must be initialize. The daemon rejects all other methods until initialize succeeds. Protocol version mismatch produces a structured error with code -32011.

{
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "protocolVersion": 1
  },
  "id": 1
}

The endpoint does not require a pairing token. Access control is handled by the operating system:

  • Unix: socket is 0o600, parent directory is 0o700.
  • Windows: named pipe ACL defaults to the creating user and SYSTEM.

Methods

MethodDirectionDescription
initializeclient -> daemonAuthenticate and negotiate protocol version
session/newclient -> daemonCreate an agent session (requires agentAlias, optional cwd, sessionId)
session/closeclient -> daemonClose and clean up a session
session/promptclient -> daemonRun a turn (streamed via session/update notifications)
session/cancelclient -> daemonCancel an in-flight turn
statusclient -> daemonServer version, protocol version, active session list
session/updatedaemon -> clientStreaming notification during a turn (text chunks, tool calls, approvals)

Turn streaming

session/prompt returns the final result when the turn completes. During execution, the daemon sends session/update notifications with incremental events:

{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"...","type":"agent_message_chunk","text":"Hello"}}
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"...","type":"tool_call","toolCallId":"tc_1","name":"bash","rawInput":{...}}}
{"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"...","type":"tool_result","toolCallId":"tc_1","name":"bash","rawOutput":"..."}}

Event types: agent_message_chunk, agent_thought_chunk, tool_call, tool_result, approval_request.

Ephemeral mode

zeroclaw daemon --ephemeral tracks connected clients and self-terminates when the last one disconnects (after a 1-second grace period). A reconnect during the grace period cancels the shutdown. The daemon will not exit until at least one client has connected.

Daemons started without --ephemeral ignore client count and run until explicitly stopped.

Security

  • Unix socket directory: 0o700 (owner only)
  • Unix socket file: 0o600 (owner only)
  • Windows named pipe: default ACL grants the creating user and SYSTEM
  • SO_PEERCRED on Linux provides the connecting process PID and UID for audit logging; Windows logs pipe:local as the peer label

Quick test

Start the daemon in one terminal:

sh

zeroclaw daemon

In a second terminal on Unix, connect with socat:

sh

socat READLINE UNIX-CONNECT:~/.zeroclaw/data/daemon.sock

Paste lines one at a time:

{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":1},"id":1}
{"jsonrpc":"2.0","method":"status","params":{},"id":2}

On Windows, use any named-pipe client (PowerShell [System.IO.Pipes.NamedPipeClientStream], nc via WSL, or just run zerocode).

Internals

The dispatch layer lives in crates/zeroclaw-runtime/src/rpc/:

FileRole
transport.rsRpcTransport trait
turn.rsexecute_turn() shared turn executor
session.rsRpcSession, SessionStore
dispatch.rsRpcDispatcher method routing
local.rsLocalTransport + listener (Unix socket / Windows named pipe)
wss.rsWSS (WebSocket Secure) transport + TLS acceptor
attachments.rsFile upload processing, dedup, marker generation

The RpcTransport trait is designed so that additional transports (vsock, custom IPC) slot in without touching the dispatch or session logic. The local.rs module wraps the Unix and Windows primitives behind a single LocalTransport struct using tokio::io::split, so the read/write loop is shared across both platforms.