Skip to content

WebSocket API

ClaudeControl uses WebSocket for real-time event streaming between the server and connected clients.

Connecting

ws://host:port

If PIN authentication is enabled, include the token as a query parameter:

ws://host:port?token=<pin-hash>

The token is the SHA-256 hash of the PIN, returned by POST /api/auth/login.

Connections without a valid token when a PIN is set will be closed with code 4001 Unauthorized.

Heartbeat

The server sends a WebSocket ping frame every 30 seconds. Clients must respond with a pong (handled automatically by most WebSocket libraries). If no pong is received within 10 seconds, the connection is terminated.

Events from server

All events are JSON objects with a type field. Events scoped to a workspace include a workspaceId field.

Agent lifecycle

EventDescriptionKey fields
agent_createdNew agent spawnedagent, workspaceId, spawnedBy
agent_updatedAgent config changedagentId, agent, workspaceId
agent_removedAgent closed/deletedagentId, workspaceId
agent_doneAgent finished processingagentId, workspaceId, role, cost
agent_errorAgent encountered an erroragentId, workspaceId, error
agent_sessionSDK session ID assignedagentId, sessionId

Agent output

EventDescriptionKey fields
agent_textAgent produced text outputagentId, workspaceId, text
agent_toolAgent invoked a toolagentId, workspaceId, tool, input
agent_tool_resultTool execution resultagentId, workspaceId, tool, result
agent_workingAgent status changed to workingagentId, workspaceId
agent_user_messageUser message was loggedagentId, workspaceId
agent_log_updatedFull log was updated (e.g. entry hidden)agentId, workspaceId, log
agent_todosAgent todo list updatedagentId, workspaceId, todos

Orchestration

EventDescriptionKey fields
delegation_updateDelegation status changedagentId, workspaceId, delegationId, status, toRole
agent_spawn_requestAgent requested multi-agent spawnworkspaceId, request
spawn_request_updateSpawn request resolvedworkspaceId, request

Permissions

EventDescriptionKey fields
permission_requestAgent needs user approval for a tool callrequestId, agentId, workspaceId, tool, input

Workspace

EventDescriptionKey fields
workspace_resetWorkspace was resetworkspaceId

Messages from client

Clients can send JSON messages to the server:

permission_response

Respond to a permission request:

json
{
  "type": "permission_response",
  "requestId": "req_abc123",
  "approved": true,
  "updatedInput": { "key": "modified_value" }
}
FieldTypeRequiredDescription
requestIdstringyesID from the permission_request event
approvedbooleanyesWhether to allow the tool call
updatedInputobjectnoModified tool input (optional override)

subscribe

Filter events to a specific workspace. Without subscribing, the client receives all events.

json
{
  "type": "subscribe",
  "workspaceId": "ws_abc123"
}

unsubscribe

Stop filtering for a workspace:

json
{
  "type": "unsubscribe",
  "workspaceId": "ws_abc123"
}

Example: connecting with JavaScript

javascript
const ws = new WebSocket('ws://localhost:22609?token=YOUR_TOKEN');

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  switch (data.type) {
    case 'agent_text':
      console.log(`[${data.agentId}] ${data.text}`);
      break;
    case 'agent_done':
      console.log(`Agent ${data.agentId} finished (cost: $${data.cost})`);
      break;
    case 'permission_request':
      // Auto-approve example
      ws.send(JSON.stringify({
        type: 'permission_response',
        requestId: data.requestId,
        approved: true,
      }));
      break;
  }
};

// Subscribe to a specific workspace
ws.onopen = () => {
  ws.send(JSON.stringify({
    type: 'subscribe',
    workspaceId: 'your-workspace-id',
  }));
};

Released under the MIT License.