Rune Box docs

REST API

`runeward serve` exposes the control plane over HTTP (default `127.0.0.1:8080`), and every action goes through the same governed path as the CLI.

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

  • serve refuses a non-loopback --bind unless auth is configured.
  • Single token: --token or RUNEWARD_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_ISSUER and RUNEWARD_OIDC_AUDIENCE. Signed Rune Box claims map to the same model as local tokens.
  • Send Authorization: Bearer <token> or X-Runeward-Token on every request except /healthz and 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/tickets mints one: body {"kind":"ide","sandbox_id":"<id>"}, where kind may also be terminal or conversation (both need sandbox_id) or download.
  • Non-loopback listeners need TLS (--tls-cert/--tls-key) unless --allow-insecure-http acknowledges 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.