kas serve
Start an HTTP server that exposes the kasmos task store over a REST API backed by SQLite. Optionally starts a second MCP server on a separate port.
kas serve [flags]
flags
| flag | default | description |
|---|---|---|
--port | 7433 | port for the REST API |
--bind | 0.0.0.0 | address to bind to |
--db | ~/.config/kasmos/taskstore.db | path to the SQLite database file |
--repo | none | repo root to serve; repeat for multiple project-scoped repos |
--mcp | true | enable the MCP server (Streamable HTTP) |
--mcp-port | 7434 | port for the MCP server |
--admin-dir | embedded | path to the built admin SPA dist/ directory |
examples
# start with defaults (port 7433, embedded admin UI)
kas serve
# use a custom port and database
kas serve --port 8080 --db /data/kasmos/tasks.db
# serve one or more repo-scoped projects
kas serve --repo /srv/kasmos/repos/app --repo /srv/kasmos/repos/docs
# bind to localhost only, disable MCP
kas serve --bind 127.0.0.1 --mcp=false
# use a separately built admin UI
kas serve --admin-dir /opt/kasmos/admin/dist
rest api
All task endpoints use the project-scoped URL prefix /v1/projects/{project}/tasks.
In the default daemon-backed mode, the project catalog is resolved from the live daemon and shared task store for each request. Repositories registered after kas serve starts are therefore available to REST and MCP task/signal calls without restarting the server. Explicit --repo mode remains a fixed allowlist.
health
| method | path | description |
|---|---|---|
GET | /v1/ping | health check — returns 200 if the store is reachable |
tasks
| method | path | description |
|---|---|---|
GET | /v1/projects/{project}/tasks | list tasks; accepts ?status=<s> and ?topic=<t> query params |
POST | /v1/projects/{project}/tasks | create a task (JSON body: TaskEntry) |
GET | /v1/projects/{project}/tasks/{filename} | get a single task |
PUT | /v1/projects/{project}/tasks/{filename} | update task metadata |
task content
| method | path | description |
|---|---|---|
GET | /v1/projects/{project}/tasks/{filename}/content | retrieve plan content (returns text/markdown) |
PUT | /v1/projects/{project}/tasks/{filename}/content | replace plan content (raw markdown body) |
architect decisions
| method | path | description |
|---|---|---|
GET | /v1/projects/{project}/tasks/{filename}/architect-decisions | return the cached architect decision_audit, final task markdown, and any planner draft decisions recorded for hq task details |
The endpoint reads .kasmos/cache/<task>-architect.json from the resolved repo root. Older tasks without architect metadata return available: false with a stable reason instead of failing the task detail page.
subtasks
| method | path | description |
|---|---|---|
GET | /v1/projects/{project}/tasks/{filename}/subtasks | list subtask entries |
PUT | /v1/projects/{project}/tasks/{filename}/subtasks | replace subtask list (JSON array) |
PUT | /v1/projects/{project}/tasks/{filename}/subtasks/{taskNumber}/status | update a single subtask status |
task metadata
| method | path | description |
|---|---|---|
PUT | /v1/projects/{project}/tasks/{filename}/goal | set task goal text |
PUT | /v1/projects/{project}/tasks/{filename}/phase-timestamp | record a phase timestamp |
PUT | /v1/projects/{project}/tasks/{filename}/clickup-task-id | set ClickUp task ID |
POST | /v1/projects/{project}/tasks/{filename}/increment-review-cycle | increment review cycle counter |
PUT | /v1/projects/{project}/tasks/{filename}/pr-url | store the PR URL |
PUT | /v1/projects/{project}/tasks/{filename}/pr-state | update PR review decision and check status |
POST | /v1/projects/{project}/tasks/{filename}/rename | rename the task (changes stored filename) |
pr reviews
| method | path | description |
|---|---|---|
POST | /v1/projects/{project}/tasks/{filename}/pr-reviews | record a PR review (idempotent by review ID) |
GET | /v1/projects/{project}/tasks/{filename}/pr-reviews/pending | list reviews not yet dispatched to a fixer |
GET | /v1/projects/{project}/tasks/{filename}/pr-reviews/{reviewID}/processed | check if a review has been processed |
POST | /v1/projects/{project}/tasks/{filename}/pr-reviews/{reviewID}/reacted | mark that a reaction was posted to a review |
audit events
| method | path | description |
|---|---|---|
GET | /v1/projects/{project}/audit-events | query audit log entries |
Query parameters: repeated kind= values, task, instance, after, before, and limit. after and before accept RFC3339 timestamps with optional fractional seconds; limit defaults to 100 and is capped at 500. Responses include stable id values for idempotent pollers. Because after is a strict timestamp filter, pollers should overlap windows and de-duplicate by id instead of relying on timestamp-only checkpoints.
linear webhooks
| method | path | description |
|---|---|---|
POST | /v1/projects/{project}/linear/webhook | ingest a signed Linear webhook delivery for the project |
the webhook endpoint is active only in repo-scoped serve mode (--repo, or daemon repo auto-detection when --db is not set). bare --db mode returns 503 for this route because kasmos cannot load the repo-local .env and [linear.triggers] configuration needed to verify and route Linear deliveries.
webhook requests must include Linear's signature and delivery headers and use the secret configured by [linear.triggers.webhook]. accepted deliveries are recorded quickly, queued, and drained asynchronously through the same guarded Linear trigger path as the poller. see linear triggers for setup and response details.
instances
Live-preview and permission endpoints for daemon-managed SDK instances. These routes
bridge the daemon control API to the browser-facing kas serve stack. Only
daemon-managed SDK instances support the structured presentation response; tmux
instances return supported: false.
| method | path | description |
|---|---|---|
GET | /v1/projects/{project}/instances/{title}/presentation | retrieve the current structured turn snapshot for a daemon-managed SDK instance; returns { supported, turns, captured_at } |
POST | /v1/projects/{project}/instances/{title}/permission | submit the user's permission choice for a pending prompt; body: { "choice": <0|1|2> } where 0 = allow once, 1 = allow always, 2 = reject |
Daemon instance rows returned through status/listing APIs may include last_activity and health_reason. health_reason is empty when the instance is healthy, or one of stale, paused_old, or exited.
MCP instance_list prefers the live daemon inventory, including daemon-owned SDK and tmux planners that are not persisted in the local state file. It falls back to the persisted state only when the daemon is unavailable.
The MCP instance action tools use the same daemon inventory first. instance_pause, instance_resume, instance_restart, and instance_send therefore work for daemon-owned SDK sessions as well as tmux sessions. capture_pane returns the daemon's structured SDK presentation turns when available, including every retained turn, and otherwise uses the daemon's terminal capture endpoint. Each action accepts an optional project argument. A title-only action is allowed only when that title is unique across the daemon's registered repositories; ambiguous titles fail closed and require project. Pause, resume, send, and capture fall back to the legacy persisted-instance implementation only when an unqualified title is not present in the live daemon inventory; restart requires a daemon-managed instance.
permission choice values:
| value | meaning |
|---|---|
0 | allow once (allow_once) |
1 | allow always (allow_always) |
2 | reject (reject) |
the presentation response shape:
{
"supported": true,
"captured_at": "2026-01-01T10:00:00Z",
"turns": [
{
"id": "turn-1",
"number": 1,
"started_at": "2026-01-01T10:00:00Z",
"completed_at": "2026-01-01T10:00:05Z",
"interrupted": false,
"tool_count": 2,
"rows": [
{ "kind": "tool", "text": "reading file", "tool_name": "Read", "timestamp": null, "is_error": false },
{ "kind": "result", "text": "contents", "tool_name": "", "timestamp": null, "is_error": false },
{ "kind": "response", "text": "", "tool_name": "", "timestamp": null, "is_error": false },
{ "kind": "prose", "text": "I found the file.", "tool_name": "", "timestamp": null, "is_error": false }
]
}
]
}
row kind values: thinking, tool, result, system, permission, response, prose, status.
admin ui
A built-in web admin UI is served at /admin/. To use an externally built admin SPA, pass --admin-dir pointing to the dist/ directory (must contain index.html).
mcp server
When --mcp is true (the default), a Streamable HTTP MCP server starts on --mcp-port (default 7434). The MCP endpoint is at http://<bind>:<mcp-port>/mcp. It exposes the task store and signal gateway as MCP tools, plus filesystem tools scoped to the current working directory and repo root.
the full mcp endpoint does not grant cors access to standalone files or arbitrary web origins. POST /v1/monitor/snapshot on the rest listener is the supported read-only host bridge. generated kas monitor widget files may still use POST /v1/widget-preview/open-monitor, which is retained as a deprecated alias with identical behavior. neither endpoint grants cors beyond the null origin. they accept monitor scope rather than a tool name and cannot route requests to any other mcp capability.
The task MCP tools include lifecycle and content operations such as task_list, task_show, task_create, task_update_content, task_delete, and task_transition. They also expose explicit Linear linking operations: task_link_linear fetches and stores a Linear issue link, while task_unlink_linear clears the stored link. In multi-project mode these tools accept an optional project argument to select the target project namespace.
The read-only live_status tool returns the canonical compact orchestration snapshot. It accepts project to select the target project (required in multi-project mode) and an optional numeric cap that limits each of the active_agents and attention arrays. The default cap is 20 and values above the hard maximum of 100 are reduced to 100.
The read-only open_monitor tool serves the Codex monitor widget and its initial structured snapshot. The app-only refresh_monitor tool returns subsequent snapshots without a widget template, preventing polling calls from remounting the rendered UI. In multi-project mode their projects fields follow the same live routing catalog as other MCP tools, so newly registered projects become selectable without restarting the server.
Daemon data is best effort for live_status. If the daemon control socket is unavailable, the tool still returns lifecycle counts and task-derived attention from the task store with daemon_running: false; daemon-derived agents, heartbeat fields, and stale_instance attention are unavailable. See the live status contract for the response fields and truncation semantics.
Long-lived MCP servers refresh that project namespace at request time. A project added to the daemon or shared task store after MCP startup can be selected immediately. When the live catalog is empty, single-repo mode preserves its working-directory project fallback so the first task can be created; an explicit --repo invocation remains restricted to its startup allowlist.
For signal-bearing transitions, MCP records the matching pre-applied signal. In particular, implement_start dispatches the architect or initial implementation wave even though the task is already in implementing state.
When [linear.receipts] is enabled, transitions driven through both the task actions REST endpoints and the MCP task_transition tool fire the same Linear receipt hooks as the CLI. See linear receipts for configuration and event allowlist details.