Paths use the Rune Box names: citadels (sandboxes), charters (policies), cohorts (agent groups), chronicle (signed audit trail), conclave (approvals), perimeter (network controls), rationing (budgets).
Authentication
serverefuses a non-loopback--bindunless auth is configured.- Single token:
--tokenorRUNEWARD_API_TOKEN. Multi-principal RBAC:RUNEWARD_AUTHZ_FILE, a JSON store of principals, each with a token, launch scope, optional approval-profile scope and admin flag. - OIDC:
RUNEWARD_OIDC_ISSUERandRUNEWARD_OIDC_AUDIENCE. Signed Rune Box claims map to the same model as local tokens. - Send
Authorization: Bearer <token>orX-Runeward-Tokenon every request except/healthzand the static dashboard shell. - Under RBAC, non-admins see only their tenant's resources; admins see all. Agents can share a tenant and stay separately attributable.
- The terminal WebSocket uses a short-lived, single-use scoped ticket, so long-lived credentials never appear in URLs.
POST /v1/ticketsmints one: body{"kind":"ide","sandbox_id":"<id>"}, wherekindmay also beterminalorconversation(both needsandbox_id) ordownload. - Non-loopback listeners need TLS (
--tls-cert/--tls-key) unless--allow-insecure-httpacknowledges a trusted TLS-terminating proxy. - Request bodies are capped at 16 MiB.
See Security.
Errors
Non-governance failures carry a stable code: authentication_required, authz_denied, not_found, conflict, rate_limited, invalid_request or internal_error. Policy denials return {"verdict":"deny",...}. Approval pauses return {"verdict":"require-approval","approval_id":"..."}. SDKs raise different exception types for authorization and policy denials.
Health and identity
| Method | Path | Description |
|---|---|---|
GET |
/healthz |
Liveness probe (unauthenticated). |
GET |
/v1/whoami |
Identity and effective capabilities, including launch and approval scopes. |
GET |
/v1/readiness?profile=NAME |
Policy, runtime, secret-source and image readiness, without exposing host paths or secrets. |
GET |
/metrics |
Prometheus metrics. |
GET |
/v1/charters |
Reachable policies (under RBAC, the caller's allowed_profiles). |
Sandboxes
| Method | Path | Description |
|---|---|---|
POST |
/v1/citadels |
Create. Takes profile, admin-only copy_from, and optional lineage parent_citadel, run_id, agent, provider, model. A child's profile must be the parent's or provably no broader (Charter subsumption), else 403. |
GET |
/v1/citadels |
List (caller-scoped under RBAC). |
GET |
/v1/citadels/{id} |
Get one, with owner, capabilities and cumulative usage. |
DELETE |
/v1/citadels/{id} |
Kill and remove. |
GET |
/v1/citadels/{id}/workspace |
Download the workspace as tar. |
GET |
/v1/citadels/{id}/evidence |
Resolved policy plus signed audit as evidence JSON. |
POST |
/v1/citadels/{id}/fork |
Copy into a new sandbox (profile, run_id, agent, provider, model, nano_cpus, memory_bytes). A policy not provably within the source's (Charter subsumption) needs an admin. |
POST |
/v1/citadels/{id}/sleep |
Sleep a persistent sandbox; 409 citadel_busy while calls, terminals or turns are active. |
POST |
/v1/citadels/{id}/wake |
Wake it. Any governed call also wakes it. |
GET |
/v1/citadels/{id}/workspace/status |
running/sleeping, idle timeout, last sleep/wake, forked_from. |
POST |
/v1/citadels/{id}/snapshot |
Snapshot the workspace. |
GET |
/v1/snapshots |
List snapshots (tenant-scoped). |
POST |
/v1/snapshots/{id}/restore |
Restore a snapshot. |
Governed actions
Paths are under /v1/citadels/{id}.
| Method | Path | Description |
|---|---|---|
POST |
/shell/exec |
Run a shell command. |
POST |
/code/python |
Run Python (needs the python capability). |
POST |
/code/node |
Run Node (needs the node capability). |
POST |
/file/read |
Read a file. |
POST |
/file/write |
Write a file. |
POST |
/file/list |
List files. |
POST |
/file/search |
Search files. |
POST |
/usage |
Report model usage, e.g. {"tokens":123,"cost_usd":0.04}; counts toward rationing.max_tokens/max_cost_usd. |
GET |
/perimeter |
Network-control decision log. |
GET |
/terminal |
WebSocket terminal (same-origin only). |
POST |
/terminal-ticket |
Mint a short-lived terminal ticket. |
GET |
/conversation |
Bounded, redacted chat history (after_id, limit). |
POST |
/conversation |
Publish a user, assistant, tool or system turn. |
GET |
/conversation/stream |
Read-only chat WebSocket; needs a scoped conversation ticket. |
Agent sessions
| Method | Path | Description |
|---|---|---|
POST |
/v1/citadels/{id}/agent-sessions |
Launch a durable, observable agent command. |
GET |
/v1/agent-sessions |
List, optionally by cohort_id. |
GET |
/v1/agent-sessions/{id} |
Metadata and terminal status. |
GET |
/v1/agent-sessions/{id}/events |
Redacted stdout/stderr events after a sequence cursor. |
GET |
/v1/agent-sessions/{id}/stream |
Replay after after (or Last-Event-ID), then follow live over SSE. |
POST |
/v1/agent-sessions/{id}/turns |
Start the next turn (command, optional model); 409 session_busy while one is active. |
POST |
/v1/agent-sessions/{id}/cancel |
Cancel the active turn (does not rewind). |
Runs
Durable lineage records that outlive the sandbox: tenant, actor, policy, agent/provider/model, optional parent run, timestamps and terminal status.
| Method | Path | Description |
|---|---|---|
GET |
/v1/runs |
List accessible runs (tenant-scoped). Delegated children and forks carry charter_lineage (exact, subsumed or admin-override), parent_charter and charter_proof. |
GET |
/v1/runs/{id} |
Get one run. |
Agent groups
Paths after the first two rows are under /v1/cohorts/{id}.
| Method | Path | Description |
|---|---|---|
POST / GET |
/v1/cohorts |
Create or list groups. |
GET / DELETE |
/v1/cohorts/{id} |
Get or tear down a group. |
GET / POST |
/tasks |
List or add tasks. |
POST |
/claim |
Claim the next task; returns a signed lease_token. "context": true (and memory_bytes) also returns its context. |
POST |
/tasks/{taskID}/complete |
Complete; needs lease_token, accepts a handoff note. |
POST |
/tasks/{taskID}/fail |
Fail; needs lease_token, accepts a handoff note. |
POST |
/tasks/{taskID}/heartbeat |
Renew the lease with the current token; returns a fresh one. |
POST |
/tasks/{taskID}/children |
Add a child task (payload). |
POST |
/tasks/{taskID}/notes |
Add a handoff note (text). |
PUT |
/tasks/{taskID}/brief |
Set or clear an agent's brief (agent, * for all; brief). |
GET |
/tasks/{taskID}/context |
Notes, brief (?agent=), parent and ranked memory. |
GET |
/memory |
List memory, or search with query, tags, limit, max_bytes. |
POST |
/memory |
Write (key, text, tags, optional expected_version; 409 version_conflict when stale). |
GET / DELETE |
/memory/{key} |
Read or delete (?version= makes delete conditional). |
Schedules
| Method | Path | Description |
|---|---|---|
GET / POST |
/v1/citadels/{id}/schedules |
List or create schedules for a sandbox. |
GET / POST |
/v1/cohorts/{id}/schedules |
List or create schedules for an agent group. |
GET |
/v1/schedules |
List visible schedules. |
GET / DELETE |
/v1/schedules/{id} |
Read or delete. |
POST |
/v1/schedules/{id}/run |
Fire now; policy, precheck and budgets still apply. |
A schedule body has exactly one of cron (5 fields, UTC) or every (a duration such as 15m or 1h30m, at least 1m), plus command and optional prompt, precheck, agent, model. See Workspaces.
Signed audit trail
| Method | Path | Description |
|---|---|---|
GET |
/v1/citadels/{id}/chronicle |
Audit events for a sandbox. |
GET |
/v1/chronicle/verify |
Verify the on-disk hash chain. |
GET |
/v1/chronicle/pubkey |
The ledger's ed25519 public key. |
GET |
/v1/chronicle/export |
Export a signed transcript bundle. |
Approvals
| Method | Path | Description |
|---|---|---|
GET |
/v1/conclave |
Pending approvals. |
POST |
/v1/conclave/{id}/approve |
Approve a paused action. |
POST |
/v1/conclave/{id}/deny |
Deny a paused action. |
Experimental surfaces
Warning: Both are off by default. Enable the browser only in a trusted deployment after reading Security.
Browser
Needs RUNEWARD_ENABLE_EXPERIMENTAL_BROWSER=1 and a browser-capable policy.
| Method | Path | Description |
|---|---|---|
POST |
/v1/citadels/{id}/browser |
One-shot action. |
POST |
/v1/citadels/{id}/browser/sessions |
Open a stateful session. |
POST |
/v1/citadels/{id}/browser/sessions/{sid}/act |
Act in a session. |
DELETE |
/v1/citadels/{id}/browser/sessions/{sid} |
Close a session. |
Browser IDE
code-server against /workspace. Needs RUNEWARD_ENABLE_EXPERIMENTAL_IDE=1, policy [ide] enabled = true, and an ide or ide-agents image from deploy/Dockerfile.ide.
| Method | Path | Description |
|---|---|---|
POST |
/v1/citadels/{id}/ide-ticket |
Mint a short-lived IDE ticket (or kind=ide via POST /v1/tickets). |
GET |
/v1/citadels/{id}/ide / /ide/{path...} |
Reverse proxy (HTTP and WebSocket). Open with ?ticket=…. |
The ticket is single-use; a session cookie covers later asset loads. Sandbox list/get may include ide / ide_agents. Limits: no per-keystroke policy, no Cursor, Claude Desktop or Codex GUIs inside the sandbox, and no first-class GitHub Copilot (Open VSX). Details: Browser IDE.
Example
AUTH=(-H "Authorization: Bearer $RUNEWARD_API_TOKEN") # omit when serving without a token: AUTH=()
SB=$(curl -s "${AUTH[@]}" -X POST localhost:8080/v1/citadels -d '{"profile":"ns-auto"}' | jq -r .id)
curl -s "${AUTH[@]}" -X POST "localhost:8080/v1/citadels/$SB/shell/exec" -d '{"command":["echo","hi"]}'
curl -s "${AUTH[@]}" "localhost:8080/v1/chronicle/verify"
curl -s "${AUTH[@]}" -X DELETE "localhost:8080/v1/citadels/$SB"
Written from docs/rest-api.md at commit 1ee29ff4ab36. Rune Box is open source under Apache-2.0.