API Reference
Base URL: http://127.0.0.1:23000 (configurable via ENSEMBLE_PORT)
Rate limit: 100 requests per 60 seconds per IP.
Health
GET /api/v1/health
curl http://localhost:23000/api/v1/health
{ "status": "healthy", "version": "1.0.0" }
Teams
POST /api/ensemble/teams — Create team
curl -X POST http://localhost:23000/api/ensemble/teams \
-H "Content-Type: application/json" \
-d '{
"name": "review-team",
"description": "Review the auth module for security issues",
"agents": [
{ "program": "codex", "role": "lead", "hostId": "local" },
{ "program": "claude", "role": "worker", "hostId": "local" }
],
"workingDirectory": "/path/to/project",
"feedMode": "live",
"useWorktrees": false,
"templateName": null,
"staged": false
}'
Required fields:
name(string) — team namedescription(string) — task for the teamagents(array) — at least one agent withprogramfield
Optional fields:
workingDirectory(string) — project path for agentsfeedMode("silent","summary", or"live") — message delivery modeuseWorktrees(boolean) — isolate agents in git worktreestemplateName(string) — use a collab template (review,implement,debug)staged(boolean) — enable staged plan/execute/verify workflowstagedConfig(object) — phase timeouts and settings
Response: { "team": EnsembleTeam }
Returns 400 for malformed JSON, 429 for rate limit exceeded.
GET /api/ensemble/teams — List teams
curl http://127.0.0.1:23000/api/ensemble/teams
Response: { "teams": EnsembleTeam[] }
GET /api/ensemble/teams/:id — Get team details
curl http://127.0.0.1:23000/api/ensemble/teams/abc-123
Response: { "team": EnsembleTeam, "messages": EnsembleMessage[] }
POST /api/ensemble/teams/:id — Send message
curl -X POST http://127.0.0.1:23000/api/ensemble/teams/abc-123 \
-H "Content-Type: application/json" \
-d '{
"from": "user",
"to": "codex-1",
"content": "Focus on the auth module"
}'
Fields:
content(string, required) — message textto(string) — recipient agent name; defaults to"team"when omitted or emptyfrom(string) — sender name (default:"user")
Response: { "message": EnsembleMessage }
Returns 400 for malformed JSON.
DELETE /api/ensemble/teams/:id — Disband team
curl -X DELETE http://127.0.0.1:23000/api/ensemble/teams/abc-123
Stops all agents, generates summary, cleans up. Also available as POST /api/ensemble/teams/:id/disband.
Response: { "team": EnsembleTeam }
Feed
GET /api/ensemble/teams/:id/feed — Message feed
# All messages
curl http://localhost:23000/api/ensemble/teams/abc-123/feed
# Incremental (since timestamp)
curl "http://localhost:23000/api/ensemble/teams/abc-123/feed?since=2026-03-20T10:00:00Z"
Query params:
since(ISO 8601 timestamp) — only return messages after this time
Response: { "messages": EnsembleMessage[] }
Use the since parameter for efficient polling — avoids re-fetching the entire message history.
Types
EnsembleTeam
{
id: string
name: string
description: string
status: 'forming' | 'active' | 'paused' | 'completed' | 'disbanded' | 'failed'
agents: EnsembleTeamAgent[]
createdBy: string
createdAt: string // ISO 8601
completedAt?: string
feedMode: 'silent' | 'summary' | 'live'
result?: EnsembleTeamResult
}
EnsembleTeamAgent
{
agentId: string
program: string
name: string
role: string
hostId: string
status: 'spawning' | 'active' | 'idle' | 'done' | 'failed'
worktreePath?: string
worktreeBranch?: string
}
EnsembleTeamResult
{
summary: string
decisions: string[]
discoveries: string[]
filesChanged: string[]
duration: number
}
EnsembleMessage
{
id: string
teamId: string
from: string
to: string
content: string
type: string
timestamp: string // ISO 8601
}