Skip to content

Agent API

Each agent VM runs a FastAPI server with the endpoints documented below. All endpoints except /health require authentication via the Authorization: Bearer <agent_secret> header.

In normal operation, these endpoints are called by the LiberClaw API proxy — not by end users directly. This reference is for developers building integrations or debugging agent behavior.

Every request (except GET /health) must include:

Authorization: Bearer <agent_secret>

The agent stores a SHA-256 hash of the secret and validates using constant-time comparison. Requests without a valid token receive a 401 Unauthorized response.

Health check endpoint. No authentication required.

Response:

{
"status": "ok",
"agent_name": "MyAgent",
"version": 5,
"capabilities": ["vision"]
}

capabilities are agent/model capabilities reported by the VM, such as vision. They are not the same as client feature flags like uploads, usage, redeploy, or workspace tree support, which describe what a particular frontend/API adapter can call.

Terminal window
curl https://agent.example.com/health

Authenticated runtime introspection endpoint. Use this to discover the agent runtime version, model, feature flags, available tools, unavailable tool reasons, and shallow local subsystem health.

Response:

{
"agent_name": "MyAgent",
"agent_version": 5,
"api_version": 3,
"model": "claw-core",
"capabilities": ["vision"],
"features": {
"tool_gating": true,
"tool_result_events": true,
"tool_metadata": true,
"runtime_health": true,
"mcp_health": true,
"runtime_events": true,
"context_injection_scanner": true,
"tool_policy": true,
"coding_task_runtime": true,
"file_watchers": true
},
"tool_policy": {
"mode": "full-auto",
"allowlist": [],
"denylist": []
},
"tools": ["bash", "read_file", "list_dir"],
"tool_metadata": [
{
"name": "list_dir",
"available": true,
"unavailable_reason": null,
"mutating": false,
"image_aware": false
}
],
"unavailable_tools": {},
"runtime_health": {
"database": "configured",
"workspace": "configured",
"mcp": "disabled",
"mcp_detail": {
"enabled": false,
"server_count": 0,
"connected_count": 0,
"tool_count": 0,
"servers": []
},
"heartbeat": "enabled"
}
}

Send a message and receive an SSE stream of events as the agent processes it. If there is an existing active run for the same chat_id, it is automatically cancelled before starting the new one.

Request body:

{
"message": "Hello, what can you do?",
"chat_id": "conv_abc123",
"mode": "chat"
}

Set mode to coding to inject the coding-task runtime contract into the turn and emit coding_task.* lifecycle events.

Response: text/event-stream (Server-Sent Events)

Each event is a JSON object on a data: line:

Event typeFieldsDescription
textcontentText output from the model
tool_usename, inputTool call being executed
tool_resultname, content, is_error, duration_ms, truncated, metadata, artifactsStructured result metadata for a completed tool call
filepath, captionFile being sent to the user
errorcontentError message
keepalive(none)Connection keepalive (sent every 15s during long operations)
subagent_spawnedrun_id, label, statusBackground subagent was started
subagent_completedrun_id, label, statusBackground subagent completed
subagent_failedrun_id, label, status, errorBackground subagent failed or timed out
guardrail_blockedtool, reason, policyTool call was blocked by runtime policy
skill.consideredplatform, count, skillsSkills visible to the current turn
skill.loadedid, path, toolA skill file was read by the agent
skill.draft.proposedtool_calls, proposalDraft-only reusable skill proposal
coding_task.startedmodeCoding runtime started
coding_task.checkpointstatus, contentPre-task checkpoint result
coding_task.completedmode, statusCoding runtime finished
done(none)Stream is complete

Live and replayed events may include timestamp_ms.

MCP tool results keep the normal text content field and add metadata such as provider: "mcp", server, original_name, namespaced_name, content_types, and mcp_is_error.

Deterministic JSON eval cases can exercise this runtime without live model calls by scripting model responses and expected files/history. Run them with scripts/run_agent_eval.py evals/smoke.

Terminal window
curl -N -X POST https://agent.example.com/chat \
-H "Authorization: Bearer $SECRET" \
-H "Content-Type: application/json" \
-d '{"message": "List files in the workspace", "chat_id": "test"}'

Start a coding-task runtime stream. This is a thin API wrapper over /chat with mode: "coding" and a generated chat_id of coding:<task_id>.

Request body:

{
"task_id": "fix-tests-123",
"task": "Fix the failing pytest slice and report verification.",
"mode": "implement",
"context": "Optional extra task context"
}

mode is either implement or inspect.

Response: text/event-stream

The first event is coding_task.meta with task_id and chat_id, followed by the normal chat stream plus coding_task.* lifecycle events.

Return durable runtime events for a coding task.

Reconnect to an active coding task stream.

Cancel an active coding task.

Example SSE output:

data: {"type": "tool_use", "name": "list_dir", "input": "{\"path\": \".\"}"}
data: {"type": "tool_result", "name": "list_dir", "is_error": false, "duration_ms": 4, "truncated": false, "metadata": {"mutating": false}, "artifacts": [], "content": "[file] notes.txt"}
data: {"type": "text", "content": "Here are the files in your workspace:\n..."}
data: {"type": "subagent_spawned", "run_id": "a1b2c3d4", "label": "Research", "status": "running"}
data: {"type": "done"}

Check if there is an active (in-progress) chat run for a given chat ID.

Response:

{
"active": true,
"user_message": "List files in the workspace"
}

If no active run exists:

{
"active": false,
"user_message": ""
}
Terminal window
curl https://agent.example.com/chat/test/active \
-H "Authorization: Bearer $SECRET"

Reconnect to an active chat run’s SSE stream. Replays all buffered events from the beginning, then continues streaming live events. The first event is a stream_meta with the original user_message.

If no active run exists, returns a single done event.

Terminal window
curl -N https://agent.example.com/chat/test/stream \
-H "Authorization: Bearer $SECRET"

Example output on reconnect:

data: {"type": "stream_meta", "user_message": "List files in the workspace"}
data: {"type": "tool_use", "name": "list_dir", "input": "{\"path\": \".\"}"}
data: {"type": "text", "content": "Here are the files..."}
data: {"type": "done"}

Return conversation history as a list of chat events.

Query parameters:

ParameterTypeDefaultDescription
limitinteger50Maximum number of messages

Response:

{
"messages": [
{"type": "text", "content": "Hello", "name": "user"},
{"type": "text", "content": "Hi! How can I help?"},
{"type": "tool_use", "name": "bash", "input": "{\"command\": \"ls\"}"},
{"type": "file", "path": "images/chart.png"}
]
}

Return durable runtime events for a chat, ordered oldest to newest. This trace is stored in SQLite and survives reconnects and process restarts.

Query parameters:

ParameterTypeDefaultDescription
limitinteger200Maximum number of events, capped at 1000
after_idintegernoneReturn only events with an id greater than this value

Response:

{
"events": [
{
"id": 1,
"type": "tool_result",
"payload": {
"type": "tool_result",
"name": "list_dir",
"is_error": false,
"duration_ms": 4
},
"created_at": "2026-05-12T10:15:00+00:00"
}
]
}

User messages include "name": "user". Assistant messages omit the name field.

Terminal window
curl https://agent.example.com/chat/test/history?limit=20 \
-H "Authorization: Bearer $SECRET"

Clear conversation history for a chat.

Response:

{
"status": "ok",
"deleted": 42
}
Terminal window
curl -X DELETE https://agent.example.com/chat/test \
-H "Authorization: Bearer $SECRET"

Return pending proactive messages (from heartbeat, subagents) and clear them.

Response:

{
"messages": [
{
"chat_id": "owner_123",
"content": "[Heartbeat] Updated the daily report.",
"source": "heartbeat",
"created_at": "2026-02-23T10:30:00"
}
]
}
Terminal window
curl https://agent.example.com/pending \
-H "Authorization: Bearer $SECRET"

Serve a file from the workspace. The path is relative to the workspace root. Protected by workspace boundary checks and the sensitive file blocklist.

Terminal window
curl https://agent.example.com/files/images/chart.png \
-H "Authorization: Bearer $SECRET" \
--output chart.png

Returns 403 Forbidden for paths that escape the workspace or match sensitive filenames (.env, agent.db).


Upload a file to the agent workspace.

Request: multipart/form-data

FieldTypeRequiredDescription
filefileyesThe file to upload
pathstringnoTarget directory (default: "uploads")

Response:

{
"path": "uploads/data.csv",
"size": 1024,
"name": "data.csv"
}

Maximum file size: 50 MB.

Terminal window
curl -X POST https://agent.example.com/files/upload \
-H "Authorization: Bearer $SECRET" \
-F "file=@data.csv" \
-F "path=uploads"

Return a recursive file tree of the workspace.

Query parameters:

ParameterTypeDefaultDescription
max_depthinteger5Maximum directory depth

Response:

{
"tree": [
{
"name": "memory",
"path": "memory",
"type": "dir",
"children": [
{"name": "MEMORY.md", "path": "memory/MEMORY.md", "type": "file", "size": 256}
]
},
{"name": "HEARTBEAT.md", "path": "HEARTBEAT.md", "type": "file", "size": 0}
]
}

Directories are listed before files. Sensitive files (.env, agent.db, .git, __pycache__, node_modules) are excluded.

Terminal window
curl https://agent.example.com/workspace/tree?max_depth=3 \
-H "Authorization: Bearer $SECRET"

List all subagent runs. Running subagents are listed first, then sorted by start time (newest first). Completed runs are retained for 1 hour.

Response:

{
"subagents": [
{
"id": "a1b2c3d4",
"label": "Research task",
"task": "Find the latest pricing for...",
"role": "researcher",
"status": "running",
"chat_id": "conv_abc123",
"started_at": 1708700000.0,
"completed_at": null,
"result_preview": null,
"error": null,
"duration": 12.5
}
]
}

Subagent statuses: running, completed, failed, timeout.

Terminal window
curl https://agent.example.com/subagents \
-H "Authorization: Bearer $SECRET"

Get full details of a single subagent run, including the complete task, result, and persona.

Response:

{
"id": "a1b2c3d4",
"label": "Research task",
"task": "Find the latest pricing for cloud VMs across providers",
"persona": "You are a cloud infrastructure researcher",
"role": "researcher",
"status": "completed",
"chat_id": "conv_abc123",
"started_at": 1708700000.0,
"completed_at": 1708700045.0,
"result": "Based on my research, here are the current prices...",
"error": null,
"duration": 45.0
}
Terminal window
curl https://agent.example.com/subagents/a1b2c3d4 \
-H "Authorization: Bearer $SECRET"

Cancel a running subagent. Returns an error if the subagent is not in the running state.

Response:

{
"status": "ok",
"run_id": "a1b2c3d4",
"message": "Subagent 'Research task' cancelled"
}
Terminal window
curl -X POST https://agent.example.com/subagents/a1b2c3d4/stop \
-H "Authorization: Bearer $SECRET"

Return Telegram bot connection status for agents with Telegram integration enabled.

Response (connected):

{
"connected": true,
"bot_username": "my_agent_bot",
"bot_name": "My Agent"
}

Response (not connected):

{
"connected": false,
"bot_username": "",
"bot_name": ""
}
Terminal window
curl https://agent.example.com/telegram/status \
-H "Authorization: Bearer $SECRET"

List Telegram contacts, optionally filtered by status.

Query parameters:

ParameterTypeRequiredDescription
statusstringnoFilter by status: allowed, pending, or blocked

Response:

{
"contacts": [
{
"telegram_id": "123456789",
"username": "johndoe",
"display_name": "John Doe",
"status": "allowed"
}
]
}
Terminal window
curl "https://agent.example.com/telegram/contacts?status=pending" \
-H "Authorization: Bearer $SECRET"

Update a Telegram contact’s status.

Request body:

{
"status": "allowed"
}

Valid statuses: allowed, pending, blocked.

Terminal window
curl -X PATCH https://agent.example.com/telegram/contacts/123456789 \
-H "Authorization: Bearer $SECRET" \
-H "Content-Type: application/json" \
-d '{"status": "allowed"}'

Remove a Telegram contact.

Response:

{
"status": "ok",
"telegram_id": "123456789"
}
Terminal window
curl -X DELETE https://agent.example.com/telegram/contacts/123456789 \
-H "Authorization: Bearer $SECRET"