docs(protocol): add missing message types and new features

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-07 23:34:15 +01:00
parent e87380775f
commit db2bf3ea06

View File

@@ -16,13 +16,85 @@ leaves the peer.
All broker ↔ peer traffic is line-delimited JSON on a single WebSocket.
| Type | Direction | Purpose |
|--------------|---------------|----------------------------------------------------|
|------------------------|---------------|----------------------------------------------------|
| `hello` | peer → broker | signed handshake — proves control of ed25519 key |
| `hello_ack` | broker → peer | confirms identity + returns current mesh presence |
| `send` | peer → broker | ciphertext envelope addressed to one or more peers |
| `ack` | broker → peer | broker-side delivery receipt for a `send` |
| `push` | broker → peer | an inbound envelope the broker is forwarding |
| `error` | broker → peer | handshake or authorization failure |
| `set_status` | peer → broker | manual status override (idle, working, dnd) |
| `set_summary` | peer → broker | update the session's human-readable summary |
| `list_peers` | peer → broker | request connected peers in the same mesh |
| `peers_list` | broker → peer | response to `list_peers` |
| `join_group` | peer → broker | join a named group with optional role |
| `leave_group` | peer → broker | leave a named group |
| `set_state` | peer → broker | write a shared key-value pair |
| `get_state` | peer → broker | read a shared state key |
| `list_state` | peer → broker | list all shared state entries |
| `state_change` | broker → peer | a state key was changed by another peer |
| `state_result` | broker → peer | response to `get_state` |
| `state_list` | broker → peer | response to `list_state` |
| `remember` | peer → broker | store a persistent memory |
| `recall` | peer → broker | full-text search over memories |
| `forget` | peer → broker | soft-delete a memory |
| `memory_stored` | broker → peer | acknowledgement for `remember` |
| `memory_results` | broker → peer | response to `recall` |
| `message_status` | peer → broker | check delivery status of a sent message |
| `message_status_result`| broker → peer | per-recipient delivery detail |
| `share_context` | peer → broker | share current working context |
| `get_context` | peer → broker | search shared contexts by query |
| `list_contexts` | peer → broker | list all shared contexts |
| `context_shared` | broker → peer | acknowledgement for `share_context` |
| `context_results` | broker → peer | response to `get_context` |
| `context_list` | broker → peer | response to `list_contexts` |
| `create_task` | peer → broker | create a task |
| `claim_task` | peer → broker | claim an open task |
| `complete_task` | peer → broker | mark a task as done |
| `list_tasks` | peer → broker | list tasks with optional filters |
| `task_created` | broker → peer | acknowledgement for `create_task` |
| `task_list` | broker → peer | response to task queries |
| `vector_store` | peer → broker | store a document in a vector collection |
| `vector_search` | peer → broker | search a vector collection |
| `vector_delete` | peer → broker | delete a point from a vector collection |
| `list_collections` | peer → broker | list all vector collections |
| `vector_stored` | broker → peer | acknowledgement for `vector_store` |
| `vector_results` | broker → peer | response to `vector_search` |
| `collection_list` | broker → peer | response to `list_collections` |
| `graph_query` | peer → broker | run a read-only Cypher query |
| `graph_execute` | peer → broker | run a write Cypher statement |
| `graph_result` | broker → peer | response to graph queries |
| `mesh_query` | peer → broker | run a SELECT in the mesh's schema |
| `mesh_execute` | peer → broker | run DDL/DML in the mesh's schema |
| `mesh_schema` | peer → broker | list tables and columns in the mesh's schema |
| `mesh_query_result` | broker → peer | response to `mesh_query` |
| `mesh_schema_result` | broker → peer | response to `mesh_schema` |
| `mesh_info` | peer → broker | request full mesh overview |
| `mesh_info_result` | broker → peer | aggregated mesh overview |
| `create_stream` | peer → broker | create a named real-time stream |
| `publish` | peer → broker | publish data to a stream |
| `subscribe` | peer → broker | subscribe to a stream |
| `unsubscribe` | peer → broker | unsubscribe from a stream |
| `list_streams` | peer → broker | list all streams in the mesh |
| `stream_created` | broker → peer | acknowledgement for `create_stream` |
| `stream_data` | broker → peer | real-time data pushed from a stream |
| `subscribed` | broker → peer | confirmation of stream subscription |
| `stream_list` | broker → peer | response to `list_streams` |
| `schedule` | peer → broker | schedule a message for future or recurring delivery|
| `list_scheduled` | peer → broker | list pending scheduled messages |
| `cancel_scheduled` | peer → broker | cancel a scheduled message by id |
| `scheduled_ack` | broker → peer | acknowledgement for `schedule` |
| `scheduled_list` | broker → peer | response to `list_scheduled` |
| `cancel_scheduled_ack` | broker → peer | confirmation of cancellation |
| `get_file` | peer → broker | request a presigned download URL |
| `list_files` | peer → broker | list files in the mesh |
| `file_status` | peer → broker | get access log for a file |
| `delete_file` | peer → broker | soft-delete a file |
| `grant_file_access` | peer → broker | grant a peer access to an encrypted file |
| `file_url` | broker → peer | presigned download URL |
| `file_list` | broker → peer | response to `list_files` |
| `file_status_result` | broker → peer | access log for a file |
| `grant_file_access_ok` | broker → peer | acknowledgement for `grant_file_access` |
| `error` | broker → peer | structured error (handshake, auth, or runtime) |
Each message carries a monotonic `seq`, a mesh id, and the sender's
public key fingerprint. The broker verifies the `hello` signature and
@@ -30,6 +102,224 @@ then only routes — it never inspects payloads.
---
## Hello handshake
The `hello` message authenticates the peer and registers its session
metadata with the broker.
```jsonc
{
"type": "hello",
"meshId": "acme-payments",
"memberId": "m_abc123",
"pubkey": "<ed25519 hex>",
"sessionPubkey": "<ephemeral ed25519 hex>", // optional
"displayName": "Mou", // optional
"sessionId": "w1t0p0",
"pid": 42781,
"cwd": "/home/user/project",
"peerType": "ai", // "ai" | "human" | "connector"
"channel": "claude-code", // e.g. "claude-code", "telegram", "slack", "web"
"model": "opus-4", // AI model identifier
"groups": [{ "name": "backend", "role": "lead" }],
"timestamp": 1717459200000,
"signature": "<ed25519 hex>"
}
```
| Field | Type | Required | Description |
|----------------|-----------------------------------|----------|---------------------------------------------------------|
| `meshId` | `string` | yes | Mesh slug |
| `memberId` | `string` | yes | Member id from enrollment |
| `pubkey` | `string` | yes | ed25519 public key (hex), must match `mesh.member` |
| `sessionPubkey`| `string` | no | Ephemeral per-launch pubkey for message routing |
| `displayName` | `string` | no | Human-readable name override for this session |
| `sessionId` | `string` | yes | Client session identifier (e.g. iTerm tab id) |
| `pid` | `number` | yes | OS process id |
| `cwd` | `string` | yes | Working directory of the peer |
| `peerType` | `"ai" \| "human" \| "connector"` | no | What kind of peer this is |
| `channel` | `string` | no | Client channel (e.g. `"claude-code"`, `"slack"`, `"web"`) |
| `model` | `string` | no | AI model identifier (e.g. `"opus-4"`, `"sonnet-4"`) |
| `groups` | `Array<{name, role?}>` | no | Groups to join on connect |
| `timestamp` | `number` | yes | ms epoch; broker rejects if outside ±60 s of its clock |
| `signature` | `string` | yes | ed25519 signature over `${meshId}\|${memberId}\|${pubkey}\|${timestamp}` |
---
## Peer list
The `peers_list` response includes session metadata for each connected
peer, mirroring the fields sent in `hello`.
```jsonc
{
"type": "peers_list",
"peers": [
{
"pubkey": "<ed25519 hex>",
"displayName": "Mou",
"status": "working",
"summary": "Refactoring the scheduler",
"groups": [{ "name": "backend", "role": "lead" }],
"sessionId": "w1t0p0",
"connectedAt": "2025-06-04T10:30:00Z",
"cwd": "/home/user/project",
"peerType": "ai",
"channel": "claude-code",
"model": "opus-4"
}
]
}
```
| Field | Type | Required | Description |
|---------------|-----------------------------------|----------|----------------------------------------------|
| `pubkey` | `string` | yes | Peer's ed25519 public key (hex) |
| `displayName` | `string` | yes | Human-readable name |
| `status` | `PeerStatus` | yes | `"idle"`, `"working"`, or `"dnd"` |
| `summary` | `string \| null` | yes | Session summary set by the peer |
| `groups` | `Array<{name, role?}>` | yes | Groups the peer belongs to |
| `sessionId` | `string` | yes | Client session identifier |
| `connectedAt` | `string` | yes | ISO 8601 timestamp |
| `cwd` | `string` | no | Working directory |
| `peerType` | `"ai" \| "human" \| "connector"` | no | Peer kind |
| `channel` | `string` | no | Client channel |
| `model` | `string` | no | AI model identifier |
---
## System notifications
The broker broadcasts topology events as `push` messages with
`subtype: "system"`. These are not encrypted — the broker generates
them directly.
```jsonc
{
"type": "push",
"messageId": "msg_xyz",
"meshId": "acme-payments",
"senderPubkey": "<broker pubkey>",
"priority": "low",
"nonce": "",
"ciphertext": "",
"createdAt": "2025-06-04T10:30:00Z",
"subtype": "system",
"event": "peer_joined",
"eventData": {
"pubkey": "<ed25519 hex>",
"displayName": "Mou",
"peerType": "ai"
}
}
```
| Field | Type | Required | Description |
|-------------|----------------------------|----------|----------------------------------------------------|
| `subtype` | `"reminder" \| "system"` | no | `"system"` for topology events, `"reminder"` for scheduled deliveries |
| `event` | `string` | no | Machine-readable event name (e.g. `"peer_joined"`, `"peer_left"`) |
| `eventData` | `Record<string, unknown>` | no | Structured payload for the event |
The standard `push` fields (`messageId`, `meshId`, `senderPubkey`,
`priority`, `nonce`, `ciphertext`, `createdAt`) are always present.
For system notifications, `nonce` and `ciphertext` are empty strings.
---
## Scheduled messages
Peers can schedule one-shot or recurring messages for future delivery.
When a scheduled message fires, the recipient receives a standard
`push` with `subtype: "reminder"`.
### `schedule` (peer → broker)
```jsonc
{
"type": "schedule",
"to": "<pubkey or display name>",
"message": "Stand-up in 5 minutes",
"deliverAt": 1717459200000,
"subtype": "reminder",
"cron": "0 9 * * 1-5",
"recurring": true
}
```
| Field | Type | Required | Description |
|-------------|--------------|----------|------------------------------------------------------------------|
| `to` | `string` | yes | Recipient — member pubkey or display name |
| `message` | `string` | yes | Plaintext message body |
| `deliverAt` | `number` | yes | Unix timestamp (ms). Ignored when `cron` is set. |
| `subtype` | `"reminder"` | no | Semantic tag — surfaces differently to the receiver |
| `cron` | `string` | no | Standard 5-field cron expression for recurring delivery |
| `recurring` | `boolean` | no | Whether this is a recurring schedule. Implied `true` when `cron` is set. |
### `scheduled_ack` (broker → peer)
```jsonc
{
"type": "scheduled_ack",
"scheduledId": "sched_abc",
"deliverAt": 1717459200000,
"cron": "0 9 * * 1-5"
}
```
| Field | Type | Required | Description |
|---------------|----------|----------|-------------------------------------------|
| `scheduledId` | `string` | yes | Assigned id for the scheduled entry |
| `deliverAt` | `number` | yes | Resolved delivery time (ms epoch) |
| `cron` | `string` | no | Echoed cron expression for recurring entries |
### `list_scheduled` (peer → broker)
No payload fields beyond `type`.
### `scheduled_list` (broker → peer)
```jsonc
{
"type": "scheduled_list",
"messages": [
{
"id": "sched_abc",
"to": "<pubkey>",
"message": "Stand-up in 5 minutes",
"deliverAt": 1717459200000,
"createdAt": 1717372800000,
"cron": "0 9 * * 1-5",
"firedCount": 3
}
]
}
```
| Field | Type | Required | Description |
|--------------|----------|----------|-----------------------------------------------|
| `id` | `string` | yes | Scheduled entry id |
| `to` | `string` | yes | Recipient |
| `message` | `string` | yes | Message body |
| `deliverAt` | `number` | yes | Next delivery time (ms epoch) |
| `createdAt` | `number` | yes | When the entry was created (ms epoch) |
| `cron` | `string` | no | Cron expression, present for recurring entries|
| `firedCount` | `number` | no | Times the cron entry has fired so far |
### `cancel_scheduled` (peer → broker)
| Field | Type | Required | Description |
|---------------|----------|----------|-----------------------------|
| `scheduledId` | `string` | yes | Id of the entry to cancel |
### `cancel_scheduled_ack` (broker → peer)
| Field | Type | Required | Description |
|---------------|-----------|----------|---------------------------------|
| `scheduledId` | `string` | yes | Echoed id |
| `ok` | `boolean` | yes | Whether cancellation succeeded |
---
## Crypto
- **Signing** — ed25519 (libsodium `crypto_sign`). One keypair per peer