Coven local socket API
The Coven local HTTP API served over a Unix socket: health, capabilities, actions, sessions, events, and input forwarding under /api/v1.
3 min read
Last updated: 2026-05-09
Looking for an interactive reference?
The API Reference section renders each endpoint as a live page with request/response schemas, code samples in four languages, and Try It panels that bridge to your local daemon. This page remains the narrative reference for concepts, error model, and versioning rules.
Coven exposes a small HTTP API over the local Unix socket at <covenHome>/coven.sock. The Rust daemon is the authority boundary: clients may validate for UX, but the daemon still validates project roots, cwd, harness ids, session ids, input, and live-session state before acting.
For a consolidated visual map of route topology, compatibility handshake, error flow, event cursors, live control, launch lifecycle, and authority boundaries, see API architecture diagrams.
Every route returns either a documented success shape or the structured error envelope. Unknown routes, unknown action ids, and unknown API versions all fail closed with invalid_request or not_found.
See Authentication and local access for the current auth posture. In short: the daemon API does not use OAuth, JWTs, bearer tokens, API keys, or cookies today. Access is local Unix-socket based, provider credentials stay with the harness CLIs, and any remote, browser, or TCP exposure needs a separate auth design.
Versioning
The current public API contract is the named coven.daemon.v1 contract served under the /api/v1 route prefix.
Versioned clients should use the /api/v1 prefix:
| Method | Path | Surface | Purpose |
|---|---|---|---|
| GET | /api/v1/api-version | Meta | Read the active API version and supported versions. |
| GET | /api/v1/health | Meta | Check daemon health and metadata. |
| GET | /api/v1/capabilities | Meta | Discover daemon / control-plane capabilities and policy hints. |
| POST | /api/v1/actions | Control | Route a policy-shaped control-plane action. |
| GET | /api/v1/sessions | Sessions | List active sessions. |
| POST | /api/v1/sessions | Sessions | Launch a session. |
| GET | /api/v1/sessions/:id | Sessions | Fetch one session. |
| GET | /api/v1/events?sessionId=... | Events | Read session events. |
| POST | /api/v1/sessions/:id/input | Sessions | Forward input to a live session. |
| POST | /api/v1/sessions/:id/kill | Sessions | Kill a live session. |
Unversioned routes currently remain as legacy aliases during the early MVP window, but new clients should not rely on them.
Unknown /api/<version>/... prefixes fail closed with an unsupported API version JSON response.
Health Response
GET /api/v1/health is the required compatibility handshake. It returns the named contract version, the installed Coven binary version, machine-readable capabilities, and optional daemon metadata:
{
"ok": true,
"apiVersion": "coven.daemon.v1",
"covenVersion": "0.0.0",
"capabilities": {
"sessions": true,
"events": true,
"eventCursor": "sequence",
"structuredErrors": true
},
"daemon": {
"pid": 12345,
"startedAt": "2026-05-09T12:00:00Z",
"socket": "/Users/example/.coven/coven.sock"
}
}When no daemon metadata is available, daemon is null.
Clients should treat apiVersion: "coven.daemon.v1" as the stable contract guard. covenVersion identifies the binary build and can be shown in diagnostics, but clients should not branch compatibility on a package version alone.
GET /api/v1/api-version is lower-level route metadata. It currently returns the route prefix version, not the named contract:
{
"apiVersion": "v1",
"supportedApiVersions": ["v1"]
}Use /api/v1/health for normal client handshakes. Use /api/v1/api-version only when debugging route-prefix support.
Control-plane Capabilities
GET /api/v1/capabilities is the discovery point for first-party clients. It returns capability ids, adapter ownership, availability, policy hints, and action ids. This keeps clients from hard-coding what the daemon can do.
{
"capabilities": [
{
"id": "coven.control.actions",
"label": "Coven control-plane action router",
"adapter": "coven-daemon",
"status": "available",
"policy": "allow",
"actions": ["coven.capabilities.refresh"]
},
{
"id": "desktop.automation",
"label": "Desktop automation adapters",
"adapter": "desktop-use",
"status": "planned",
"policy": "requiresApproval",
"actions": []
}
]
}Control-plane Actions
POST /api/v1/actions accepts a structured intent envelope. The daemon routes only known actions; unknown actions fail closed before any adapter can run.
{
"action": "coven.capabilities.refresh",
"origin": "coven-client",
"args": {}
}Immediately completed safe actions return 200 with an event-shaped payload that clients can render optimistically or fold into later event streams:
{
"ok": true,
"accepted": true,
"action": "coven.capabilities.refresh",
"status": "completed",
"event": {
"kind": "capabilities.refreshed",
"action": "coven.capabilities.refresh",
"origin": "coven-client",
"payload": { "capabilities": 3 }
}
}Session Records
Session endpoints return the Rust daemon's SessionRecord shape with snake_case field names:
{
"id": "session-1",
"project_root": "/Users/example/project",
"harness": "codex",
"title": "Fix failing tests",
"status": "running",
"exit_code": null,
"archived_at": null,
"created_at": "2026-05-09T06:43:00Z",
"updated_at": "2026-05-09T06:43:05Z"
}| Method | Path | Response | Notes |
|---|---|---|---|
| GET | /api/v1/sessions | SessionRecord[] | Lists active, non-archived sessions. |
| POST | /api/v1/sessions | SessionRecord | Launches a project-scoped harness session. |
| GET | /api/v1/sessions/:id | SessionRecord | Returns 404 session_not_found for unknown ids. |
POST /api/v1/sessions accepts the launch fields the daemon validates before spawning a harness:
{
"projectRoot": "/Users/example/project",
"cwd": "/Users/example/project",
"harness": "codex",
"prompt": "Fix the failing tests",
"title": "Fix failing tests"
}cwd must resolve inside projectRoot. harness must be a supported harness id. Provider credentials are not part of this request; Codex, Claude Code, and future harnesses keep their own local auth flows.
Events
GET /api/v1/events returns an event page for one session.
| Parameter | Required | Meaning |
|---|---|---|
sessionId | Yes | Session id whose events should be returned. |
afterSeq | No | Preferred cursor. Returns events with seq > afterSeq. |
afterEventId | No | Compatibility cursor resolved to a sequence position. |
limit | No | Maximum records to return. The daemon enforces a max of 1000. |
{
"events": [
{
"seq": 42,
"id": "event-1",
"session_id": "session-1",
"kind": "output",
"payload_json": "{\"data\":\"hello\"}",
"created_at": "2026-05-09T06:43:10Z"
}
],
"nextCursor": {
"afterSeq": 42
},
"hasMore": false
}nextCursor is null when there are no events. Persisting nextCursor.afterSeq lets clients resume incremental reads after a daemon restart.
Live Input
POST /api/v1/sessions/:id/input forwards input only to a daemon-verified live session.
Request:
{
"data": "continue with the next failing test\n"
}Success returns 202:
{
"ok": true,
"accepted": true
}The daemon records accepted input as a session event. Completed, failed, killed, archived, or orphaned sessions are replay/log surfaces, not live input targets.
Live Kill
POST /api/v1/sessions/:id/kill terminates only a daemon-verified live process. The request body is empty.
Success returns 202:
{
"ok": true,
"accepted": true
}After a successful kill, the daemon updates the session status to killed and writes a kill event. Killing a session is not the same as deleting its history; use archive/summon/sacrifice lifecycle commands for record management.
Error Envelope
All API failures use this structured envelope. Clients should branch on error.code, not message text:
{
"error": {
"code": "session_not_found",
"message": "Session was not found.",
"details": {
"sessionId": "session-1"
}
}
}| Code | HTTP status | Meaning |
|---|---|---|
not_found | 404 | Route not found. |
invalid_request | 400 or 404 | Malformed request, unsupported API version, or unknown control action. |
session_not_found | 404 | Session id does not exist. |
session_not_live | 409 | Session exists but cannot accept input or kill because it is not running in this daemon. |
project_root_violation | 400 | Requested cwd resolves outside the declared project root. |
pty_spawn_failed | 500 | Harness PTY could not be launched. |
runtime_unavailable | 503 | The session runtime is unavailable. |
internal_error | 500 | Unexpected internal daemon error. |
Unknown session:
{
"error": {
"code": "session_not_found",
"message": "Session was not found.",
"details": { "sessionId": "session-1" }
}
}Non-live input or kill:
{
"error": {
"code": "session_not_live",
"message": "Session is not live.",
"details": { "sessionId": "session-1" }
}
}Compatibility Rules
| Rule | Risk area | Client or maintainer action |
|---|---|---|
Additive JSON fields are allowed in v1 responses. | Forward compatibility | Clients should ignore unknown optional fields when safe. |
Existing required fields should not be removed or renamed inside v1. | Breaking changes | Keep required response shapes stable for versioned clients. |
| Breaking response-shape or behavior changes require a new API version prefix. | Versioning | Move incompatible behavior behind a new route prefix. |
External clients should call /api/v1/health before assuming compatibility. | Handshake | Check daemon availability and API version first. |
Daemon changes that affect /api/v1/health, /api/v1/sessions, /api/v1/events, input, or kill behavior should update client compatibility tests in the same repo. | Contract drift | Update tests with the API-affecting change. |
Last updated on