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 OK with { "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 Error with { "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 snapshot

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