Dashboard and API
cos serve runs a web dashboard and a small JSON and WebSocket API on 127.0.0.1.
cos serve starts the dashboard at http://127.0.0.1:9120. Use it to chat with any profile, approve tool calls, stop running turns, browse sessions and see costs. Everything it does goes through the API below, so scripts can do the same.
Routes
| Route | Returns |
|---|---|
GET / |
The dashboard page |
GET /api/profiles |
Profiles with tags, provider, model, skills and effective tools |
GET /api/sessions?profile=&limit= |
Sessions, newest first, without child sessions. limit defaults to 50, max 500. |
GET /api/sessions/{id} |
One session’s messages, turns (including children) and tool calls with approvals |
GET /api/plugins |
Names of the running plugins |
GET /api/approvals |
Ids of approvals waiting for an answer |
WS /api/ws |
Chat, approvals, stop and live events |
| Plugin routes | For example CommonBill’s GET /api/costs |
Errors come back as HTTP 500 with {"error": "…"}.
GET /api/profiles
[
{
"id": "Household",
"loaded": true,
"provider": "mock",
"model": "mock-1",
"tags": ["area:household"],
"skills": "",
"tools": ["delegate_task", "memory", "session_search"],
"created_at": "2026-10-27T00:50:42.568734Z"
}
]tools is what the agent really gets: the profile’s tools list, or every installed tool.
GET /api/sessions
[
{
"id": "01a17ad6-8926-7622-a9a6-52f6cdc0808f",
"profile_id": "Household",
"source": "cli",
"title": "hello there",
"tags": [],
"parent_session_id": null,
"context_snapshot": "MEMORY (your notes) — 0% used, 0/2200 chars\n(empty)\n\nUSER (about the person) — 0% used, 0/1375 chars\n(empty)",
"created_at": "2026-10-27T00:50:42.600115Z",
"updated_at": "2026-10-27T00:50:43.124892Z"
}
]context_snapshot is the frozen context tier of the session’s prompt.
WebSocket
Connect to ws://127.0.0.1:9120/api/ws. Every message is JSON with a type.
Client to server
{ "type": "chat", "profile": "Household", "session_id": null, "text": "hello", "tags": ["project:kitchen"] }
{ "type": "approve", "id": "<approval id>", "approved": true }
{ "type": "stop", "session_id": "<session id>" }| Message | Does |
|---|---|
chat |
Sends a message. session_id: null starts a new session. tags is optional and applies to a new session. |
approve |
Answers a pending approval |
stop |
Cancels the running turn of a session |
Server to client
| Message | When |
|---|---|
{"type": "event", "kind", "turn", "payload", "at"} |
Live events as a turn runs. kind is the hook point: on_session_start, pre_api_request, post_api_request, api_request_error, post_tool_call, pre_approval_request, post_approval_response, subagent_start, subagent_stop, post_llm_call, agent_loop_stopped, on_session_end. |
{"type": "reply", …} |
The turn finished. Carries profile_id, session_id, turn_id, status and text. |
{"type": "error", "message"} |
Something failed, for example approval not pending |
Approval requests arrive as events. Answer them with an approve message.
The dashboard design
The page follows Air + Glass, from the Project Silk palette: mostly Pearl and Frost with 1px lines, and glass over soft Mist shapes only where you talk to the agent, the chat panel and approval prompts. The Costs panel appears only when CommonBill is enabled.