HTTP API reference¶
For client-side React integration contracts, see docs/ui-hook-api.md.
This page lists every route that is part of Jarela's stable HTTP API. A
route is part of the contract only if its source file carries a @public
JSDoc header; everything else under app/api/v1/* is considered UI-internal
and may change between minor versions.
The contract follows the deprecation policy in
CONTRIBUTING.md → Public API surface:
deprecate in 0.X.0, remove no earlier than 0.(X+1).0.
Auth. All routes require a same-origin request (or the loopback bypass for the bin/CLI). See
lib/auth/access.ts. CORS is opened only on the page-capture endpoint, for the browser extension.Schemas. Request/response shapes are validated with
zodat the route boundary. The schema location is given per-route below — link directly into the source for the authoritative shape.Versioning. All routes live under
/api/v1. A v2 prefix would only appear on a major bump.
Health¶
GET /api/v1/health¶
Liveness/readiness probe. Returns { ok, db_path, agent_count, master_key_source, version }.
- Source:
app/api/v1/health/route.ts - Used by: browser extension heartbeat, external uptime monitors
- Auth: loopback or same-origin
Threads¶
A thread is a single conversation; messages, tool calls, and run state all live inside one.
GET /api/v1/threads¶
List threads, newest first.
POST /api/v1/threads¶
Create a thread bound to an agent.
- Source:
app/api/v1/threads/route.ts - Body schema:
{ agent_id: string, title?: string }
GET /api/v1/threads/[thread_id]¶
Read messages (paged or "after a marker") for one thread. before/after
are message seq values (the server-assigned monotonic order), not
timestamps — pass the seq of the oldest/newest message you already have.
PATCH /api/v1/threads/[thread_id]¶
Rename or rebind the thread to a different agent.
DELETE /api/v1/threads/[thread_id]¶
Drop the thread, its messages, and its checkpoint state.
POST /api/v1/threads/[thread_id]/run¶
Submit a run. Returns immediately with the run id; output is streamed via the GET on the same path.
GET /api/v1/threads/[thread_id]/run¶
Subscribe to the in-flight run as a Server-Sent Events stream. Reconnects resume from the last seen sequence id.
PATCH /api/v1/threads/[thread_id]/run¶
Steer the run that is already streaming (ADR-0080). Body: { "message": "…" }.
The message is queued and delivered before the agent's next model call,
alongside the tool results it should react to — the run is not aborted.
Returns 409 { "steered": false } when no run is active, in which case submit a
normal POST instead.
DELETE /api/v1/threads/[thread_id]/run¶
Abort the in-flight run. This is the only interrupt; typing mid-run steers.
- Source:
app/api/v1/threads/[thread_id]/run/route.ts - Stream chunk types:
text,thinking,tool_call,tool_result,tool_progress(zero or more per call, live status from a still-running tool — ADR-0073),reset_text(discard prior live text before an output-validator replacement retry),usage,done(seelib/agents/base.tsfor the full union)
Agents¶
GET /api/v1/agents¶
List configured agents.
POST /api/v1/agents¶
Upsert an agent config. The full schema (identity, instructions, tools,
model_config_name, harness_id, delegation, etc.) lives in
lib/stores/agent-configs.ts.
- Source:
app/api/v1/agents/route.ts
GET / PATCH / DELETE /api/v1/agents/[id]¶
Read, update, or delete one agent config.
- Source:
app/api/v1/agents/[id]/route.ts
Tools¶
GET /api/v1/tools¶
Returns every tool in the agent's pool with { name, description, source,
category, capability, group, mcp_server, stats }. Source is
builtin | external | mcp. Capability is read | write | execute.
mcp_server is populated for MCP-sourced tools so clients can render
MCP -> server -> tools permission hierarchies.
Query parameters:
-
q— optional case-insensitive search across name, description, category, capability, source, group, and MCP server. -
Source:
app/api/v1/tools/route.ts - Agent equivalent:
list_toolstool — same data, callable from inside an agent run, with the samequerysearch behavior.
Skills¶
Packaged built-in skills are always readable. User skills are layered on top
from the repos in the skill_repos DB table (ADR-0074) and override built-ins
with the same id. Repos are scanned in the order they were added — a later
repo's skill overrides an earlier repo's (and built-ins) on id collision, so
a team-shared repo can be layered under a personal one. Writes and deletes
always target the one repo flagged writable, so the rest can be read-only
clones; POST /api/v1/skills and friends 503 with "No writable skill repo is
configured" until at least one repo exists (the first repo created becomes
writable automatically unless writable: false is passed explicitly).
GET /api/v1/skills/repos¶
List configured skill repos: { repos: [{ id, path, label, writable, enabled, created_at, updated_at }] }.
POST /api/v1/skills/repos¶
Add a repo. Body: { path, label?, writable? }. path must already exist
and be a directory; 409 if a repo for that path already exists.
GET|PATCH|DELETE /api/v1/skills/repos/[id]¶
Fetch, update ({ label?, enabled?, writable? }), or remove one repo.
Setting writable: true on one repo clears it on any other.
- Sources:
lib/skills/index.ts,lib/stores/skill-repos.ts,app/api/v1/skills/route.ts,app/api/v1/skills/[id]/route.ts,app/api/v1/skills/repos/route.ts,app/api/v1/skills/repos/[id]/route.ts - Agent equivalent:
list_skills,read_skill, andwrite_skilltools (repo management has no agent tool yet — API only).
Models¶
GET /api/v1/models¶
List model configs (per-model parameter presets that agents bind to).
POST /api/v1/models¶
Upsert a model config.
- Source:
app/api/v1/models/route.ts
Providers¶
GET /api/v1/providers¶
Lists every registered LLM provider name (built-in + external .cjs
plugins under ~/.jarela/providers/).
- Source:
app/api/v1/providers/route.ts - Agent equivalent:
list_providersanddescribe_providertools.
Page capture (browser extension)¶
POST /api/v1/page-capture¶
Receives a page-capture upload from the browser extension and routes it into the most recently active thread on the default agent.
Request body (JSON):
| field | type | required | notes |
|---|---|---|---|
url |
string | yes | Page URL the element was picked from. |
text |
string | yes | Element text content (truncated to 100 KB UTF-8 server-side). |
capturedAt |
string | yes | ISO-8601 timestamp. |
title |
string | no | Document title (≤500 chars). |
selector |
string | no | CSS selector path of the picked element (≤ 2000 chars). |
tagName |
string | no | Tag name of the picked element (≤ 64 chars). |
screenshot |
string | no | Base64-encoded PNG of just the picked element (≤ 4 MB encoded). No data: URL prefix. |
screenshotMediaType |
string | no | MIME type for the screenshot (default image/png). |
When screenshot is present the persisted user message is stored as a
multipart ContentPart[] of [text, image] so the chat UI renders the
picture inline and vision-capable models see it on the silent observer
turn that fires immediately after.
Response: { thread_id, msg_id, agent_id, agent_name, thread_title, created_thread, truncated, originalBytes }.
OPTIONS /api/v1/page-capture¶
CORS preflight.
- Source:
app/api/v1/page-capture/route.ts,lib/api/page-capture.ts - Auth: loopback only (
Host:must belocalhost/127.0.0.1); CORS reflects the requestOriginso the extension passes preflight.
Events (notification stream)¶
GET /api/v1/events¶
Server-Sent Events stream of in-process notifications: run completion, watcher fires, queue progress, bridge messages.
- Source:
app/api/v1/events/route.ts - Event types: see
lib/notifications/bus.tsfor the full union (run_completed,task_completed,bridge_message_received, etc.)
Out of scope (UI-internal routes)¶
The following endpoints exist but are NOT part of this contract — they serve the in-app UI and are subject to change without notice:
/api/v1/health/probes/api/v1/events/test/api/v1/threads/[thread_id]/context-pin/api/v1/delegations/codex/[job_id]/api/v1/agents/[id]/compact,/display-filters,/thread/api/v1/models/[name]/api/v1/providers/[provider]/models,/github-copilot/auth/api/v1/extensions/.../api/v1/integrations/.../api/v1/mcp-servers/.../api/v1/scheduled-tasks/.../api/v1/watchers/.../api/v1/memory/.../api/v1/dashboard/.../api/v1/voice/.../api/v1/documents/.../api/v1/env-sync/.../api/v1/proxy-config/.../api/v1/access/.../api/v1/config/.../api/v1/harnesses/...
If you build something that depends on any of these, file an issue so we
can decide whether to promote them to @public.