Skip to main content

Starting the Server

polpo serve --port 3000 --api-key my-secret
The server provides a REST API, an OpenAI-compatible chat endpoint, Server-Sent Events (SSE), and WebSocket streaming.

Base URL

http://localhost:3000/api/v1/projects/:projectId
All endpoints are scoped to a project. The project ID defaults to the working directory name.

Authentication

When --api-key is set, all requests must include the key:

REST Endpoints

Projects

MethodPathDescription
GET/api/v1/projectsList all projects
GET/api/v1/projects/:id/stateFull state snapshot
GET/api/v1/projects/:id/configOrchestrator config

Tasks

MethodPathDescription
GET/tasksList all tasks (filterable)
GET/tasks/:idGet single task
POST/tasksCreate task
PATCH/tasks/:idUpdate task
DELETE/tasks/:idRemove task
POST/tasks/:id/retryRetry failed task
POST/tasks/:id/killKill running task
POST/tasks/:id/reassessRe-run assessment
Filters (query params on GET /tasks):
  • ?status=failed — filter by status
  • ?group=feature-auth — filter by mission group
  • ?assignTo=backend-dev — filter by agent

Missions

MethodPathDescription
GET/missionsList all missions
GET/missions/resumableList resumable missions
GET/missions/:idGet mission details
POST/missionsSave mission (JSON)
PATCH/missions/:idUpdate mission
DELETE/missions/:idDelete mission
POST/missions/:id/executeExecute mission
POST/missions/:id/resumeResume mission
POST/missions/:id/abortAbort mission

Agents

MethodPathDescription
GET/agentsList agents
POST/agentsAdd agent
DELETE/agents/:nameRemove agent
GET/agents/teamGet team info
PATCH/agents/teamRename team
GET/agents/processesActive processes

Memory

MethodPathDescription
GET/memoryGet project memory
PUT/memoryUpdate project memory

Files

MethodPathDescription
GET/files/listList directory contents (sandboxed to .polpo/ and project root)
GET/files/readStream file content with correct Content-Type
GET/files/previewGet structured preview data (type, content for text, URL for binary)
Query params on GET /files/list:
  • ?path=.polpo/output — directory to list (defaults to project root)
Query params on GET /files/read:
  • ?path=/abs/path/to/file — file path (required)
  • ?download=1 — force download (Content-Disposition: attachment)
Query params on GET /files/preview:
  • ?path=/abs/path/to/file — file path (required)
  • ?maxLines=500 — max lines for text content (default: 500)
All paths are sandboxed — .. traversal is rejected, and only files under .polpo/ or the project working directory are accessible.

Chat (OpenAI-compatible)

The primary way to talk to Polpo programmatically:
MethodPathDescription
POST/v1/chat/completionsTalk to Polpo (OpenAI-compatible, streaming + non-streaming)
This endpoint accepts standard OpenAI-format messages and returns responses in OpenAI format. Polpo runs its full tool loop internally (38 tools) — you describe what you need, Polpo handles the rest. Supports "stream": true for SSE streaming.
curl http://localhost:3000/v1/chat/completions \
  -H "Authorization: Bearer my-secret" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "user", "content": "Create a mission to build a REST API for user management"}],
    "stream": false
  }'

Sessions

MethodPathDescription
GET/chat/sessionsList all sessions
GET/chat/sessions/:id/messagesGet messages for a session
PATCH/chat/sessions/:idRename a session ({ title })
DELETE/chat/sessions/:idDelete a session

Logs

MethodPathDescription
GET/logsList log sessions
GET/logs/:sessionIdGet session log entries

Health

MethodPathDescription
GET/api/v1/healthServer health check

Server-Sent Events (SSE)

Subscribe to real-time events:
const events = new EventSource(
  'http://localhost:3000/api/v1/projects/my-project/events'
);

events.onmessage = (e) => {
  const { event, data } = JSON.parse(e.data);
  console.log(event, data);
};

Reconnection

SSE supports Last-Event-ID for reconnection. The server maintains a circular buffer of the last 1000 events:
// Resume from event 42
const events = new EventSource(
  'http://localhost:3000/api/v1/projects/my-project/events?lastEventId=42'
);

WebSocket

WebSocket provides the same event stream with optional filtering:
const ws = new WebSocket(
  'ws://localhost:3000/api/v1/projects/my-project/ws'
);

// Filter events with glob patterns
ws.send(JSON.stringify({ type: 'subscribe', pattern: 'task:*' }));
ws.send(JSON.stringify({ type: 'subscribe', pattern: 'assessment:*' }));

ws.onmessage = (e) => {
  const { event, data } = JSON.parse(e.data);
  console.log(event, data);
};

Filter Patterns

PatternMatches
task:*All task events
agent:*All agent events
assessment:*Assessment events
mission:*Mission events
*All events

Response Format

All REST responses follow a consistent format:
// Success
{
  "ok": true,
  "data": { /* ... */ }
}

// Error
{
  "ok": false,
  "error": "Task not found",
  "code": "NOT_FOUND"
}
The server uses Hono (14KB, zero dependencies) with @hono/node-server. It’s a pure translation layer over the Orchestrator public API — no core logic is duplicated.