HTTP API
Everything is served from one origin. system owns the root path; each app's router is mounted under /app/<id>/. Routes inside an app are written without that prefix.
| Prefix | Owner |
|---|---|
/ |
system — container, event/, assets/, app registry, scenes |
/app/explorer/ |
explorer |
/app/editor/ |
editor |
/app/agent/ |
agent |
There is no authentication. The server binds 127.0.0.1; see Deploy for reaching it safely.
Streaming
POST /app/agent/api/chat and POST /app/agent/api/run send text/event-stream whose body is newline-delimited JSON — one object per line, not SSE data: frames:
{"type":"session","path":"…/20261021-110716-yggu.sss"}
{"type":"thinking_delta","text":"…"}
{"type":"text_delta","text":"Let me look"}
{"type":"tool_use","name":"bash","input":{"command":"ls"}}
{"type":"tool_result","name":"bash","content":"…","isError":false}
{"type":"usage","input":1234,"output":56}
{"type":"done"}
| Type | Meaning |
|---|---|
session |
Path of the session file being written (first line of a new conversation) |
text_delta / thinking_delta |
Incremental model output |
tool_use |
The model called a tool |
tool_result |
That tool returned |
search_result |
Web search results |
usage |
Token counts |
retry |
The upstream call failed and is being retried |
error |
Request-level failure |
done |
Turn finished |
out / exit |
Shell output and exit code — only from /api/run |
Closing the connection aborts the turn, including a bash call in progress.
system
| Method | Path | Body / query | Returns |
|---|---|---|---|
| GET | /api/health |
— | { "ok": true, "app": "dox" } |
| GET | /api/app |
— | Registered apps, minus hidden: { id, name, entry, renders? } |
| GET | /api/stats |
— | { rss, heapUsed, heapTotal, external } for the server process |
| POST | /api/scene/save |
{ path, windows } |
Writes a .dox scene |
| GET | /api/scene/load |
?path= |
The saved scene |
/api/health exists so the launcher can tell dox apart from whatever else holds port 3000.
agent — /app/agent
| Method | Path | Body / query | Returns |
|---|---|---|---|
| GET | /api/config |
— | { baseUrl, apiKey, model, workspace, defaultModel? } |
| PUT | /api/config |
partial config | Merged config |
| GET | /api/models |
— | { models: [{ id, label, baseUrl, apiKey, model, reasoningEffort?, tools? }] }, read from dox-data/agent/models/*.env |
| PUT | /api/models |
{ models } |
Syncs the directory: writes each model to <id>.env, deletes files no longer listed; at least one required |
| GET | /api/sessions |
— | { sessions: [{ path, title, updatedAt, count }] } |
| GET | /api/session |
?path= |
{ path, title, messages, updatedAt, model? } |
| PUT | /api/session |
{ path, title?, messages?, model? } |
{ ok: true } — model is a model id; send an empty string to clear it |
| DELETE | /api/session |
?path= |
{ ok: true } |
| GET | /api/session-meta |
?path= |
{ title, count, created, updated } — what the explorer row shows |
| POST | /api/chat |
{ sessionPath, text, images?, model? } |
Stream (above). Empty sessionPath creates a new .sss and reports it in the session event. model is a model id: it overrides the session's pinned value and is written into the session |
| POST | /api/run |
{ command } |
Stream of out / exit — runs a shell command without the model |
images is an array of { data, media_type } with base64 data, passed to the model as image blocks.
curl -sN -X POST http://127.0.0.1:3000/app/agent/api/chat \
-H 'content-type: application/json' \
-d '{"sessionPath":"","text":"what is in this folder?"}'
explorer — /app/explorer
| Method | Path | Body / query | Returns |
|---|---|---|---|
| GET | /api/root |
— | { root } — default browse root |
| GET | /api/list |
?path= |
{ entries: [{ name, isDir, size? }] }, directories first |
| GET | /api/stat |
?path= |
{ exists, isDir } |
| GET | /api/file |
?path= |
Raw bytes, capped at 50 MB — used for thumbnails |
| POST | /api/mkdir |
{ path } |
Creates a directory |
| POST | /api/mkfile |
{ path } |
Creates an empty file |
| POST | /api/rename |
{ path, newName } |
Renames in place |
| DELETE | /api/delete |
?path= |
Deletes a file or a tree |
| POST | /api/copy |
{ src, destDir } |
Copies |
| POST | /api/move |
{ src, destDir } |
Moves |
editor — /app/editor
| Method | Path | Body / query | Returns |
|---|---|---|---|
| GET | /api/stat |
?path= |
{ exists, size? } |
| GET | /api/read |
?path= |
{ path, content } |
| POST | /api/write |
{ path, content } |
Writes and returns the new stat |
Notes
- Paths are normalised server-side; a relative path is resolved against the process's working directory. Pass absolute paths when in doubt.
- Every error response is
{ "error": "…" }with a 4xx/5xx status. A thrown handler returns500 {"error":"internal error"}and does not affect other requests. GET /serves the container (icanvas/index.html).