# Cairn — API

## Server API (FastAPI)

Base URL: `http://localhost:8000`

### Projects

| Method | Path | Request | Response | Status |
|--------|------|---------|----------|--------|
| GET | `/projects` | — | `list[ProjectSummary]` | 200 |
| POST | `/projects` | `CreateProjectRequest` | `ProjectDetail` | 201 |
| GET | `/projects/{project_id}` | — | `ProjectDetail` | 200 |
| DELETE | `/projects/{project_id}` | — | — | 204 |
| PUT | `/projects/{project_id}/title` | `UpdateProjectTitleRequest` | `ProjectMeta` | 200 |
| PUT | `/projects/{project_id}/status` | `UpdateProjectStatusRequest` | `ProjectMeta` | 200 |
| POST | `/projects/{project_id}/reason/claim` | `ReasonClaimRequest` | `ProjectMeta` | 200 |
| POST | `/projects/{project_id}/reason/heartbeat` | `HeartbeatRequest` | `ProjectMeta` | 200 |
| POST | `/projects/{project_id}/reason/release` | `HeartbeatRequest` | `ProjectMeta` | 200 |
| POST | `/projects/{project_id}/complete` | `CompleteRequest` | `Intent` | 200 |
| POST | `/projects/{project_id}/reopen` | `ReopenRequest` | `ReopenResponse` | 200 |

### Intents

| Method | Path | Request | Response | Status |
|--------|------|---------|----------|--------|
| POST | `/projects/{project_id}/intents` | `CreateIntentRequest` | `Intent` | 201 |
| POST | `/projects/{project_id}/intents/{intent_id}/heartbeat` | `HeartbeatRequest` | `Intent` | 200 |
| POST | `/projects/{project_id}/intents/{intent_id}/release` | `HeartbeatRequest` | `Intent` | 200 |
| POST | `/projects/{project_id}/intents/{intent_id}/conclude` | `ConcludeRequest` | `ConcludeResponse` | 200 |

### Hints

| Method | Path | Request | Response | Status |
|--------|------|---------|----------|--------|
| POST | `/projects/{project_id}/hints` | `CreateHintRequest` | `Hint` | 201 |

### Export

| Method | Path | Query | Response | Status |
|--------|------|-------|----------|--------|
| GET | `/projects/{project_id}/export` | `format=yaml\|timeline` | `text/plain` | 200 |

### Settings

| Method | Path | Request | Response | Status |
|--------|------|---------|----------|--------|
| GET | `/settings` | — | `Settings` | 200 |
| PUT | `/settings` | `Settings` | `Settings` | 200 |

## Data Models

### Core domain

| Model | Fields |
|-------|--------|
| `Fact` | `id: str`, `description: str` |
| `Intent` | `id`, `from: list[str]`, `to: str\|None`, `description`, `creator`, `worker\|None`, `last_heartbeat_at\|None`, `created_at`, `concluded_at\|None` |
| `Hint` | `id`, `content`, `creator`, `created_at` |
| `ProjectReason` | `worker`, `trigger`, `started_at`, `last_heartbeat_at` |
| `ProjectMeta` | `id`, `title`, `status: "active"\|"stopped"\|"completed"`, `bootstrap_enabled`, `created_at`, `reason\|None` |
| `ProjectSummary` | ProjectMeta + `fact_count`, `intent_count`, `working_intent_count`, `unclaimed_intent_count`, `hint_count` |
| `ProjectDetail` | `project: ProjectMeta`, `facts`, `intents`, `hints` |
| `Settings` | `intent_timeout: int (≥5)`, `reason_timeout: int (≥5)` |

### Request models

| Model | Key fields |
|-------|-----------|
| `CreateProjectRequest` | `title`, `origin`, `goal`, `bootstrap_enabled=True`, `hints?: list[CreateHintInline]` |
| `CreateIntentRequest` | `from: list[str]`, `description`, `creator`, `worker?` |
| `CreateHintRequest` | `content`, `creator` |
| `HeartbeatRequest` | `worker` |
| `ReasonClaimRequest` | `worker`, `trigger` |
| `ConcludeRequest` | `worker`, `description` |
| `CompleteRequest` | `from: list[str]`, `description`, `worker` |
| `ReopenRequest` | `description`, `creator` |

### Response models

| Model | Fields |
|-------|--------|
| `ConcludeResponse` | `fact: Fact`, `intent: Intent` |
| `ReopenResponse` | `project: ProjectMeta`, `fact: Fact`, `intent: Intent` |

## CLI

| Command | Options | Description |
|---------|---------|-------------|
| `cairn serve` | `--host`, `--port`, `--db-path`, `--log-level`, `--access-log/--no-access-log` | Start API server |
| `cairn dispatch` | `--config`, `--once`, `--startup-healthcheck-only`, `--log-level` | Run dispatcher |

## Static UI

The server also serves a built-in web UI at `/` (static files mounted at `/static`).
