The default base URL is http://localhost:9889.
This page maps the public API by family and gives representative requests.
When cao-server is running, its generated FastAPI OpenAPI schema and schema
UI are the exhaustive contract for individual HTTP operations. OpenAPI does
not describe WebSocket behavior; the PTY WebSocket contract is documented
below.
curl http://localhost:9889/health
curl http://localhost:9889/sessions
curl http://localhost:9889/agents/providersHTTP errors use standard status codes and generally return a JSON detail
field. Authentication and network behavior depend on server configuration;
see Configuration and Security.
GET /healthreports service health.GET /.well-known/oauth-protected-resourcepublishes OAuth protected resource metadata when applicable.
/eventsand/events/historyexpose server events./agui/v1/streamand/agui/v1/emit_uiprovide the AG-UI stream and generative UI input.
See AG-UI for enablement, event shapes, and privacy boundaries.
GET /agents/profilesandGET /agents/profiles/{name}list and inspect installed profiles.GET /agents/profiles/searchranks installed, loadable profiles by capability using the same service ascao profile find.GET /agents/profiles/templateslists public template metadata (nameanddescriptiononly); internal template filesystem paths are never returned.GET /agents/profiles/templates/{category}/{name}/schemareturns a template's JSON-Schema.POST /agents/profiles/templates/validatevalidates a config object against a template's JSON-Schema without writing a profile.POST /agents/profiles/templates/previewvalidates and renders a template to Markdown without writing a profile.POST /agents/profiles/validatevalidates a finished profile's frontmatter against the profile JSON-Schema plus CAO conventions, without writing anything. This is the HTTP equivalent ofcao profile validate, and is distinct fromtemplates/validate, which checks a template config against that template's own schema. Findings are severity-tagged (errororwarning); only errors clear thevalidflag, so warnings are advisory.GET /agents/profiles/schemareturns the agent profile JSON-Schema, so a client can render create and edit forms from the server's definition instead of duplicating the field list.POST /agents/profiles/installinstalls a profile.- Template validation and preview require the selected template to include a
schema.jsonfile. /agents/providersreports provider availability./settings/*exposes supported agent-directory, skill-directory, and memory settings.
See Agent Profiles and Configuration.
/skills/{name}retrieves an installed skill.
See Skills for discovery, installation, and catalog behavior.
/sessions*creates, lists, inspects, and deletes sessions./sessions/{session_name}/terminals*creates and lists session terminals./terminals/{terminal_id}*inspects terminals, sends input or keys, reads output and working-directory state, exits providers, and deletes terminals.GET /terminals/{terminal_id}/output?mode=fullreturns the StatusMonitor rolling buffer (most recentstate_buffer_maxbytes of streamed output — server setting, 32KB by default, see Configuration), not unbounded scrollback. Long sessions are truncated to the tail; use the on-disk terminal log for complete history.- Terminal creation accepts
use_worktree(bool, defaultfalse, issue #100 Phase 1): provisions an isolatedgit worktreeon its own branch instead of sharingworking_directoryas given, requiring the resolved directory to be inside a git repository. At deletion, the worktree's working-tree contents are always discarded, but the branch is only deleted if it has no unmerged commits — commit and merge/push results before the terminal is deleted if they need to be kept. See the MCPhandoff/assigntool descriptions for the full behavior. POST /sessionsaccepts optionalgroup/metadataat creation, opting a session's initial terminal into peer discovery (a mid-session worker usesPATCH /terminals/{terminal_id}/group/metadatainstead — see below).groupis an ordered, general-to-specific array (e.g.["tenant_1", "project_5"]);metadatais a free-form JSON object the running agent updates via theupdate_metadataMCP tool. Both PATCH endpoints are whole-value replace, not merge, last-write-wins under concurrent calls, and reject an omitted field with422(an explicitnull/[]/{}clears the value; omitting it does not).GET /terminals/{terminal_id}/siblingslists other terminals sharing a leading prefix ofterminal_id's owngroup, optionally narrowed bydepth; a caller can never see a wider scope than its own group, and a terminal with nogroupset finds no siblings. Session-scoped by default — results are also filtered to the caller's own tmux session unless the explicitcross_session=trueopt-in is passed. Siblingmetadatais agent-authored, untrusted content — same trust domain as an inboundsend_messagebody. Thelist_siblings/update_metadataMCP tools also require thediscoveryentry inallowedTools— a separate opt-in from orchestration tools, not bundled into@cao-mcp-server— see Tool Restrictions and Discovery Tool Coexistence.
group is an organizational label, not a security boundary. On a
default install with auth disabled, a worker already has local shell access
to this API, so group/discovery/session-scoping provide no tenant
isolation or access-control guarantee even used together — do not build a
security boundary on top of them.
Terminal identifiers used in these routes are eight-character hexadecimal strings. See Control Planes for operator-facing choices.
/terminals/{terminal_id}/inbox/messagessends and reads terminal inbox messages.
Agents normally use the in-session supervisor protocols rather than calling these routes directly.
/workflows*validates and inspects workflow specifications.POST /workflows/runsstarts a run inline and holds the connection until it finishes, returning the complete result.POST /workflows/runs:submitstarts a run asynchronously: it returns202with{run_id, state, links}as soon as the run is durably journaled, then drives the run in the background. Thelinksmap always carriesself/status/result/cancel;eventsappears only on a build that serves the events route, so treat it as optional.GET /workflows/runslists journaled runs newest-first (?state=,?limit=).GET /workflows/runs/{run_id}returns a point-in-time status snapshot.GET /workflows/runs/{run_id}/resultreturns the complete retained result. It is assembled from the journal, so it answers for a detached, in-flight, or post-restart run — not only a finished one. No run-leveloutputfield is returned (run-level output is not journaled); per-step outputs are onsteps[].output.POST /workflows/runs/{run_id}/cancelcooperatively cancels a run;POST /workflows/runs/{run_id}/resumere-drives a crashed/failed one.
See Workflows.
/settings/memoryreports memory enablement (includinglearning_enabled)./memory*lists, reads, exports, and deletes memories./memory/relationships*lists, creates, patches, promotes, rejects, and soft-deletes typed relationships between memories.GETis read-scoped and capped bylimit(default 50, max 100); the mutating routes are write-scoped.DELETEis a soft-delete — the row is retained withstatus=deleted./graph/{provider}*projects and exports graph views./outcomesrecords (POST, write-scope) and lists (GET) workflow outcomes for the self-learning loop. Both return 404 whilememory.learning_enabledis false.
See Memory, Self-Learning, and Knowledge Graph Viewing.
/flows*creates, lists, reads, deletes, enables, disables, and runs scheduled flows.
See Flows.
Connect to:
/terminals/{terminal_id}/ws
The path must identify an existing terminal. This endpoint is unauthenticated and grants full read/write access to that terminal's PTY.
By default, only loopback clients identified as 127.0.0.1, ::1, or
localhost are allowed. CAO_WS_ALLOWED_CLIENTS adds comma-separated client
IP addresses or hostnames to that allowlist. A literal * disables the
client-IP restriction.
Adding clients or using * gives those clients full PTY read/write access.
Treat either change as a security-boundary change and do not expose the
endpoint to untrusted networks. See the
network configuration for
related server settings.
The server sends binary WebSocket frames containing raw PTY bytes.
Clients send JSON in text frames:
{"type":"input","data":"ls -la\n"}The input message writes the UTF-8 string in data to the PTY.
{"type":"resize","rows":24,"cols":80}The resize message changes the PTY dimensions. Missing values default to 24
rows and 80 columns.
4003: the client is restricted, or terminal/backend target metadata is invalid.4004: the terminal does not exist, or the backend cannot attach to it.- A normal viewer disconnect detaches that viewer and preserves the session.
Malformed JSON, missing input data, unsupported message types, and other forwarding errors do not currently have a documented stable application close code.