Local IPC
The daemon's canonical wire protocol. Clients on the same machine — the CLI, an operator UI, third-party tooling — speak length-prefixed JSON over a Unix socket at $COVENANT_HOME/sock. The HTTP gateway is a thin adapter on top of the same surface.
Frame format
Each frame is a 4-byte big-endian unsigned integer length prefix followed by exactly that many bytes of UTF-8 JSON. Frames over 8 MiB are rejected at the read boundary.
+---------+---------+---------+---------+---------- … ----------+
| len[31..24] | len[23..16] | len[15..8] | len[7..0] | JSON payload |
+-------------+-------------+------------+-----------+--------------+
4-byte big-endian length up to 8 MiBThe framing applies in both directions: the request frame is followed by exactly one response frame, and a long-lived connection can carry many request/response pairs in sequence. Connections are not pooled by the daemon; clients are expected to reuse a single connection or open one per request as convenient.
Request shapes
A request is a JSON object tagged with kind. The full set today:
{ "kind": "ping" }
{ "kind": "submit_intent",
"text": "…" }
{ "kind": "recent_memory",
"tier": "working" | "episodic" | "longterm" | null,
"limit": 10 }
{ "kind": "search_memory",
"query": "…",
"tier": "working" | "episodic" | "longterm" | null,
"limit": 10 }
{ "kind": "purge_memory",
"tier": "working" | "episodic" | "longterm" | null,
"before_ms": 1714938000000 }
{ "kind": "recent_receipts",
"limit": 10 }
{ "kind": "recent_capabilities",
"limit": 10 }
{ "kind": "grant_capability",
"action": "tool.web_search",
"scope": null | { ... },
"expires_at": null | 1714938000000 }
{ "kind": "revoke_capability",
"signature_b58": "…" }
{ "kind": "verify",
"window": 100 }
{ "kind": "ignore_check",
"text": "…" }
{ "kind": "list_tools" }
{ "kind": "call_tool",
"name": "echo",
"arguments": { ... } }
{ "kind": "recent_audit",
"limit": 20 }
{ "kind": "send_a2a_task", "task": { ... } }
{ "kind": "try_recv_a2a_task" }
{ "kind": "post_a2a_result", "result": { ... } }
{ "kind": "try_recv_a2a_result" }Response shapes
Responses are also kind-tagged. One canonical response shape per request, plus a generic error for any handler-level failure.
{ "kind": "pong" }
{ "kind": "intent_result",
"intent_id": "uuid",
"status": "ok" | "ignored",
"text": "…",
"sources": ["…"],
"settlement": null | { ... } }
{ "kind": "memories", "records": [ ... ] }
{ "kind": "memory_purged", "purged": 42 }
{ "kind": "receipts", "receipts": [ ... ] }
{ "kind": "capabilities", "capabilities": [ ... ] }
{ "kind": "capability_granted",
"signature_b58": "…",
"subject_display": "user@local",
"action": "tool.web_search" }
{ "kind": "capability_revoked",
"signature_b58": "…",
"removed": true }
{ "kind": "verify_report",
"window": 100,
"checks": [ { "name": "…", "passed": true, "message": "…" } ],
"orphans_total": 0 }
{ "kind": "ignore_report",
"ignored": false,
"matched_pattern": null,
"rules_loaded": 3 }
{ "kind": "tool_list", "tools": [ ... ] }
{ "kind": "tool_result", "content": [ ... ], "is_error": false }
{ "kind": "audit_events", "events": [ ... ] }
{ "kind": "a2a_task_queued", "task_id": "uuid" }
{ "kind": "a2a_task_opt", "task": null | { ... } }
{ "kind": "a2a_result_posted", "task_id": "uuid" }
{ "kind": "a2a_result_opt", "result": null | { ... } }
{ "kind": "error", "message": "…" }Implementation notes
- Backpressure. The daemon reads one frame at a time per connection; long-running operations hold the connection open until they complete, so a slow handler will delay the next request on that connection.
- Frame size. The 8 MiB cap applies in both directions. Returning a memory record set that exceeds it should not happen in normal operation, but a verification window over millions of records can. Use
limitarguments where they exist. - Timeouts. The daemon does not impose a per-request timeout. Clients should set their own.
- Authentication. Connecting to the Unix socket is the credential. Anything with read access to
$COVENANT_HOME/sockcan submit intents.
Reference implementation
The covenant-ipc Rust crate provides read_frame and write_frame helpers plus the Request and Response enums. See CLI for an end-to-end example using both.
Related
- HTTP API — the same surface for clients that prefer JSON over HTTP.
- Security model — what the socket-as-credential design costs you.