Skip to content

Dashboard API·

The cockpit server (dashboard_server.py, plus dashboard_replay.py and personas.py mounted on the same app) is a FastAPI application on :8080 (TLS by default). This table is regenerated from the route decorators at every docs build by scripts/routedoc.py; the anonymous? column is derived from the _PUBLIC_EXACT / _PUBLIC_PREFIXES allow-list in the auth middleware.

Authentication. After a passkey login the browser holds a short-lived HS256 JWT. Send it as Authorization: Bearer <jwt> on /api/* and as ?token=<jwt> when opening /ws/chat or /ws/voice. Anonymous /api/*401 {"error": …}; anonymous WebSocket → close code 4401. auth.issue_token(subject, name, ttl=) mints long-lived service tokens for scripts and sibling robots. See Auth.

Talking to the agent from a machine. POST /api/chat {"prompt": "…"} (or text, ≤ 600 chars) runs one synchronous agent turn (≤ 90 s, 504 on timeout) and returns {ok, result, reply, seconds}. It is the target of tiny.technology's endpoint proxy — such turns get no fleet tools (fleet=True), which enforces the one-hop depth cap described in Fleet.

Driving. POST /api/control {"linear": 0.4, "angular": 0, "duration": 0.3} is one frame; hold a stream of them for motion (the cockpit joystick sends them while pressed). Both the thinker drive gate and the clamp apply.

Health & telemetry·

method path params anonymous? what
GET /api/config 🔒 session Current model id, voice provider/name, system prompt and masked env keys for the ⚙️ drawer. · src
POST /api/config JSON 🔒 session Update system prompt / model / env vars. Rebuilds the agent. · src
GET /api/health ✅ public Liveness: {ok, sdk, …} — the only /api route without a session. · src
GET /api/telemetry 🔒 session The SDK's /data snapshot: battery, GPS, IMU, RPMs, lamp, signal. · src

Camera·

method path params anonymous? what
GET /api/frame/{view} 🔒 session Latest JPEG for front or rear (proxied from the SDK / hub). · src
GET /api/screenshot views: str 🔒 session Composite screenshot of views (default front,rear,map) from the SDK. · src

Control·

method path params anonymous? what
POST /api/control JSON 🔒 session One drive frame {linear, angular, duration} in [-1, 1]; hold a stream of them to move (joystick/WASD). · src
POST /api/lamp JSON 🔒 session Headlamp on/off {on}. · src
POST /api/speak JSON 🔒 session Say {text} through the rover's onboard speaker (SDK /speak). · src

Agent (Ask / chat)·

method path params anonymous? what
POST /api/chat 🔒 session tiny.technology endpoint-device chat (use_device invoke → here). Gated like everything else. · src
WS /ws/chat 🔒 session WebSocket: chat (streaming agent) · src
WS /ws/voice 🔒 session Voice: browser mic ↔ bidi model (PCM16 over WS). Pragmatic streaming bridge. · src

Personas·

method path params anonymous? what
GET /api/personas 🔒 session Snapshot of every persona: container state (voice/thinker/telegram) + flags (thinker_drive, recording). · src
POST /api/personas/{name} JSON 🔒 session Body: {"action": "start"|"stop"|"on"|"off"}. Container personas answer · src
GET /api/personas/{name}/logs n: int 🔒 session Last lines of that persona container's logs via the host supervisor. · src

Replay (datasets)·

method path params anonymous? what
GET /api/replay/datasets 🔒 session List datasets under the dataset root with episode counts and index_state. · src
GET /api/replay/{ds_id}/audio/{episode_index} 🔒 session Serve the per-episode WAV sidecar (mic capture) for timeline sync. · src
GET /api/replay/{ds_id}/episode/{episode_index} 🔒 session One episode: state/action rows + the aligned reasoning trace. · src
GET /api/replay/{ds_id}/episodes 🔒 session Episode index for a dataset (length, video window, task) with fallbacks when the parquet has no footer. · src
GET /api/replay/{ds_id}/frame/{view}/{episode_index}/{frame} 🔒 session Serve a single PNG frame for the image-sequence scrubber. · src
GET /api/replay/{ds_id}/frames/{view}/{episode_index} 🔒 session List available PNG frame indices for a LIVE (image-sequence) episode. · src
GET /api/replay/{ds_id}/memory/search q: str, k: int, modality: str, episode: int, objects: str 🔒 session Semantic memory search → hits carry frame_index for scrubber seek. · src
GET /api/replay/{ds_id}/memory/stats 🔒 session Counts for the dataset's memory/reasoning index. · src
GET /api/replay/{ds_id}/video/{view} file: Optional[str] 🔒 session Stream the mp4 for a camera view; ?file= selects the per-episode file. · src

Auth (passkeys)·

method path params anonymous? what
GET /auth/credentials ✅ public List enrolled passkeys (admin only). · src
POST /auth/credentials/delete JSON ✅ public Delete a passkey {id}; the last one cannot be removed. · src
POST /auth/credentials/rename JSON ✅ public Rename a passkey {id, name} (session required inside the handler). · src
POST /auth/login/begin ✅ public Issue a login challenge. · src
POST /auth/login/finish JSON ✅ public Verify the assertion and issue the session JWT. · src
POST /auth/logout ✅ public Drop the session. · src
POST /auth/register/begin JSON ✅ public Start a WebAuthn registration ceremony (first one may require the bootstrap token). · src
POST /auth/register/finish JSON ✅ public Verify the attestation and store the new passkey's public key. · src
GET /auth/status ✅ public setup_required (no passkeys yet), enabled, current session subject. · src

Shell & trust·

method path params anonymous? what
GET / ✅ public The cockpit SPA shell (docs/index.html); the login/enrol screen loads from here. · src
GET /ca ✅ public Serve the mkcert root CA so iOS/Android can trust scout's HTTPS. · src
GET /field-card ✅ public Printable QR field-setup card (public — it's just the access URL). · src
GET /replay ✅ public The dataset replay page (docs/replay.html). · src
GET /trust ✅ public On-device CA-trust helper: QR to /ca + iOS/Android step-by-step. · src

38 routes; 15 answer without a session (health, the passkey ceremony, the page shells and the trust/CA pages), every other /api/* route returns 401 to anonymous callers and the WebSockets close with 4401.

WebSocket message shapes·

/ws/chat — open with ?token=<jwt>. Client sends {"type":"chat","text":"…"} (a bare string is treated as chat), {"type":"control", "linear","angular","duration"} for joystick frames (answered with {"type":"control_ack"}, {"stop":true} on release) and {"type":"ping"}pong. The server streams the agent turn as {"type":"token","data","complete"}, {"type":"tool", …}, {"type":"reasoning","data"}, then {"type":"done","text"} or {"type":"error","error"}.

/ws/voice — binary PCM16 frames up (the browser mic); {"type":"voice_meta","rate"} once, then {"type":"audio","data":"<base64>"} frames down; {"type":"stop"} ends the session. Provider and voice follow the dashboard config.