API Reference

Complete REST API and WebSocket protocol for programmatic control of your agent fleet.

Base URL: http://127.0.0.1:5111 (default). All endpoints return JSON. When auth is enabled, include the session cookie or Authorization: Bearer <token> header.

Agents

List Agents

GET /api/agents

Returns all active agents. Supports optional query filters:

ParameterTypeDescription
project_idstringFilter by project ID
branchstringFilter by git branch name
statusstringFilter by status (planning, working, waiting, error, idle)
# Example
curl http://127.0.0.1:5111/api/agents?status=working

# Response
[
  {
    "id": "a7f3",
    "name": "auth-api",
    "role": "backend",
    "status": "working",
    "task": "Add input validation to the user registration endpoint",
    "working_dir": "/Users/dev/Projects/my-app",
    "backend": "claude-code",
    "project_id": "p1a2",
    "git_branch": "feature/auth-validation",
    "created_at": "2026-03-08T10:30:00Z",
    "summary": "Editing src/auth/validators.py — adding email format checks",
    "health_score": 92,
    "owner": "admin@example.com"
  }
]

Spawn Agent

POST /api/agents

FieldTypeRequiredDescription
rolestringNoAgent role (default from config). One of: frontend, backend, devops, tester, reviewer, security, architect, docs, general.
taskstringYesThe task description to send to the agent.
working_dirstringNoWorking directory path. Must be under ~/ or /tmp.
backendstringNoBackend to use (default from config).
namestringNoAgent display name. Auto-generated if omitted.
plan_modebooleanNoEnable plan mode (Claude Code only).
project_idstringNoAssign to a project.
modelstringNoModel name override (Claude Code only).
toolsstringNoComma-separated tool restriction list (Claude Code only).
output_modestringNo"tmux" (default) or "stream-json". Stream-json uses subprocess instead of tmux (non-interactive, Claude Code only).
# Example
curl -X POST http://127.0.0.1:5111/api/agents \
  -H "Content-Type: application/json" \
  -d '{
    "role": "backend",
    "task": "Add input validation to user registration",
    "working_dir": "~/Projects/my-app",
    "backend": "claude-code",
    "plan_mode": true
  }'

# Response
{
  "id": "b2c4",
  "name": "backend-b2c4",
  "role": "backend",
  "status": "starting",
  "task": "Add input validation to user registration",
  "working_dir": "/Users/dev/Projects/my-app",
  "backend": "claude-code",
  "plan_mode": true
}

Get Agent Details

GET /api/agents/{id}

Returns full agent details including recent terminal output.

# Response includes output lines
{
  "id": "a7f3",
  "name": "auth-api",
  "role": "backend",
  "status": "working",
  "output": ["line1", "line2", "..."],
  "git_branch": "feature/auth-validation",
  "health_score": 92,
  "summary": "Editing src/auth/validators.py"
}

Kill Agent

DELETE /api/agents/{id}

Sends /exit to the agent, waits 3 seconds, then kills the tmux session. Only the agent owner or admin can kill an agent.

curl -X DELETE http://127.0.0.1:5111/api/agents/a7f3

Send Message to Agent

POST /api/agents/{id}/send

Sends a message to the agent's stdin via tmux send-keys. Maximum message length: 50,000 characters. Returns 400 for stream-json agents (non-interactive).

curl -X POST http://127.0.0.1:5111/api/agents/a7f3/send \
  -H "Content-Type: application/json" \
  -d '{"message": "yes, proceed with those changes"}'

Pause / Resume Agent

POST /api/agents/{id}/pause — Sends SIGTSTP to pause the agent process.

POST /api/agents/{id}/resume — Sends SIGCONT to resume a paused agent.

Restart Agent

POST /api/agents/{id}/restart

Kills the current agent and respawns with the same configuration (role, task, working directory, backend).

Bulk Actions

POST /api/agents/bulk

curl -X POST http://127.0.0.1:5111/api/agents/bulk \
  -H "Content-Type: application/json" \
  -d '{
    "action": "pause",
    "agent_ids": ["a7f3", "b2c4", "d5e6"]
  }'

Supported actions: pause, resume, kill, restart.

Projects

List Projects

GET /api/projects

# Response
[
  {
    "id": "p1a2",
    "name": "my-app",
    "path": "/Users/dev/Projects/my-app",
    "git_remote_url": "git@github.com:user/my-app.git",
    "default_branch": "main",
    "default_backend": "claude-code",
    "created_at": "2026-03-01T09:00:00Z"
  }
]

Create Project

POST /api/projects

curl -X POST http://127.0.0.1:5111/api/projects \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-app",
    "path": "~/Projects/my-app"
  }'

The path must be a real directory under ~/ or /tmp. Git metadata (remote URL, default branch) is auto-detected.

Update Project

PUT /api/projects/{id}

curl -X PUT http://127.0.0.1:5111/api/projects/p1a2 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-app-v2",
    "description": "Main application repository"
  }'

Delete Project

DELETE /api/projects/{id}

Project Context

GET /api/projects/{id}/context — Returns project agents, branches, and recent tasks.

Project Scratchpad

GET /api/projects/{id}/scratchpad — Get project-level scratchpad notes.

POST /api/projects/{id}/scratchpad — Update project scratchpad.

Project Events

GET /api/projects/{id}/events — Project event feed (agent spawns, completions, conflicts).

Workflows (Pro)

List Workflows

GET /api/workflows

Create Workflow

POST /api/workflows

Define a DAG of agent tasks with dependency ordering:

curl -X POST http://127.0.0.1:5111/api/workflows \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Full Stack Feature",
    "agents": [
      {
        "name": "backend-api",
        "role": "backend",
        "task": "Create REST endpoint for user profiles",
        "backend": "claude-code"
      },
      {
        "name": "frontend-ui",
        "role": "frontend",
        "task": "Build profile page component",
        "backend": "claude-code",
        "depends_on": ["backend-api"]
      },
      {
        "name": "test-suite",
        "role": "tester",
        "task": "Write integration tests for profile feature",
        "backend": "claude-code",
        "depends_on": ["backend-api", "frontend-ui"]
      }
    ]
  }'

Update Workflow

PUT /api/workflows/{id} — Validates that there are no circular dependencies.

Run Workflow

POST /api/workflows/{id}/run — Executes the workflow. Agents are spawned in dependency order.

Delete Workflow

DELETE /api/workflows/{id}

Intelligence (Pro)

Parse Natural Language Command

POST /api/intelligence/command

curl -X POST http://127.0.0.1:5111/api/intelligence/command \
  -H "Content-Type: application/json" \
  -d '{"text": "spawn 3 backend agents on my-app to refactor the auth module"}'

# Response
{
  "intent": "spawn",
  "count": 3,
  "role": "backend",
  "project": "my-app",
  "task": "refactor the auth module"
}

Fleet Insights

GET /api/intelligence/insights

Returns LLM-generated analysis of the current fleet: conflicts, stuck agents, handoff opportunities, optimization suggestions.

Authentication

Session-based authentication with bcrypt password hashing. Auth is optional — single-user setups work without it.

Check Auth Status

GET /api/auth/status

# Response (auth not required)
{"require_auth": false}

# Response (auth required)
{"require_auth": true, "user": {"email": "admin@example.com", "role": "admin"}}

Register

POST /api/auth/register

The first user to register becomes the admin and creates the organization.

curl -X POST http://127.0.0.1:5111/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@example.com",
    "password": "securepassword123",
    "name": "Admin User"
  }'

Login

POST /api/auth/login

Returns a session cookie (HttpOnly, SameSite=Strict, Secure behind HTTPS).

curl -X POST http://127.0.0.1:5111/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "admin@example.com", "password": "securepassword123"}'

Logout

POST /api/auth/logout — Clears the session cookie.

Current User

GET /api/auth/me — Returns the current authenticated user info.

Invite User (Admin, Pro)

POST /api/auth/invite

curl -X POST http://127.0.0.1:5111/api/auth/invite \
  -H "Content-Type: application/json" \
  -d '{"email": "dev@example.com", "name": "Developer"}'

# Response includes temporary password
{"email": "dev@example.com", "temp_password": "abc123xyz"}

List Team Members (Pro)

GET /api/auth/team — Lists all organization members.

Licensing

License Status

GET /api/license/status

# Response
{
  "tier": "community",
  "max_agents": 5,
  "max_seats": 1,
  "features": ["core"],
  "expires_at": null,
  "effective_max_agents": 5
}

Activate License

POST /api/license/activate — Admin only.

curl -X POST http://127.0.0.1:5111/api/license/activate \
  -H "Content-Type: application/json" \
  -d '{"key": "eyJhbGciOiJFZERTQSIs..."}'

Deactivate License

DELETE /api/license/deactivate — Admin only. Reverts to Community tier.

System

System Metrics

GET /api/system

# Response
{
  "cpu_pct": 34.2,
  "memory": {"total": 17179869184, "used": 8589934592, "pct": 50.0},
  "agents_active": 3,
  "agents_total": 5,
  "uptime_seconds": 3600
}

Health Check

GET /api/health

{"status": "ok", "version": "1.6.1"}

Get Config

GET /api/config — Returns current runtime configuration.

Update Config

PUT /api/config — Updates config, saves to YAML, applies at runtime. Admin only when auth is enabled.

List Roles

GET /api/roles — Returns all available agent roles with names, colors, and icons.

List Backends

GET /api/backends — Returns available backends with capabilities.

Cost Estimates

GET /api/costs — Returns cost estimates for active and historical agents (heuristic based on character count).

Fleet Templates

List Templates

GET /api/fleet-templates

Create Template

POST /api/fleet-templates

curl -X POST http://127.0.0.1:5111/api/fleet-templates \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Feature Sprint",
    "agents": [
      {"role": "backend", "task": "Implement {feature} API endpoints"},
      {"role": "frontend", "task": "Build {feature} UI components"},
      {"role": "tester", "task": "Write tests for {feature}"}
    ]
  }'

Task strings support parameterized variables: {branch}, {project_name}, {date}, and custom variables.

Update / Delete Template

PUT /api/fleet-templates/{id}

DELETE /api/fleet-templates/{id}

Deploy Template

POST /api/fleet-templates/{id}/deploy

curl -X POST http://127.0.0.1:5111/api/fleet-templates/ft1/deploy \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "p1a2",
    "variables": {"feature": "user-profiles"}
  }'

Agent Extras

Trigger LLM Summary

POST /api/agents/{id}/summarize — Triggers an immediate LLM-generated summary for the agent.

Configure Auto-Handoff

POST /api/agents/{id}/configure-handoff

curl -X POST http://127.0.0.1:5111/api/agents/a7f3/configure-handoff \
  -H "Content-Type: application/json" \
  -d '{
    "next_agent_config": {
      "role": "tester",
      "task": "Write tests for the changes made by {prev_agent}: {prev_summary}",
      "backend": "claude-code"
    }
  }'

When the agent completes, Ashlr automatically spawns the next agent with the configured settings. Variables {prev_summary} and {prev_agent} are interpolated. No recursive chains are allowed.

WebSocket Protocol

Connect to ws://127.0.0.1:5111/ws for real-time updates.

Server-to-Client Messages

TypeDescriptionPayload
syncInitial state on connectionagents, projects, config, license, effective_max_agents
agent_updateAgent state changedagent object with all fields
agent_outputNew terminal output linesagent_id, lines array
metricsSystem metrics updatecpu_pct, memory, agents_active
eventAgent event (needs input, etc.)event name, agent_id, message
license_updateLicense changedlicense object, effective_max_agents
intelligence_alertFleet analysis insightinsight object
file_conflictTwo agents editing same fileconflict object with agent IDs and file path

Client-to-Server Messages

TypeFieldsDescription
spawnrole, name, working_dir, task, plan_modeSpawn a new agent
sendagent_id, messageSend message to agent
killagent_idKill an agent
pauseagent_idPause an agent
resumeagent_idResume a paused agent

Example WebSocket Client

const ws = new WebSocket('ws://127.0.0.1:5111/ws');

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  switch (msg.type) {
    case 'sync':
      console.log('Connected, agents:', msg.agents.length);
      break;
    case 'agent_update':
      console.log(`Agent ${msg.agent.id}: ${msg.agent.status}`);
      break;
    case 'agent_output':
      console.log(`Output from ${msg.agent_id}:`, msg.lines);
      break;
    case 'event':
      if (msg.event === 'agent_needs_input') {
        console.log(`Agent ${msg.agent_id} needs input: ${msg.message}`);
      }
      break;
  }
};

// Spawn an agent via WebSocket
ws.send(JSON.stringify({
  type: 'spawn',
  role: 'backend',
  name: 'my-agent',
  working_dir: '~/Projects/my-app',
  task: 'Add input validation'
}));

// Send a response to a waiting agent
ws.send(JSON.stringify({
  type: 'send',
  agent_id: 'a7f3',
  message: 'yes, proceed'
}));

Error Responses

All endpoints return consistent error JSON:

// 400 Bad Request
{"error": "task is required"}

// 403 Forbidden (feature gated)
{"error": "Pro plan required for workflows", "feature": "workflows", "current_plan": "community"}

// 404 Not Found
{"error": "agent not found"}

// 429 Too Many Requests
{"error": "rate limit exceeded"}

Rate Limiting

The server applies rate limiting via middleware. Default limits are generous for local use but can be hit during automated scripting. Rate-limited responses return HTTP 429 with a Retry-After header.

Edit this page on GitHub