# 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.

| Transport | When | Path / Port |
| --- | --- | --- |
| Unix domain socket | macOS, Linux | `~/.crabtalk/run/crabtalk.sock` |
| TCP | Windows, or `--tcp` flag | Port 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:

```protobuf
// 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:

| Event | What it carries |
| --- | --- |
| `StreamStart` | Agent name + session ID |
| `StreamChunk` | Text delta |
| `StreamThinking` | Reasoning delta (when `thinking = true`) |
| `ToolStartEvent` | Array of tool calls being dispatched |
| `ToolResultEvent` | Single tool result with `call_id` and `duration_ms` |
| `ToolsCompleteEvent` | All pending tool calls finished |
| `AskUserEvent` | Agent needs input — questions with options |
| `StreamEnd` | Final 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.

| Operation | Message |
| --- | --- |
| List sessions | `Sessions` → `SessionList` |
| Kill a session | `KillMsg { session }` |
| Compact history | `CompactMsg { session }` → `CompactResponse { summary }` |
| List conversations | `ListConversationsMsg { 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:

| Operation | Message |
| --- | --- |
| List agents | `ListAgentsMsg` → `AgentList` |
| Get agent details | `GetAgentMsg { name }` → `AgentInfo` |
| Create agent | `CreateAgentMsg { name, config }` |
| Update agent | `UpdateAgentMsg { name, config }` |
| Delete agent | `DeleteAgentMsg { 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.

```protobuf
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:

```protobuf
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

| Operation | Message |
| --- | --- |
| Ping | `Ping` → `Pong` |
| Reload config | `ReloadMsg` |
| Get stats | `GetStats` → `DaemonStats { 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.

- [`crabtalk.proto`](https://github.com/crabtalk/crabtalk/blob/main/crates/core/proto/crabtalk.proto) — the full protobuf definition
- [RFC 0018 — Wire Protocol](https://crabtalk.github.io/crabtalk/rfcs/0018-protocol.html) — transport layer, message dispatch, streaming design
- [RFC 0064 — Sessions](https://crabtalk.github.io/crabtalk/rfcs/0064-session.html) — JSONL persistence, compaction, auto-injection
- [RFC 0080 — Cron](https://crabtalk.github.io/crabtalk/rfcs/0080-cron.html) — daemon-level scheduling, quiet hours, persistence
- [RFC 0009 — Transport](https://crabtalk.github.io/crabtalk/rfcs/0009-transport.html) — UDS and TCP, frame encoding, accept loop

## What's next

- [Build a Gateway](/content/blog/build-gateway/index.html) — build a client that uses this protocol
- [Sessions](/content/docs/crabtalk/sessions/index.html) — how session persistence works
- [Events](/content/docs/crabtalk/events/index.html) — real-time event subscription

### MCP Servers

Connect external tool servers to CrabTalk — stdio or HTTP, auto-discovered, hot-reloadable.
