CAWA (Coding Agent Web API) v1 provides RESTful API and Server-Sent Events (SSE) endpoints for managing the lifecycle of coding agents, creating sessions, sending asynchronous messages, and streaming execution task logs.
By default, all API endpoints are exposed at http://localhost:3100 (customizable via agent_service.port in the configuration file config.yaml).
| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check of the agent service, LLMGP status, and server settings. |
GET |
/api/v1/agents |
Retrieve the list of available coding agents. |
GET |
/api/v1/models |
Retrieve available LLM models and the default model. |
POST |
/api/v1/embeddings |
Create text embeddings (bypasses Coding Agents; proxied to LLMGP). |
GET |
/api/v1/embeddings/models |
Retrieve embedding-only models (mode: embedding). |
POST |
/api/v1/sessions |
Initialize a new coding session. |
GET |
/api/v1/sessions?work_dir= |
List sessions persisted under a workspace .tern directory. |
GET |
/api/v1/sessions/:id |
Retrieve metadata and state of a specific session. |
PATCH |
/api/v1/sessions/:id |
Update config_dir, agent, model, and/or supplement. |
DELETE |
/api/v1/sessions/:id |
Delete session data. |
POST |
/api/v1/sessions/:id/messages |
Send a message (text/image) to a session. |
POST |
/api/v1/sessions/:id/terminate |
Force terminate an active session process. |
GET |
/api/v1/sessions/:id/logs |
Stream detailed task logs generated during session execution. |
Performs a health check, retrieves the cached LLM Gateway Proxy (LLMGP) status, and details the server configuration settings.
- Method:
GET - Path:
/health - Response (200 OK):
{ "status": "ok", "cli_versions": { "claudecode": "0.1.0", "codex": "1.2.3" }, "gateway": { "status": "ok", "url": "http://localhost:3101", "last_checked_at": "2026-06-29T17:45:00+09:00" }, "server_settings": { "disable_sandbox": true, "enable_subagent": false, "enabled_versions": [1] } }
Retrieves the names of all available coding agents.
- Method:
GET - Path:
/api/v1/agents - Response (200 OK):
[ {"name": "claudecode"}, {"name": "codex"}, {"name": "wayfinder"} ]
Retrieves the list of all available LLM models and the default model, obtained via the LLM Gateway Proxy (LLMGP).
- Method:
GET - Path:
/api/v1/models - Response (200 OK):
{ "models": [ { "provider": "anthropic", "model": "claude-3-5-sonnet-20241022", "tool_call_fallback": false }, { "provider": "ollama", "model": "qwen2.5-coder:7b", "tool_call_fallback": true } ], "default_model": { "provider": "anthropic", "model": "claude-3-5-sonnet-20241022", "tool_call_fallback": false } }
Creates text embeddings via LLMGP. This endpoint does not start a Coding Agent session; AgentService proxies the request to POST /v1/embeddings on the gateway.
- Method:
POST - Path:
/api/v1/embeddings - Request Body (JSON): OpenAI Embeddings API compatible (
model,inputas string or string array, optionalencoding_format,dimensions) - Response (200 OK): OpenAI-compatible embedding list (
object,data,model,usage)
Returns models declared with mode: embedding in model_profiles.yaml. These models are excluded from GET /api/v1/models.
- Method:
GET - Path:
/api/v1/embeddings/models - Response (200 OK):
{ "models": [ { "provider": "openai", "model": "text-embedding-3-small" } ] }
Initializes a new coding session.
- Method:
POST - Path:
/api/v1/sessions - Request Body (JSON):
agent(string, Required): The name of the agent to use (claudecode,wayfinder, etc.).model(string, Optional): The LLM model to use. If not specified, the default model is applied.work_dir(string, Required): The absolute workspace directory path where the agent will operate.session_dir(string, Optional): The directory path to store session data. Defaults towork_dir/.tern/{session_id}. Agent native files (ClaudeCLAUDE_CONFIG_DIR, CodexCODEX_HOME) are stored under{session_dir}/native.config_dir(string, Optional): Agent config set directory (skills / rules / settings). When set, Tern overlays allowlisted entries into{session_dir}/nativebefore launching the agent. When omitted, behavior is unchanged from previous versions (no overlay).- Paths (
work_dir,session_dir,config_dir) must be visible to the Tern process (for example, mounted into the container when Tern runs in Docker).
{ "agent": "claudecode", "model": "claude-3-5-sonnet-20241022", "work_dir": "/path/to/workspace", "session_dir": "/path/to/tern-sessions/card-1", "config_dir": "/path/to/config-sets/alpha" }- Persistence env mapping: Claude Code uses
CLAUDE_CONFIG_DIR={session_dir}/native; Codex usesCODEX_HOME={session_dir}/native. - Precedence:
- Claude Code: CLI flags > project
.claudeunderwork_dir> user config underCLAUDE_CONFIG_DIR(after overlay). Project.claudenesting ofconfig_diris not supported. - Codex: CLI
-c> (whenconfig_diris set)$CODEX_HOMEuser config/skills > project.codex; whenconfig_diris omitted,--ignore-user-config+-cas today.
- Claude Code: CLI flags > project
- Overlay is re-applied on each agent process start; session-only data (
projects/,sessions/, …) is preserved.
- Response (201 Created):
{ "session_id": "a95db64cb646901efb395a18d817a37d", "status": "created" }
Retrieves metadata and the active state of a created session.
- Method:
GET - Path:
/api/v1/sessions/:id - Response (200 OK):
status: The execution state of the session (active,completed,error,closed).
{ "id": "a95db64cb646901efb395a18d817a37d", "agent_name": "claudecode", "model": "claude-3-5-sonnet-20241022", "status": "active", "work_dir": "/path/to/workspace", "session_dir": "/path/to/workspace/.tern/a95db64cb646901efb395a18d817a37d", "config_dir": "/path/to/config-sets/alpha", "agent_session_id": "agent-internal-session-id", "active_agent": "claudecode", "agent_bindings": { "claudecode": { "agent_session_id": "agent-internal-session-id", "ingested_through_seq": 4 } }, "supplement": { "algorithm": "map_reduce", "max_chunk_messages": 20, "threshold_bytes": 32768, "recent_keep": 8 }, "error": "" }config_diris included when set at CreateSession time (or later via PATCH).agent_bindingsandsupplementare the canonical metadata (effective supplement merges server defaults with the session strategy; turn override is not stored).
Lists session records persisted under {work_dir}/.tern/*/record.json. Memory is only a cache; there is no session.db.
- Method:
GET - Path:
/api/v1/sessions?work_dir= - Query:
work_dir(required) — workspace path whose.terndirectory is scanned. - Response (200 OK): JSON array of session records (same shape as Get Session).
Updates config_dir, agent, model, and/or supplement on an existing session. At least one of these fields is required. Does not change work_dir, session_dir, or the Tern id. Overlay of a new config_dir runs on the next message send. terminate is not part of the normal switch flow.
Switch semantics:
-
PATCH
agent: clears the activeagent_session_id. Per-agentagent_bindingsare kept. The next SendMessage for a new agent does not pass another agent's native resume id; it injects a Tern history supplement (headerTern session context transfer) for foreign origins. Returning to an agent resumes that agent's stored native id and injects only newer foreign-origin facts. -
PATCH
modelonly: keeps the current native resume id and does not inject a transfer header. -
PATCH
agentandmodeltogether: agent-switch semantics (active native id cleared). -
Busy or suspended sessions return
409. -
Method:
PATCH -
Path:
/api/v1/sessions/:id -
Request Body (JSON) — at least one of:
config_dir(string): Path to the config set directory. An empty string clears overlay.agent(string): Coding agent name (claudecode,codex,wayfinder).model(string): LLM model id.supplement(object): Partial strategy (algorithm,model,max_chunk_messages,threshold_bytes,recent_keep). Known algorithms:map_reduce(default),full,structured.
-
Example:
{ "agent": "codex", "supplement": { "algorithm": "map_reduce", "model": "", "max_chunk_messages": 20, "threshold_bytes": 32768, "recent_keep": 8 } } -
Response (200 OK): Full session record (same shape as Get Session).
-
Errors:
404session not found409session busy or suspended400no updatable field, unknown agent/algorithm, invalidconfig_dir, or unsupported model
Server default strategy (merged under session + turn values):
agent_service:
supplement:
algorithm: map_reduce
model: ""
max_chunk_messages: 20
threshold_bytes: 32768
recent_keep: 8Deletes the session record from the server.
- Method:
DELETE - Path:
/api/v1/sessions/:id - Response (204 No Content): (Empty body)
Sends prompt text and image data to an active session, initiating agent execution.
-
Method:
POST -
Path:
/api/v1/sessions/:id/messages -
Request Body (JSON): Provide structured blocks (text or image) within the
contentarray.{ "correlation_id": "job-20260814-001", "supplement": { "algorithm": "full" }, "content": [ { "type": "text", "text": "What is in this screenshot?" }, { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ..." } } ] } -
Response Format (Content Negotiation): The response format varies depending on the request's
Acceptheader.If
Accept: text/event-streamis included in the request headers, the response is streamed in real time.- Content-Type:
text/event-stream - Event Structure:
data: <JSON>type(string): Event type (text,system,error, etc.).content(string): Text chunk output by the agent.session_id(string, system events only): Agent-specific internal session ID.turn_id(string, optional): Server-generated turn identifier for this SendMessage execution.correlation_id(string, optional): Echoed user-supplied correlation ID.
- Termination Signal: Stream ends with
data: [DONE]. - Response Example:
HTTP/1.1 200 OK Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive data: {"type":"text","content":"Analyzing"} data: {"type":"text","content":" the image..."} data: [DONE]
- Transient Codex process exits (
exit status 1) and upstream stream failures (Reconnecting..., high demand, HTTP 429) are retried on the server within bounded limits. Intermediate failures are not written to SSE. Clients wait for a finalresultor a singleerror. - When retries are exhausted,
error.contentends with[upstream_overloaded]for classified overload messages, or[upstream_error]for generic process failures such asexit status 1. Permanent failures (unauthorized, invalid API key, unknown model, invalid arguments) are not retried and end with[upstream_error]. - Closing the SSE connection does not immediately kill the coding-agent CLI. The server drains the in-flight process for up to 15 seconds, then stops it (
ProcessManager.Stop) and clears the session busy state. A follow-upPOSTon the samesession_idis accepted (it is409only while an execution is still active and the drain deadline has not elapsed). Ifcodex exec resumefails retryably, Tern drops the native thread id, injects canonical history into a freshcodex exec, and keeps the HTTPsession_id. - When Codex process retries are exhausted, SSE still ends with a single classified
error([upstream_error]or[upstream_overloaded]). Operators inspect process logs forcodex process retry exhausted(session_id,attempt,max_attempts,resume_mode,agent_session_id, stderr tail up to 8KiB,exit_status). Client SSE disconnect logs asclient disconnected during SSE stream. Drain stop logs asSSE drain timed out; stopping agent processwith terminal contentclient drain timeout. Gateway upstream deadlines log asupstream stream read deadline exceeded. Closing the SSE body can still surface asstream read error: context deadline exceededon the HTTP client.
- Content-Type:
For each POST /api/v1/sessions/:id/messages execution, Tern assigns a turn_id.
-
You may provide an optional
correlation_idin the request body. -
turn_idandcorrelation_idare propagated to System Artifact events created during that execution. -
POST /api/v1/sessions/:id/respondcontinues the same turn.If
text/event-streamis not specified in theAcceptheader, all streaming events are aggregated and returned as a single JSON array.- Content-Type:
application/json - Response Example:
[ {"type": "text", "content": "Analyzing"}, {"type": "text", "content": " the image..."} ]
- Content-Type:
-
Status Codes:
200 OK: Successful transmission and processing.400 Bad Request: Invalid request data (e.g., sending invalid image data).404 Not Found: Session not found.501 Not Implemented: Returned if an image is sent to an agent that does not support multi-modal input (e.g.,wayfinder).
Forcefully stops and terminates the running session process (the agent process executing in the background).
- Method:
POST - Path:
/api/v1/sessions/:id/terminate - Response (200 OK):
{ "status": "terminated" }
Streams detailed system logs and progress states generated during session execution via SSE.
- Method:
GET - Path:
/api/v1/sessions/:id/logs - Content-Type:
text/event-stream - Event Formats:
- event:
logdata: JSON representation of the log entry.
- event:
status(only on completion/termination)data: Final status ({"status":"terminated"}or{"status":"failed"}).
- data:
[DONE](stream termination)
- event:
- Response Example:
HTTP/1.1 200 OK Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive event: log data: {"id":"log-id-1","session_id":"a95db64...","type":"send","body":"..."} event: status data: {"status":"terminated"} data: [DONE]