Navigate

API Reference

Complete reference for the Cephable Automate HTTP Server — base URL, authentication, every endpoint, request and response schemas, status codes, and error shapes.

Base URL

http://127.0.0.1:4317

The server binds 127.0.0.1 only — never 0.0.0.0, never a LAN address. Remote hosts cannot reach it.

If the preferred port is occupied, Cephable tries the next eleven ports (43174328) and reports the one it bound. Always read the endpoint from the extension detail view, an environment variable, or a discovery sweep — never assume 4317. See Finding the port.

http://localhost:4317 usually works too, but prefer the literal 127.0.0.1: on some systems localhost resolves to ::1 first, and the server is not listening there.


Authentication

Every route, including /health, requires the access key as a bearer token:

Authorization: Bearer <access key>
  • Comparison is constant-time. A missing, malformed, or wrong token returns 401 before routing, so an unauthenticated request cannot even discover which paths exist.
  • The key is generated by the app (32 random bytes, base64url — 43 characters), stored encrypted in OS secure storage, and must be at least 24 characters.
  • Regenerating the key in the app invalidates the old one immediately.
  • The key is deliberately not accepted as a command-line argument, because operating systems expose process command lines to other local processes.

Conventions

Content type application/json; charset=utf-8 on every response, with Cache-Control: no-store
Request bodies JSON. Max 1 MiB — larger bodies are rejected with 400
Concurrency One run at a time. /v1/runs, /v1/chat/completions, and /v1/automate/models/select return 409 while a run is in flight
Streaming Not supported. Run endpoints block until the run reaches a terminal state
CORS No CORS headers and no OPTIONS handler. A browser page on an http(s):// origin cannot call this server; use a native, Node, Electron main-process, or server-side client
Method mismatch Returns 404, not 405GET /v1/runs is "not found"

Endpoint summary

Method Path Purpose Allowed while busy
GET /health Readiness, runtime, device, and workspace info Yes
GET /v1/models OpenAI-shaped model list (always cephable-agent) Yes
GET /v1/automate/models The on-device GGUF catalog with availability Yes
POST /v1/automate/models/select Pin a model for this app session No — 409
POST /v1/automate/cancel Stop whatever is running, whoever started it Yes
POST /v1/runs Run an Automate task (native contract) No — 409
POST /v1/runs/{resumeToken}/tool-results Resume a run parked on your own tools Yes — by design
POST /v1/chat/completions Run an Automate task (OpenAI contract) No — 409, unless it carries tool results for a parked run

GET /health

No parameters. Returns the state of the server, the agent worker, the model, and the device.

curl -sS http://127.0.0.1:4317/health -H "Authorization: Bearer $CEPHABLE_AUTOMATE_KEY"
Field Type Notes
status "ok" Constant
service "cephable-agent" Use this to confirm a listener is Cephable when sweeping ports
appVersion string Desktop app version
platform string win32 · darwin · linux
architecture string x64 · arm64
osRelease string OS kernel/release string
cpu string First CPU model string, or "unknown"
logicalCpuCount number Logical cores
totalMemoryBytes number Physical RAM
workflowStatus string Agent status — see workflow statuses
activeRequestId string | null The run in flight, if any
modelName string | null GGUF file name currently loaded
workerRunning boolean Whether the workflow utility process is warm
busy boolean Whether this server is executing a run — including one parked awaiting your tool results
awaitingToolResults boolean A run is parked awaiting caller-executed tool results. Lets a client recovering from a crash tell "someone else's run" from "my own run waiting on me"
workspace string Absolute path of the Automate workspace folder
backend object | null { flavorId, accelerator, cpuFallback } — the llama.cpp acceleration actually in use
contextSize number | null The context window this device got. Sized from system RAM, so it varies per machine — record it in any comparison between runs
launchModelSelectionError string | null Why a --model/--family/--size launch argument could not be applied
automateModelSelection object | null The model pinned via /v1/automate/models/select, or null when the app's own selection is in effect

Ready to run means busy === false and workflowStatus is idle or terminated.

{
  "status": "ok",
  "service": "cephable-agent",
  "appVersion": "4.2.1",
  "platform": "win32",
  "architecture": "x64",
  "osRelease": "10.0.26200",
  "cpu": "AMD Ryzen 9 7940HS",
  "logicalCpuCount": 16,
  "totalMemoryBytes": 68719476736,
  "workflowStatus": "idle",
  "activeRequestId": null,
  "modelName": "gemma-4-4b-it-Q4_K_M.gguf",
  "workerRunning": true,
  "busy": false,
  "workspace": "C:\\Users\\you\\AppData\\Roaming\\Cephable\\automate-http-workspace",
  "backend": { "flavorId": "vulkan", "accelerator": "vulkan", "cpuFallback": false },
  "contextSize": 16384,
  "launchModelSelectionError": null,
  "automateModelSelection": null
}

GET /v1/models

The OpenAI-compatible model list. There is exactly one entry, and it represents the whole assistant rather than a raw model.

{
  "object": "list",
  "data": [{ "id": "cephable-agent", "object": "model", "owned_by": "cephable" }]
}

To see the actual GGUF catalog, use /v1/automate/models.


GET /v1/automate/models

The on-device model catalog as Cephable knows it, including which entries this device can run and which are already downloaded.

{
  "object": "list",
  "data": [
    {
      "name": "Gemma 4 M",
      "family": "Gemma",
      "sizeCode": "M",
      "parameterCountBillions": 4,
      "fileSizeMb": 2650,
      "supportsTools": true,
      "availableForDevice": true,
      "downloaded": true,
      "selected": true
    }
  ],
  "catalog": { "status": "ready", "modelCount": 7 }
}
Field Notes
name Exact catalog name — the value a modelName selector matches against
family / sizeCode Coarse selectors, e.g. Gemma + M
parameterCountBillions May be null
fileSizeMb May be null
supportsTools Must be true to be selectable; Automate requires tool calling
availableForDevice false when this device cannot run it (RAM, GPU, OS)
downloaded false means it must be downloaded in the Cephable UI first
selected The model that will serve the next run
catalog.status "loading" while the catalog is still syncing from Cephable; "ready" once available
catalog.modelCount Number of catalog entries

Poll until catalog.status is "ready" before selecting a model at startup — the catalog syncs asynchronously after app launch.


POST /v1/automate/models/select

Pin a specific on-device model for the current app session. This is a session preference: it overrides the account's synced model choice for the running process without changing the user's saved setting, and is cleared when the server stops.

Request — supply any combination of the three fields; the result must match exactly one catalog entry.

{ "modelName": "Gemma 4 M" }
{ "family": "Gemma", "sizeCode": "M" }
Field Type Notes
modelName string? Exact catalog name, case-insensitive
family string? Case-insensitive family match
sizeCode string? Case-insensitive size code, e.g. S, M, L

An empty object ({}) restores the app's own model selection and unpins yours.

Response

{
  "selected": { "name": "Gemma 4 M", "downloaded": true, "selected": true },
  "models": [ ]
}

selected is the full model option for the pinned model (or null when unpinning and the app has no preference); models is the refreshed catalog.

Errors

Status Cause
409 A run is in flight
400 No catalog match, ambiguous match, model not compatible with the device, model not tool-capable, model not downloaded, or the workflow is not idle

Switching models terminates a warm worker, so the next run pays a cold start. Select once at integration startup, not per request.


POST /v1/automate/cancel

Stops whatever the assistant is doing — a run you started, a run the user started in the panel, or a run another integration started. This is the one route that is not refused while a run is in flight, and it is safe to call when nothing is running, so a client recovering from a dropped connection can call it unconditionally.

Request (body optional)

{ "force": false }
Field Default Behavior
force: false default Asks the agent loop to unwind. The worker stays warm and the conversation survives, but it only lands between steps — a task already blocked inside a tool call will not notice
force: true Kills the workflow worker outright, exactly as the panel's Stop button does. Always works, at the cost of a cold start on the next run

Response — always 200

{ "stopped": true, "mode": "cancel", "requestId": "automate-run-…", "workflowStatus": "executing-progress" }
Field Notes
stopped false when there was nothing to stop
mode "cancel" · "terminate" · "none"
requestId The run that was stopped, or null
workflowStatus Status observed at the moment of the call

A run stopped by any route — including the panel's own Stop button — settles the blocking /v1/runs request that started it, rather than leaving it open until its timeout. That request then returns a record with status: "canceled" or "terminated" under HTTP 500.


POST /v1/runs

The native contract. Runs one Automate task and blocks until it reaches a terminal state.

Full treatment of every option, with examples, is in Running Automate tasks. The schema summary:

Request

Field Type Default Notes
prompt string required The task. Must be a non-empty string
taskId string? Your own correlation id, echoed back untouched
timeoutMs number? 900000 (15 min) Minimum 1000. On timeout the run is canceled and the request returns 400
thinkingLevel "low" | "medium" | "high" | "max" user setting Reasoning budget, applied per run
additionalWorkflowPrompt string? Advisory preferences appended to the system prompt
answerContract string? A binding required shape for the closing message. Returns finalAnswer alongside the untouched answer
include object? all true { steps?: boolean, trace?: boolean, events?: boolean } — set false to omit a diagnostic block
restrictToWorkspace boolean? false Confine file and CLI tools to the workspace folder. Can only narrow — a user's own restriction always wins
continuation boolean? false Continue the previous run's conversation instead of starting fresh
selectedSkillIds string[]? AI Skills to force into this run. Omit to let Cephable select by relevance
selectedMcpServerIds string[]? Configured MCP servers to force into this run. Omit for relevance-based selection
mcpServers object[]? Inline MCP servers for this run only — your own tools, without the user configuring anything. Max 8. See Custom tools
clientTools object[]? Tools you declare by JSON Schema and execute yourself. The run parks when the agent calls one. Max 32. See Custom tools
hitlAnswers Record<string, string | string[]>? Pre-supplied answers for request_user_input questions, keyed by field id
allowDestructiveTools boolean? false Approve destructive-tool requests (delete_path, run_command, move_path) instead of rejecting them

Response

{
  "schemaVersion": 1,
  "requestId": "automate-run-9c2e…",
  "taskId": "nightly-42",
  "status": "completed",
  "answer": "…",
  "finalAnswer": "…",
  "errorCode": "TOOL_TIMEOUT",
  "startedAt": "2026-09-14T18:02:11.004Z",
  "completedAt": "2026-09-14T18:02:48.771Z",
  "durationMs": 37767,
  "model": "gemma-4-4b-it-Q4_K_M.gguf",
  "appVersion": "4.2.1",
  "backend": { "flavorId": "vulkan", "accelerator": "vulkan", "cpuFallback": false },
  "steps": [ ],
  "trace": [ ],
  "usage": { "inputTokens": 5120, "outputTokens": 344, "generationMs": 8345, "ttftMs": 610, "tps": 41.2 },
  "events": [ ]
}
Field Always present Notes
schemaVersion Yes Always 1. The reliable signal that a run actually happened
requestId Yes Server-minted, automate-run-<uuid>
taskId Only when you sent one
status Yes completed · failed · canceled · terminated · awaiting_tool_results
toolCalls Only when status is awaiting_tool_results: the caller-executed tool calls to run
resumeToken Only when status is awaiting_tool_results: post results to /v1/runs/{resumeToken}/tool-results
answer Yes The closing message, exactly as a person would have seen it
finalAnswer Only when answerContract was set: the text after the last FINAL ANSWER: marker, or the whole answer if no marker was emitted
errorCode See workflow error codes
startedAt / completedAt Yes ISO 8601
durationMs Yes Wall clock, including model load and cold start
model Yes GGUF file name actually loaded, or "unknown"
appVersion Yes Desktop app version
backend Yes May be null if the runtime could not be queried
steps unless excluded Ordered tool calls with args, result summaries, produced paths and content
trace unless excluded Raw model message list
usage Yes null when no metrics were emitted
events unless excluded Every raw channel event. Large — the full step list is rebroadcast on every update, so a research run's stream runs to hundreds of KB

Status codes

Status Body Meaning
200 run record status === "completed", or awaiting_tool_results — a parked run is a successful exchange
500 run record The run ran and ended failed, canceled, or terminated. Not a server fault — schemaVersion is still 1
400 { error } Invalid request, body over 1 MiB, malformed JSON, run timeout, or an initialization failure
401 { error } Bad or missing bearer token
409 { error } A run is already active or preparing

POST /v1/runs/{resumeToken}/tool-results

Resume a run parked awaiting caller-executed tool results. Deliberately not refused while busy — the run it resumes is the reason the server is busy.

Request

{
  "results": [
    { "id": "client_tool_5f2a…", "result": "Order 4471: 2x widget, shipped 2026-09-02" },
    { "id": "client_tool_9b13…", "error": "the orders database is unreachable" }
  ]
}
Field Type Notes
results object[] Required. One entry per call you are answering
results[].id string Required. The id from the toolCalls entry
results[].result any What the model sees. A string passes through; anything else is JSON-encoded
results[].error string? Report a failure instead. The agent adapts rather than dying

Results are matched by id, not order. An id that matches nothing pending is ignored, which makes a retried resume safe.

Response — the run's next outcome: another awaiting_tool_results record (an agent loop can need several rounds), or the finished record. Same shape and status codes as /v1/runs, plus:

Status Cause
404 No parked run matches that token — it timed out (two minutes per round) or was cancelled
400 Malformed results

Full treatment in Custom tools.


POST /v1/chat/completions

The OpenAI-compatible contract over the same run engine. Non-streaming; each request executes the complete assistant loop. See OpenAI compatibility for the mapping, the cephable extension object, and the unsupported parameters.

{
  "model": "cephable-agent",
  "messages": [
    { "role": "system", "content": "Prefer metric units." },
    { "role": "user",   "content": "Summarize today's notes file." }
  ],
  "timeout_ms": 600000,
  "cephable": {
    "include": { "events": false },
    "answerContract": "End with FINAL ANSWER: <one sentence>"
  }
}

The full native run record is returned in the response's cephable field.


Error shape

Every non-run error uses the same envelope:

{ "error": { "message": "prompt must be a non-empty string", "type": "invalid_request_error" } }
type Status Cause
authentication_error 401 Missing or wrong bearer token
not_found 404 Unknown path, or the right path with the wrong method
conflict 409 A run is already active or preparing
invalid_request_error 400 Validation failure, oversized or malformed body, run timeout, model-selection problem, initialization failure

Distinguish a failed run from a failed request by checking for schemaVersion === 1 rather than by HTTP status.


Workflow statuses

Reported by /health as workflowStatus and by run records as status.

Ready: idle, and terminated (the worker is gone but nothing is running)

In progress: initializing · planning · thinking · executing-start · executing-progress · executing-complete · executing-org-block · executing-destructive-block · executing-type-focus-block · executing-permission-block · waitingForUser

Terminal for a run: completed · failed · canceled · terminated

Run-record only: awaiting_tool_results — not a workflow status. A run parked awaiting caller-executed tool results, still alive and still holding the inference slot. See Custom tools.


Workflow error codes

Returned as errorCode on a non-completed run.

Code Meaning
MODEL_LOAD_FAILED The GGUF could not be loaded
PLANNING_TIMEOUT The model did not produce a plan in time
TOOL_TIMEOUT A tool call exceeded its budget
EXECUTION_TIMEOUT The run exceeded its execution budget
EXECUTION_FAILED A step failed unrecoverably
CONTEXT_LIMIT_EXCEEDED The conversation outgrew contextSize
UNSUPPORTED_DEVICE The device cannot run AI Workflows
UNSUPPORTED_OS_VERSION The OS is below the supported minimum
DISABLED_BY_POLICY An organization policy blocked the run
SCHEMA_INVALID A tool call did not match its schema
SERVER_LOST The llama.cpp server went away mid-run
CANCELED Cancelled by a client, the panel, or a timeout