Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/docs/guides/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The catalog is being built out one guide at a time, prioritized by the questions
| [Set up memory](/docs/guides/set-up-memory) | How do I enable memory and inspect what is stored? |
| [Fix a failed install](/docs/guides/fix-a-failed-install) | My install broke — how do I diagnose and repair it? |
| [Upgrade Coven](/docs/guides/upgrade-coven) | How do I upgrade safely without losing sessions? |
| Script the API | How do I call the daemon API from my own scripts? |
| [Script the API](/docs/guides/script-the-api) | How do I call the daemon API from my own scripts? |

## Start here today

Expand Down
2 changes: 1 addition & 1 deletion content/docs/guides/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"description": "Step-by-Step How-Tos",
"root": true,
"icon": "LuCompass",
"pages": ["index", "install-and-first-run", "connect-a-harness", "set-up-the-daemon", "set-up-memory", "fix-a-failed-install", "upgrade-coven"]
"pages": ["index", "install-and-first-run", "connect-a-harness", "set-up-the-daemon", "set-up-memory", "fix-a-failed-install", "upgrade-coven", "script-the-api"]
}
113 changes: 113 additions & 0 deletions content/docs/guides/script-the-api.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
title: "Script the API"
summary: "Call the daemon API from your own scripts: health handshake, listing and launching sessions, following events with a cursor, and handling structured errors."
description: "Step-by-step guide to scripting the Coven daemon socket API with curl: health, sessions, session launch, event cursors, and the error envelope."
read_when:
- You want your own script or tool to drive Coven instead of the CLI
- You need the minimal correct client loop: health, launch, events, errors
---

Everything the CLI and every other client does goes through the daemon's local HTTP API. This guide builds the minimal correct client loop with `curl`: handshake, list, launch, follow events, and branch on structured errors. The full contract is the [API reference](/docs/reference/api) and the [OpenAPI pages](/docs/openapi).

## Prerequisites

- The daemon running — see [Set up the daemon](/docs/guides/set-up-the-daemon).
- `curl`; `jq` helps but is optional.
- A project directory and one connected harness for the launch step — see [Connect a harness](/docs/guides/connect-a-harness).

All examples use the Unix socket. Set the path once:

```bash
SOCK="$HOME/.coven/coven.sock"
```

## Step 1 — Start with the health handshake

Every client should begin every run here:

```bash
curl --unix-socket "$SOCK" http://localhost/api/v1/health
```

**Expected output:** `"ok": true`, `"apiVersion": "coven.daemon.v1"`, and a capability map. Scripts should verify the `apiVersion` matches the contract they were written for and check `GET /api/v1/capabilities` before using optional features — see [versioning rules](/docs/reference/api#versioning).

## Step 2 — List sessions

```bash
curl --unix-socket "$SOCK" http://localhost/api/v1/sessions
```

**Expected output:** a JSON array of session records with snake_case fields (`id`, `project_root`, `harness`, `title`, `status`, `created_at`, …). An empty array just means no active, non-archived sessions. The record shape is documented under [session records](/docs/reference/api#session-records).

## Step 3 — Launch a session

`POST /api/v1/sessions` validates the project boundary before spawning anything:

```bash
curl --unix-socket "$SOCK" http://localhost/api/v1/sessions \
-H 'content-type: application/json' \
-d '{
"projectRoot": "/Users/you/code/your-repo",
"cwd": "/Users/you/code/your-repo",
"harness": "codex",
"prompt": "explain this repo in 5 bullets",
"title": "API launch smoke test"
}'
```

**Expected output:** `201` with the created session record — capture its `id` for the next step. `cwd` must resolve inside `projectRoot`, `harness` must be a supported harness id, and provider credentials are never part of the request.

## Step 4 — Follow events with the cursor

Poll the event page for your session, then resume from `nextCursor.afterSeq`:

```bash
curl --unix-socket "$SOCK" \
"http://localhost/api/v1/events?sessionId=<session-id>&afterSeq=0&limit=100"
```

**Expected output:** an `events` array (each with `seq`, `kind`, `payload_json`), a `nextCursor`, and `hasMore`. The loop that never loses data:

1. Request with your last `afterSeq` (start at `0`).
2. Process the returned events.
3. If `nextCursor` is non-null, persist `nextCursor.afterSeq` — it survives daemon restarts. `nextCursor` is `null` when the page is empty; keep your previous cursor.
4. Repeat while `hasMore` is `true`, then poll on your own interval.

The daemon caps `limit` at 1000. `GET /api/v1/sessions/<id>/events` is the same read, path-scoped — see [events](/docs/reference/api#events).

## Step 5 — Branch on the error envelope

Force a failure to see the shape every error uses:

```bash
curl --unix-socket "$SOCK" http://localhost/api/v1/sessions/does-not-exist
```

**Expected output:**

```json
{
"error": {
"code": "session_not_found",
"message": "Session was not found.",
"details": { "sessionId": "does-not-exist" }
}
}
```

Branch on `error.code`, never on message text. The stable codes (`not_found`, `invalid_request`, `session_not_found`, `session_not_live`, `project_root_violation`, `pty_spawn_failed`, `runtime_unavailable`, `internal_error`) and their HTTP statuses are tabulated in the [error envelope reference](/docs/reference/api#error-envelope). A robust script treats `runtime_unavailable` as retryable (a `503`: check `coven daemon status`, then retry), and `session_not_live` as "switch to replay, do not send input."

## Troubleshooting

- **`curl` cannot connect** — daemon down or wrong socket path for your `COVEN_HOME`; see [Set up the daemon](/docs/guides/set-up-the-daemon).
- **`invalid_request` on launch** — compare your body against Step 3's fields; an unknown harness id lands here too.
- **`project_root_violation`** — your `cwd` escapes `projectRoot`; see [`cwd` rejected](/docs/reference/troubleshooting#cwd-rejected).
- **Events stop arriving** — the session likely completed; check its `status` via `GET /api/v1/sessions/<id>`.
- **Version mismatch after an upgrade** — see [API version rejected](/docs/reference/troubleshooting#api-version-rejected) and [Upgrade Coven](/docs/guides/upgrade-coven).

## Related

- [API reference](/docs/reference/api)
- [API architecture diagrams](/docs/reference/api-architecture)
- [OpenAPI endpoint pages](/docs/openapi)
- [Socket API overview](/docs/daemon/socket-api)
10 changes: 10 additions & 0 deletions scripts/check-guides-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const requiredPages = [
'set-up-memory',
'fix-a-failed-install',
'upgrade-coven',
'script-the-api',
];

const requiredMentions = [
Expand Down Expand Up @@ -53,6 +54,11 @@ const requiredMentions = [
'coven --version',
'/api/v1/capabilities',
'coven sessions --all --plain',
'/api/v1/sessions',
'/api/v1/events',
'nextCursor',
'error.code',
'session_not_found',
];

function fail(message) {
Expand Down Expand Up @@ -148,4 +154,8 @@ if (!readFileSync(join(guidesRoot, 'upgrade-coven.mdx'), 'utf8').includes('/docs
fail('upgrade-coven guide must link to the recovery and upgrades reference.');
}

if (!readFileSync(join(guidesRoot, 'script-the-api.mdx'), 'utf8').includes('/docs/reference/api')) {
fail('script-the-api guide must link to the API reference.');
}

console.log('Guides docs check passed.');