CrabTalkCrabTalk

Protocol

The wire protocol between CrabTalk clients and the daemon — protobuf over UDS or TCP.

The daemon communicates with clients over a length-prefixed protobuf protocol. Every interaction — sending a message, streaming a response, managing sessions, installing packages — is a ClientMessage / ServerMessage pair over a Unix domain socket (or TCP on Windows).

If you're building a client, this is your contract with the daemon.

Transport

The wire format is simple: [u32 BE length][protobuf payload]. Maximum frame size is 16 MiB.

TransportWhenPath / Port
Unix domain socketmacOS, Linux~/.crabtalk/run/crabtalk.sock
TCPWindows, or --tcp flagPort from ~/.crabtalk/run/crabtalk.port

Connect, send ClientMessage frames, receive ServerMessage frames. Each connection gets its own reply channel.

Sending a message

The simplest interaction — send a message to an agent and get a complete response:

// Client sends:
message SendMsg {
  string agent = 1;        // agent name, e.g. "crab"
  string content = 2;      // the message
  optional uint64 session = 3;  // resume a session, or omit for latest
  optional string sender = 4;   // client identity, e.g. "telegram-12345"
}

// Server responds:
message SendResponse {
  string agent = 1;
  string content = 2;
  uint64 session = 3;
  string provider = 4;
  string model = 5;
  optional TokenUsage usage = 6;
}

Streaming

For real-time responses, use StreamMsg instead of SendMsg. The server sends a sequence of StreamEvent messages:

EventWhat it carries
StreamStartAgent name + session ID
StreamChunkText delta
StreamThinkingReasoning delta (when thinking = true)
ToolStartEventArray of tool calls being dispatched
ToolResultEventSingle tool result with call_id and duration_ms
ToolsCompleteEventAll pending tool calls finished
AskUserEventAgent needs input — questions with options
StreamEndFinal event — agent name, error (if any), provider, model, token usage

Tool calls arrive as a batch in ToolStartEvent, results stream back individually as each completes. This enables real-time progress visibility during parallel tool execution.

Sessions

Sessions are identified by a uint64 ID. The daemon manages session persistence — clients don't need to store history.

OperationMessage
List sessionsSessionsSessionList
Kill a sessionKillMsg { session }
Compact historyCompactMsg { session }CompactResponse { summary }
List conversationsListConversationsMsg { agent, sender }ConversationList

Sessions auto-resume — if you omit session in SendMsg, the daemon picks the latest session for that (agent, sender) pair.

Agent management

Create, update, delete, and inspect agents at runtime:

OperationMessage
List agentsListAgentsMsgAgentList
Get agent detailsGetAgentMsg { name }AgentInfo
Create agentCreateAgentMsg { name, config }
Update agentUpdateAgentMsg { name, config }
Delete agentDeleteAgentMsg { name }

AgentInfo includes: model, max_iterations, thinking, members, skills, mcps, compact_threshold.

Cron

Schedule skills to run on a cron expression. Fires into a session whether or not a client is connected.

message CreateCronMsg {
  string schedule = 1;       // standard cron expression
  string skill = 2;          // fired as /<skill> into the session
  uint64 session = 3;        // target session
  optional string quiet_start = 4;  // HH:MM — skip during quiet hours
  optional string quiet_end = 5;
  bool once = 6;             // fire once then delete
}

Event subscription

Monitor all agent activity across all sessions from a single connection:

message SubscribeEvents {}

message AgentEventMsg {
  string agent = 1;
  uint64 session = 2;
  AgentEventKind kind = 3;   // TEXT_DELTA, THINKING_DELTA, TOOL_START, TOOL_RESULT, TOOLS_COMPLETE, DONE
  string content = 4;
  string timestamp = 5;
}

Daemon lifecycle

OperationMessage
PingPingPong
Reload configReloadMsg
Get statsGetStatsDaemonStats { uptime_secs, active_sessions, active_model }

Source & design documents

The protocol is defined in a single protobuf file and documented across several RFCs. Start with the proto for the contract, read the RFCs for the reasoning behind each decision.

What's next

On this page