HTTP API
The daemon exposes the same surface over HTTP that it does over the Unix socket. The HTTP gateway is suitable for browser-facing UIs and third-party tooling that cannot speak length-prefixed JSON IPC. Listening address is 127.0.0.1:8421 (loopback only) by default; override the port with the COVENANT_HTTP_PORT environment variable.
Conventions
- Request bodies are JSON; responses are JSON.
- Validation-level problems (missing capability, no agent matched) come back as
200 OKwith{ "kind": "error", "message": "…" }. This mirrors the IPC behaviour and keeps callers reading a consistent shape. - Internal errors (panic, I/O fault) come back as
500 Internal Server Errorwith{ "error": "…" }. - CORS is permissive on the gateway; treat it as a local-only surface and do not expose it beyond loopback.
Routes
Health
GET /health
→ 200 { "status": "ok" }Intents
POST /intent
Content-Type: application/json
Body: { "text": "summarise recent work on agent memory" }
→ 200 {
"kind": "intent_result",
"intent_id": "…",
"status": "ok",
"text": "…",
"sources": ["…"],
"settlement": null
}Memory
GET /memory/recent?tier=working&limit=10
GET /memory/search?q=agent+memory&tier=longterm&limit=5
POST /memory/purge
Body: { "tier": "working", "before_ms": 1714938000000 }
→ 200 { "kind": "memories", "records": [ ... ] }
or { "kind": "memory_purged", "purged": 42 }Receipts
GET /receipts/recent?limit=10
→ 200 { "kind": "receipts", "receipts": [ ... ] }Capabilities
GET /capabilities/recent?limit=10
POST /capabilities/grant
Body: {
"action": "tool.web_search",
"scope": null,
"expires_at": null
}
POST /capabilities/revoke
Body: { "signature_b58": "4qXP…" }
→ 200 {
"kind": "capability_granted",
"signature_b58": "…",
"subject_display": "user@local",
"action": "tool.web_search"
}
or { "kind": "capability_revoked", "signature_b58": "…", "removed": true }Verify
GET /verify?window=100
→ 200 {
"kind": "verify_report",
"window": 100,
"checks": [
{ "name": "memory ↔ audit", "passed": true, "message": "…" },
{ "name": "capability ↔ audit", "passed": true, "message": "…" },
{ "name": "memory ↔ receipts", "passed": true, "message": "…" }
],
"orphans_total": 0
}Tools
GET /tools
POST /tools/call
Body: { "name": "echo", "arguments": { "text": "hi" } }
→ 200 { "kind": "tool_list", "tools": [ ... ] }
or { "kind": "tool_result", "content": [ ... ], "is_error": false }Audit
GET /audit/recent?limit=20
→ 200 { "kind": "audit_events", "events": [ ... ] }Agent-to-agent
POST /a2a/tasks # body: A2ATask JSON
GET /a2a/tasks/next # consumes the next queued task
GET /a2a/tasks/recent?limit=N # non-consuming snapshot
POST /a2a/results # body: A2ATaskResult JSON
GET /a2a/results/next # consumes the next queued result
GET /a2a/results/recent?limit=N # non-consuming snapshotWrite paths (POST) require capability tokens — see Agent-to-agent for the exact actions.
Authentication
The HTTP gateway has no token authentication; reaching the loopback interface is the only credential. Treat the daemon as you would treat your shell — anything that can connect to 127.0.0.1:8421 can submit intents and grant capabilities. A future release will gate the HTTP surface behind capability tokens; until then, do not expose the gateway beyond loopback.
Related
- CLI — same surface, but talking to the Unix socket.
- Local IPC — the wire protocol on the Unix socket.
- Security model — what the loopback-only assumption costs you.