Runtime API.
Submit local recipe jobs, poll their status, upload inputs and retrieve outputs, and distinguish Runtime's short-lived job store from Code's session API.
Runtime's API installs and executes recipes and transfers their files. It is separate from Code's conversational session API. This guide follows the registered routes in CLI 0.9.0.
Start the local service
kaitoi runtime serve --host 127.0.0.1 --port 8766
Unlike Code serve, Runtime accepts a host override. Keep loopback for local
clients; changing the host changes who can reach the service. Runtime stores a
machine token in its config folder's server-token, or accepts
KAITOI_RUNTIME_TOKEN. There is no --token serve option. Config/cache locations
honor XDG on Unix and APPDATA/LOCALAPPDATA on Windows.
Only GET /health is public. Other routes require
Authorization: Bearer <runtime-token>. Browser CORS and interactive OpenAPI
docs are disabled. The machine token is not your Kaitoi account API key.
Submit, poll, then collect
POST a job with the recipe's own inputs, for example the authored recipe from the recipe guide:
{
"recipe": "hello-text",
"inputs": { "message": "Hello from the API" }
}
The recipe name must resolve in that Runtime. Optional fields are backend,
timeout, and force_reinstall. A 202 response with job_id means accepted;
validation or execution failure can still arrive in the polled job.
Submit POST /jobs, keep job_id, and poll GET /jobs/{job_id}. Pending work moves to running, then completed with a result or failed with an error. Download declared output files separately. Completed and failed records are in memory and can be removed after 300 seconds; restarting Runtime loses them. There is no job cancellation or SSE endpoint in this API.
The example keeps ticket j1 through pending, running and a completed or failed result. A collected local file can remain after the terminal job record becomes eligible for lazy removal; a failed job has no successful file to collect.
Poll for pending, running, completed, or failed. Successful results
include outputs, duration, backend, recipe name/version, and stderr. Failure
includes an error and, when provided, an error code. Job records are in memory;
terminal jobs are eligible for lazy removal after 300 seconds and all jobs
disappear on server restart. Save the result you need promptly.
Route reference
| Method and path | Purpose |
|---|---|
GET /health |
Public status, version, and input/source-policy metadata. |
GET /hardware |
Detected hardware. |
POST /jobs |
Submit {recipe, inputs, backend?, timeout?, force_reinstall?}. |
GET /jobs/{job_id} |
Poll status and eventual result or error. |
POST /install |
Install {recipe, backend?, force?}. |
GET /packages |
Installed package metadata. |
GET /recipes/available |
Registry entries and installed flags. |
GET /packages/{name}/recipe |
Installed recipe YAML and companion source. |
DELETE /packages/{name} |
Uninstall a package. |
POST /upload |
Multipart file upload; returns {path}. |
GET /files?path=... |
Download a resolved file within Runtime cache. |
There is no registered POST /run, cancel-job route, or SSE job stream. Use the
job submission and polling routes even if older help text mentions /run.
Respect remote input and file boundaries
HTTP jobs enforce the remote input policy. remote: false fields cannot be
supplied by the caller, though their defaults can apply. File inputs must use a
path returned by /upload; that is a Runtime cache path, not a Kaitoi cloud
file ID. Path-like strings and unapproved model/weight selectors are restricted.
Bounded enums or explicitly remote-enabled selectors define the allowed choices.
Download only returned files within Runtime cache through /files. Arbitrary
machine paths and cloud library files are outside that transfer contract.
Use the in-process Python API when appropriate
For owner-local Python execution, the distinct kaitoi_runtime package offers:
from kaitoi_runtime import run
result = run("./recipe.yaml", inputs={"message": "Hello"})
print(result.outputs)
This synchronous helper uses asyncio.run. Inside an existing async loop, use
await Runner().run(...) after importing Runner instead. It returns a
RunResult, executes locally, and does not apply HTTP-only remote restrictions.
It is unrelated to KaitoiCodeClient and does not create a Code conversation.
Last reviewed against Kaitoi on 24 October 2026. View this page as Markdown