REST API Reference

Complete reference for the MultiTerminal REST API running on http://localhost:5050. All endpoints accept and return JSON.

Response contract. Success returns the raw resource (or 200 OK with an empty body for a pure acknowledgement) — there is no { "success": true } envelope. Errors are ProblemDetails (RFC 7807, application/problem+json): { type, title, status, detail, traceId }. Clients distinguish success from failure by HTTP status, never by a body flag. Full rules — including the migration/unwrap convention — live in API/CONVENTIONS.md. When adding a new endpoint example below, mirror what the controller actually returns so these docs never drift from the code.

Health & Discovery

GET /

Basic health check. Returns a confirmation that the API is running.

Response

"MultiTerminal API is running"

curl

curl http://localhost:5050/
GET /health

Health check with port information.

Response

{
  "status": "healthy",
  "port": 5050
}

curl

curl http://localhost:5050/health
GET /api/tools

Self-documenting endpoint. Lists all available API endpoints with method, path, and description.

Response

{
  "baseUrl": "http://localhost:5050",
  "endpoints": [
    { "method": "GET", "path": "/", "description": "Health check - API is running" },
    { "method": "POST", "path": "/api/messaging/register", "description": "Register a terminal (name, docId)" },
    ...
  ]
}

curl

curl http://localhost:5050/api/tools

Messaging

Terminal registration and inter-terminal messaging. All messaging endpoints are under /api/messaging.

POST /api/messaging/register

Register a terminal with the messaging system. Returns a unique terminal ID used for subsequent messaging calls.

Request Body

{
  "name": "Alice",
  "docId": "abc123"
}

Response

{
  "terminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Error Response (application/problem+json)

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "Terminal already registered",
  "traceId": "00-a1b2c3d4e5f6-01"
}

curl

curl -X POST http://localhost:5050/api/messaging/register \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice","docId":"abc123"}'
POST /api/messaging/send

Send a direct message to another terminal by name.

Request Body

{
  "fromTerminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "to": "Bob",
  "message": "Hello, can you help with the database migration?"
}

Response

{
  "success": true,
  "messageId": "a1b2c3d4",
  "error": null
}

curl

curl -X POST http://localhost:5050/api/messaging/send \
  -H "Content-Type: application/json" \
  -d '{"fromTerminalId":"a1b2c3d4","to":"Bob","message":"Hello!"}'
POST /api/messaging/broadcast

Broadcast a message to all registered terminals.

Request Body

{
  "fromTerminalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "message": "Build is ready for testing!"
}

Response

{
  "success": true,
  "recipientCount": 3,
  "error": null
}

curl

curl -X POST http://localhost:5050/api/messaging/broadcast \
  -H "Content-Type: application/json" \
  -d '{"fromTerminalId":"a1b2c3d4","message":"Build ready!"}'
GET /api/messaging/messages/{terminalId}

Get pending messages for a terminal. Messages are consumed on read (delivered once).

Response

[
  {
    "from": "Bob",
    "to": "Alice",
    "message": "Sure, I can help!",
    "timestamp": "2026-03-05T10:30:00Z"
  }
]

curl

curl http://localhost:5050/api/messaging/messages/a1b2c3d4
GET /api/messaging/terminals

List all registered terminals with their names, IDs, and last-active timestamps.

Response

[
  {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "Alice",
    "docId": "abc123",
    "lastActiveAt": "2026-03-05T10:30:00Z"
  }
]

curl

curl http://localhost:5050/api/messaging/terminals
POST /api/messaging/disconnect

Disconnect a terminal by name. Used by session-end hooks for cleanup.

Request Body

{
  "name": "Alice"
}

Response

{
  "name": "Alice"
}

curl

curl -X POST http://localhost:5050/api/messaging/disconnect \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice"}'

Tasks

CRUD operations for kanban tasks. All task endpoints are under /api/tasks.

GET /api/tasks

List all tasks, optionally filtered by status.

Query Parameters

ParamTypeDefaultDescription
statusstringallFilter: all, todo, in_progress, done, suggestion

Response

[
  {
    "id": "c0ce8037",
    "title": "Add dark mode",
    "description": "Implement dark mode theme switching",
    "status": "in_progress",
    "assignee": "Alice",
    "createdBy": "Alice",
    "createdAt": "2026-03-05T08:00:00Z",
    "priority": "normal",
    "subStatus": "active",
    "checklistJson": "[...]",
    "plan": "...",
    "continuationNotes": "..."
  }
]

curl

curl http://localhost:5050/api/tasks?status=in_progress
GET /api/tasks/{taskId}

Get a specific task by ID.

Response

{
  "id": "c0ce8037",
  "title": "Add dark mode",
  "status": "in_progress",
  ...
}

Error (404)

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404,
  "detail": "Task c0ce8037 not found",
  "traceId": "00-a1b2c3d4e5f6-01"
}

curl

curl http://localhost:5050/api/tasks/c0ce8037
GET /api/tasks/{taskId}/detail

Get full task detail including parsed checklist with notes history, helpers, and progress summary.

Response

{
  "task": { "id": "c0ce8037", "title": "Add dark mode", ... },
  "checklistSummary": {
    "total": 5,
    "done": 2,
    "coding": 1,
    "testing": 1,
    "pending": 1
  },
  "checklist": [
    {
      "item": "Create theme service",
      "status": "done",
      "notes": [
        { "text": "Implemented ThemeService with light/dark toggle", "at": "2026-03-05T09:00:00Z", "by": "Alice" }
      ],
      "assignee": "Alice",
      "cycleCount": 0
    }
  ]
}

curl

curl http://localhost:5050/api/tasks/c0ce8037/detail
POST /api/tasks

Create a new kanban task.

Request Body

{
  "title": "Fix login bug",
  "description": "Users get 500 error on login when password contains special characters",
  "createdBy": "Alice",
  "status": "todo",
  "priority": "high"
}
FieldTypeRequiredDefaultDescription
titlestringYes-Task title
descriptionstringYes-Task description
createdBystringYes-Creator name
statusstringNotodoInitial status
prioritystringNonormallow, normal, high

Response

{
  "taskId": "a1b2c3d4",
  "task": { "id": "a1b2c3d4", "title": "Fix login bug", ... }
}

curl

curl -X POST http://localhost:5050/api/tasks \
  -H "Content-Type: application/json" \
  -d '{"title":"Fix login bug","description":"Details","createdBy":"Alice","status":"todo","priority":"high"}'
PATCH /api/tasks/{taskId}/status

Update a task's status.

Request Body

{
  "status": "in_progress",
  "updatedBy": "Alice"
}

Response

{ "status": "in_progress" }

curl

curl -X PATCH http://localhost:5050/api/tasks/c0ce8037/status \
  -H "Content-Type: application/json" \
  -d '{"status":"in_progress","updatedBy":"Alice"}'
POST /api/tasks/{taskId}/assign

Assign (claim) a task to a team member.

Request Body

{ "assignee": "Alice" }

Response

{ "assignee": "Alice" }

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/assign \
  -H "Content-Type: application/json" \
  -d '{"assignee":"Alice"}'
POST /api/tasks/{taskId}/activate

Set a task as the active task for its assignee. Auto-pauses any other active tasks for the same person (enforces "one active task" rule).

Request Body

{ "updatedBy": "Alice" }

Response

{
  "pausedTaskIds": ["d4e5f6a7"],
  "pausedTaskTitles": ["Refactor auth module"],
  "branchCandidates": [{ "branch": "task/9f9c3141", "outcome": "Adds OAuth login", "linkedTaskTitle": "Auth epic" }]
}

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/activate \
  -H "Content-Type: application/json" \
  -d '{"updatedBy":"Alice"}'
POST /api/tasks/{taskId}/helpers

Add a helper to a task. Helpers assist without being the primary assignee.

Request Body

{
  "helper": "Bob",
  "addedBy": "Alice"
}

Response

{ "helperCount": 2 }

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/helpers \
  -H "Content-Type: application/json" \
  -d '{"helper":"Bob","addedBy":"Alice"}'
DELETE /api/tasks/{taskId}/helpers/{helperName}

Remove a helper from a task.

Response

{ "helperCount": 1 }

curl

curl -X DELETE http://localhost:5050/api/tasks/c0ce8037/helpers/Bob
DELETE /api/tasks/{taskId}

Delete a task.

Query Parameters

ParamTypeRequiredDescription
deletedBystringYesName of person deleting

Response

200 OK (empty body)

curl

curl -X DELETE "http://localhost:5050/api/tasks/c0ce8037?deletedBy=Alice"

Checklist Workflow

Enhanced checklist management with state machine transitions. The lifecycle is: pending → coding → testing → done (cycling allowed between coding and testing).

PATCH /api/tasks/{taskId}/checklist

Replace all checklist items. Use for initial setup or bulk editing.

Request Body

{
  "checklistJson": "[{\"item\":\"Setup database\",\"status\":\"pending\",\"notes\":[]},{\"item\":\"Create API\",\"status\":\"pending\",\"notes\":[]}]"
}

Response

200 OK (empty body)

curl

curl -X PATCH http://localhost:5050/api/tasks/c0ce8037/checklist \
  -H "Content-Type: application/json" \
  -d '{"checklistJson":"[{\"item\":\"Setup database\",\"status\":\"pending\",\"notes\":[]}]"}'
POST /api/tasks/{taskId}/checklist/append

Append items to the existing checklist (preserves existing items). Appended items default to status pending.

Request Body

{
  "itemsJson": "[{\"item\":\"Add validation\",\"status\":\"pending\",\"notes\":[]}]"
}

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/checklist/append \
  -H "Content-Type: application/json" \
  -d '{"itemsJson":"[{\"item\":\"Add validation\",\"status\":\"pending\",\"notes\":[]}]"}'
POST /api/tasks/{taskId}/checklist/{itemIndex}/transition

Transition a checklist item to a new status. Enforces the state machine and tracks cycle count for escalation.

Request Body

{
  "newStatus": "testing",
  "notes": "Implemented database schema and CRUD operations",
  "updatedBy": "Alice"
}

Response

{
  "itemName": "Setup database",
  "previousStatus": "coding",
  "newStatus": "testing",
  "cycleCount": 0,
  "escalationTriggered": false
}

Note: If cycleCount reaches 3, escalationTriggered becomes true and an inbox notification is sent to the PM.

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/checklist/0/transition \
  -H "Content-Type: application/json" \
  -d '{"newStatus":"testing","notes":"Schema and CRUD done","updatedBy":"Alice"}'
POST /api/tasks/{taskId}/checklist/{itemIndex}/assign

Assign a checklist item to a specific agent.

Request Body

{ "assignee": "Alice" }

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/checklist/0/assign \
  -H "Content-Type: application/json" \
  -d '{"assignee":"Alice"}'
PATCH /api/tasks/{taskId}/plan

Set or update the implementation plan (markdown formatted).

Request Body

{
  "plan": "## Phase 1: Database\n- Create migrations\n- Add indexes\n\n## Phase 2: API\n- REST endpoints\n- Validation",
  "updatedBy": "Alice"
}

Response

200 OK (empty body)

curl

curl -X PATCH http://localhost:5050/api/tasks/c0ce8037/plan \
  -H "Content-Type: application/json" \
  -d '{"plan":"## Phase 1\n- Step 1","updatedBy":"Alice"}'
PATCH /api/tasks/{taskId}/summary

Update implementation summary and/or test results. Pass null for fields you don't want to change.

Request Body

{
  "implementationSummary": "Added ThemeService with dark/light toggle and CSS variable support",
  "testResults": "All 12 unit tests passing. Manual UI verification complete.",
  "updatedBy": "Alice"
}

Response

200 OK (empty body)

curl

curl -X PATCH http://localhost:5050/api/tasks/c0ce8037/summary \
  -H "Content-Type: application/json" \
  -d '{"implementationSummary":"Added theme service","updatedBy":"Alice"}'
PATCH /api/tasks/{taskId}/continuation

Update continuation notes for session handoff. Describes where to pick up work.

Request Body

{
  "continuationNotes": "Working on checklist item 3 (API validation). File: Controllers/TasksController.cs. Next: add input sanitization for title field.",
  "updatedBy": "Alice"
}

Response

200 OK (empty body)

curl

curl -X PATCH http://localhost:5050/api/tasks/c0ce8037/continuation \
  -H "Content-Type: application/json" \
  -d '{"continuationNotes":"Pick up at item 3","updatedBy":"Alice"}'

Inbox & Notifications

Inbox notifications for task events like checklist items ready for testing, escalations, and helper requests. Endpoints are under /api/tasks/inbox.

GET /api/tasks/inbox/{userId}

Get inbox messages for a user.

Query Parameters

ParamTypeDefaultDescription
unreadOnlybooleanfalseOnly return unread messages
limitinteger50Max messages to return

Response

{
  "success": true,
  "messages": [
    {
      "id": "abc12345",
      "userId": "Owner",
      "taskId": "c0ce8037",
      "taskTitle": "Add dark mode",
      "checklistItemIndex": 2,
      "checklistItemName": "Add validation",
      "type": "ready_for_testing",
      "summary": "Alice finished 'Add validation' - ready for testing",
      "createdAt": "2026-03-05T10:30:00Z",
      "createdBy": "Alice",
      "readAt": null,
      "replyText": null,
      "repliedAt": null
    }
  ],
  "unreadCount": 5,
  "totalCount": 1,
  "error": null
}

Message types: ready_for_testing, escalation, task_complete, helper_request

curl

curl "http://localhost:5050/api/tasks/inbox/Owner?unreadOnly=true"
POST /api/tasks/inbox/{messageId}/read

Mark a single inbox message as read.

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/tasks/inbox/abc12345/read
POST /api/tasks/inbox/{userId}/read-all

Mark all inbox messages as read for a user.

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/tasks/inbox/Owner/read-all
POST /api/tasks/inbox/{messageId}/reply

Reply to an inbox message. Auto-marks the message as read.

Request Body

{ "replyText": "Looks good, marking as done" }

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/tasks/inbox/abc12345/reply \
  -H "Content-Type: application/json" \
  -d '{"replyText":"Looks good, marking as done"}'
GET /api/tasks/inbox/{userId}/unread-count

Get unread inbox message count for a user.

Response

{ "count": 5 }

curl

curl http://localhost:5050/api/tasks/inbox/Owner/unread-count

Attachments

Image attachments for tasks and checklist items. Stored as binary blobs in SQLite.

GET /api/tasks/{taskId}/attachments

Get attachment metadata for a task, optionally filtered by checklist item index.

Query Parameters

ParamTypeDefaultDescription
itemIndexinteger-Filter by checklist item index

Response

[
  {
    "id": "att-12345",
    "taskId": "c0ce8037",
    "checklistItemIndex": 0,
    "fileName": "screenshot.png",
    "mimeType": "image/png",
    "addedBy": "Alice",
    "addedAt": "2026-03-05T10:00:00Z"
  }
]

curl

curl "http://localhost:5050/api/tasks/c0ce8037/attachments?itemIndex=0"
GET /api/tasks/attachments/{attachmentId}/image

Get raw binary image data for an attachment. Returns the file with appropriate MIME type.

Response

Raw binary image data with Content-Type header (e.g., image/png).

curl

curl http://localhost:5050/api/tasks/attachments/att-12345/image -o screenshot.png
GET /api/tasks/attachments/{attachmentId}/base64

Get attachment image as base64-encoded string with metadata. Useful for agents that need to analyze images.

Response

{
  "base64": "iVBORw0KGgoAAAANSUhEUgAA...",
  "mimeType": "image/png",
  "fileName": "screenshot.png"
}

curl

curl http://localhost:5050/api/tasks/attachments/att-12345/base64
POST /api/tasks/{taskId}/attachments

Add a base64-encoded image attachment to a task or checklist item.

Request Body

{
  "checklistItemIndex": 0,
  "fileName": "bug-screenshot.png",
  "mimeType": "image/png",
  "base64Data": "iVBORw0KGgoAAAANSUhEUgAA...",
  "addedBy": "Alice"
}

Response

{ "attachmentId": "att-67890" }

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/attachments \
  -H "Content-Type: application/json" \
  -d '{"checklistItemIndex":0,"fileName":"bug.png","mimeType":"image/png","base64Data":"...","addedBy":"Alice"}'
DELETE /api/tasks/attachments/{attachmentId}

Delete an attachment by ID.

Response

200 OK (empty body)

curl

curl -X DELETE http://localhost:5050/api/tasks/attachments/att-12345

Office Panel

Agent presence tracking for the Office Panel UI. Triggers walk-in/exit animations. Endpoints are under /api/office.

POST /api/office/agents

Notify that an agent has been spawned. Triggers walk-in animation in the Office Panel.

Request Body

{
  "name": "Alice",
  "spawnedBy": "Owner"
}

Response

{ "agentName": "Alice" }

curl

curl -X POST http://localhost:5050/api/office/agents \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice","spawnedBy":"Owner"}'
DELETE /api/office/agents/{name}

Notify that an agent has departed. Triggers exit animation in the Office Panel.

Response

{ "agentName": "Alice" }

curl

curl -X DELETE http://localhost:5050/api/office/agents/Alice
GET /api/office/agents

List all currently active office agents.

Response

[
  { "name": "Alice", "spawnedBy": "Owner", "spawnedAt": "2026-03-05T10:00:00Z" },
  { "name": "Bob", "spawnedBy": "Alice", "spawnedAt": "2026-03-05T10:05:00Z" }
]

curl

curl http://localhost:5050/api/office/agents
DELETE /api/office/agents/cleanup

Remove stale/ghost office agents older than a specified number of minutes.

Query Parameters

ParamTypeDefaultDescription
olderThanMinutesinteger30Remove agents older than this

Response

{
  "removedCount": 2,
  "removedAgents": ["Ghost1", "Ghost2"]
}

curl

curl -X DELETE "http://localhost:5050/api/office/agents/cleanup?olderThanMinutes=60"
DELETE /api/office/agents/clear-all

Force-clear all office agents. Nuclear option for ghost cleanup.

Response

{
  "removedCount": 5,
  "removedAgents": ["Ghost1", "Ghost2", "Ghost3", "Ghost4", "Ghost5"]
}

curl

curl -X DELETE http://localhost:5050/api/office/agents/clear-all

Agent Spawning

POST /api/spawn/agent

Spawn a headless AgentProcess with piped stdin/stdout. The agent runs Claude Code in stream-json mode and its conversation is displayed in the Agent Panel.

Request Body

{
  "agentName": "Agent Alice",
  "workingDir": "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal",
  "initialPrompt": "Implement the dark mode feature",
  "mcpConfigPath": "C:\\Users\\<username>\\.claude\\mcp-config.json",
  "spawnerName": "Owner",
  "taskDescription": "Add dark mode toggle to the settings panel",
  "subagentType": "coder"
}
FieldTypeRequiredDescription
agentNamestringYesName for the spawned agent
workingDirstringNoWorking directory for the agent
initialPromptstringNoInitial prompt to send to the agent
mcpConfigPathstringNoPath to MCP configuration
spawnerNamestringNoWho is spawning this agent
taskDescriptionstringNoDescription of the task for the agent
subagentTypestringNoType of subagent (e.g., coder, reviewer)

Response

{
  "agentName": "Agent Alice",
  "processId": 12345,
  "sessionId": "a1b2c3d4"
}

curl

curl -X POST http://localhost:5050/api/spawn/agent \
  -H "Content-Type: application/json" \
  -d '{"agentName":"Agent Alice","workingDir":"H:\\DevLaptop\\MyProject","initialPrompt":"Fix the bug","spawnerName":"Owner"}'

Agent Panels

POST /api/agent-panels/close

Close an agent panel by transcript path. Called by the SubagentStop hook when a subagent finishes.

Request Body

{
  "transcriptPath": "C:\\Users\\<username>\\.claude\\teams\\my-team\\Agent Alice\\transcript.jsonl"
}

Response

{
  "transcriptPath": "C:\\Users\\John\\.claude\\projects\\...\\transcript.jsonl"
}

curl

curl -X POST http://localhost:5050/api/agent-panels/close \
  -H "Content-Type: application/json" \
  -d '{"transcriptPath":"C:\\Users\\<username>\\.claude\\teams\\my-team\\Agent Alice\\transcript.jsonl"}'

Knowledge Base

Institutional memory system for decisions, patterns, gotchas, and code digests. Endpoints are under /api/knowledge.

GET /api/knowledge/search

Search knowledge entries by text query, category, project, and tags. Uses FTS5 full-text search.

Query Parameters

ParamTypeDefaultDescription
querystring-Search text
categorystring-decision, pattern, gotcha, anti_pattern, debug_insight, preference
projectIdstring-Filter by project
tagsstring-Comma-separated tags
limitinteger20Max results (max 500)

Response

{
  "results": [
    {
      "id": 1,
      "projectId": "proj-123",
      "category": "gotcha",
      "title": "PowerShell single-quote injection",
      "content": "Always escape single quotes with Replace(\"'\", \"''\") before interpolating into PowerShell commands",
      "sourceType": "session",
      "tags": "security,powershell",
      "confidence": "confirmed",
      "createdAt": "2026-02-28T10:00:00Z"
    }
  ],
  "totalCount": 1
}

curl

curl "http://localhost:5050/api/knowledge/search?query=injection&category=gotcha&limit=10"
POST /api/knowledge

Create a new knowledge entry.

Request Body

{
  "title": "Always use parameterized queries",
  "content": "Never interpolate user input into SQL strings. Use SQLiteParameter for all values.",
  "category": "pattern",
  "projectId": "proj-123",
  "sourceType": "review",
  "tags": "security,sql,database",
  "confidence": "confirmed"
}

Response

{ "id": 42 }

curl

curl -X POST http://localhost:5050/api/knowledge \
  -H "Content-Type: application/json" \
  -d '{"title":"Use parameterized queries","content":"Never interpolate...","category":"pattern","confidence":"confirmed"}'
PUT /api/knowledge/{id}

Update an existing knowledge entry. Accepts a dictionary of field names to values.

Request Body

{
  "confidence": "confirmed",
  "tags": "security,sql,database,critical"
}

Accepted fields: category, title, content, tags, confidence, superseded_by

Response

200 OK (empty body)

curl

curl -X PUT http://localhost:5050/api/knowledge/42 \
  -H "Content-Type: application/json" \
  -d '{"confidence":"confirmed","tags":"security,sql"}'
GET /api/knowledge/digest

Get the code digest (pre-analyzed summary) for a specific file.

Query Parameters

ParamTypeRequiredDescription
filePathstringYesAbsolute path to the source file
projectIdstringNoProject ID

Response

{
  "id": 1,
  "projectId": "proj-123",
  "filePath": "H:\\DevLaptop\\...\\MessageBroker.cs",
  "fileHash": "abc123def456...",
  "purpose": "Central hub routing all messages, caching tasks/terminals/profiles",
  "keyClasses": "[\"MessageBroker\"]",
  "keyMethods": "[\"SendMessage\",\"RegisterTerminal\",\"CreateTask\"]",
  "patterns": "ConcurrentDictionary caching, event-driven UI updates",
  "gotchas": "Thread-safety required for all dictionary access",
  "dependencies": "[\"TaskDatabase\",\"ActivityService\"]",
  "lineCount": 4254,
  "digestModel": "haiku"
}

curl

curl "http://localhost:5050/api/knowledge/digest?filePath=H%3A%5CDevLaptop%5C...%5CMessageBroker.cs"
POST /api/knowledge/digest

Save or update a code digest for a file.

Request Body

{
  "projectId": "proj-123",
  "filePath": "H:\\DevLaptop\\...\\TaskDatabase.cs",
  "fileHash": "sha256-hash-here",
  "purpose": "SQLite persistence layer for tasks, profiles, and activity",
  "keyClasses": "[\"TaskDatabase\"]",
  "keyMethods": "[\"GetTask\",\"SaveTask\",\"LoadTaskHelpers\"]",
  "patterns": "SQLite with manual migrations, connection pooling",
  "gotchas": "Must call EnsureSchema() before any operations",
  "dependencies": "[\"System.Data.SQLite\"]",
  "lineCount": 2694,
  "digestModel": "haiku"
}

Response

{ "id": 5 }

curl

curl -X POST http://localhost:5050/api/knowledge/digest \
  -H "Content-Type: application/json" \
  -d '{"projectId":"proj-123","filePath":"...","fileHash":"abc123","purpose":"..."}'
POST /api/knowledge/digest/stale

Check which digests are stale by comparing file hashes. Supply a dictionary of file paths to current hashes.

Query Parameters

ParamTypeRequiredDescription
projectIdstringNoFilter by project

Request Body

{
  "fileHashes": {
    "H:\\DevLaptop\\...\\MessageBroker.cs": "currenthash123",
    "H:\\DevLaptop\\...\\TaskDatabase.cs": "currenthash456"
  }
}

Response

{
  "stale": [
    {
      "filePath": "H:\\DevLaptop\\...\\MessageBroker.cs",
      "storedHash": "oldhash789",
      "currentHash": "currenthash123"
    }
  ],
  "count": 1
}

curl

curl -X POST "http://localhost:5050/api/knowledge/digest/stale?projectId=proj-123" \
  -H "Content-Type: application/json" \
  -d '{"fileHashes":{"path1":"hash1","path2":"hash2"}}'

Session Lineage

Import, query, and search Claude Code session transcripts. Supports lineage chaining for tracking agent cycling. Endpoints are under /api/session-lineage.

POST /api/session-lineage/import

Import a Claude Code session JSONL file and link it to a kanban task. Extracts messages and indexes them with FTS5 for full-text search.

Request Body

{
  "sessionFilePath": "C:\\Users\\<username>\\.claude\\projects\\...\\sessions\\abc123.jsonl",
  "taskId": "c0ce8037",
  "agentName": "Alice",
  "parentSessionId": "prev-session-id",
  "sessionType": "coding"
}
FieldTypeRequiredDescription
sessionFilePathstringYesPath to JSONL file (must be within ~/.claude/projects)
taskIdstringYesKanban task ID
agentNamestringYesAgent who ran the session
parentSessionIdstringNoParent session for lineage chaining
sessionTypestringNoSemantic label: coding, review, testing

Response

{
  "sessionId": "def456",
  "messageCount": 127
}

curl

curl -X POST http://localhost:5050/api/session-lineage/import \
  -H "Content-Type: application/json" \
  -d '{"sessionFilePath":"C:\\Users\\<username>\\.claude\\...\\abc123.jsonl","taskId":"c0ce8037","agentName":"Alice"}'
GET /api/session-lineage/task/{taskId}/sessions

Get all session lineage records for a task, newest first.

Response

[
  {
    "sessionId": "def456",
    "parentSessionId": "abc123",
    "taskId": "c0ce8037",
    "agentName": "Alice",
    "sessionType": "coding",
    "summary": "Implemented database migrations and CRUD endpoints",
    "startedAt": "2026-03-05T08:00:00Z",
    "endedAt": "2026-03-05T09:30:00Z"
  }
]

curl

curl http://localhost:5050/api/session-lineage/task/c0ce8037/sessions
GET /api/session-lineage/{sessionId}/chain

Get the full lineage chain for a session, ordered root to leaf. Walks parent_session_id links.

Response

[
  { "sessionId": "abc123", "agentName": "Alice", "sessionType": "coding", ... },
  { "sessionId": "def456", "agentName": "Alice", "sessionType": "review", "parentSessionId": "abc123", ... }
]

curl

curl http://localhost:5050/api/session-lineage/def456/chain
POST /api/session-lineage/sync

Incrementally sync sessions from a Claude project folder. Skips already-imported sessions.

Request Body

{
  "claudeProjectPath": "C:\\Users\\<username>\\.claude\\projects\\H--DevLaptop-...",
  "agentName": "Alice",
  "taskId": "c0ce8037"
}

Response

{
  "imported": 3,
  "skipped": 12,
  "failed": 0,
  "total": 15
}

curl

curl -X POST http://localhost:5050/api/session-lineage/sync \
  -H "Content-Type: application/json" \
  -d '{"claudeProjectPath":"C:\\Users\\<username>\\.claude\\projects\\...","agentName":"Alice"}'
GET /api/session-lineage/latest

Get the most recent session for a project. Optionally filter by agent name to get a specific agent's last session. If no cached summary exists, returns the last 10 assistant messages for lazy summary generation.

Query Parameters

ParamTypeRequiredDescription
projectPathstringYesFilesystem path to the project
agentNamestringNoFilter by agent name (e.g. "Alice"). Returns the most recent session for this specific agent.

Response

{
  "session": {
    "sessionId": "def456",
    "taskId": "c0ce8037",
    "agentName": "Alice",
    "sessionType": "coding",
    "startedAt": "2026-03-05T08:00:00Z"
  },
  "summary": "Implemented database migrations and CRUD endpoints for the knowledge base",
  "recentMessages": null
}

curl

# Latest session across all agents
curl "http://localhost:5050/api/session-lineage/latest?projectPath=H%3A%5CDevLaptop%5C..."

# Latest session for a specific agent
curl "http://localhost:5050/api/session-lineage/latest?projectPath=H%3A%5CDevLaptop%5C...&agentName=Alice"
PUT /api/session-lineage/{sessionId}/summary

Save a generated summary for a session.

Request Body

{ "summary": "Implemented the knowledge base with FTS5 search, CRUD endpoints, and code digest system" }

Response

200 OK (empty body)

curl

curl -X PUT http://localhost:5050/api/session-lineage/def456/summary \
  -H "Content-Type: application/json" \
  -d '{"summary":"Implemented knowledge base..."}'
GET /api/session-lineage/search

Full-text search across session messages. Uses FTS5 when available, falls back to LIKE.

Query Parameters

ParamTypeRequiredDescription
taskIdstringNo*Filter by task
querystringNo*Search text
rolestringNouser or assistant
agentNamestringNoFilter by agent
limitintegerNoMax results (default 50, max 1000)

* At least one of taskId or query is required.

Response

{
  "results": [
    {
      "sessionId": "def456",
      "messageIndex": 42,
      "role": "assistant",
      "content": "I implemented the FTS5 search indexing...",
      "toolName": null,
      "timestamp": "2026-03-05T09:15:00Z"
    }
  ],
  "totalCount": 3
}

curl

curl "http://localhost:5050/api/session-lineage/search?taskId=c0ce8037&query=FTS5&role=assistant&limit=20"

Projects

Project context endpoints for agent orientation. Endpoints are under /api/projects.

GET /api/projects/{projectId}/context

Get the full project context: project record joined with all association tables (agents, MCP servers, specialist agents, paths, prompts, skills) in a single response.

Response

{
  "project": {
    "id": "proj-123",
    "name": "MultiTerminal",
    "description": "Multi-agent coordination system",
    "path": "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal",
    "deployPath": "H:\\DevLaptop\\ClarionPowerShell\\Deploy",
    "buildCommand": "dotnet build",
    "projectType": "WinForms",
    "gitRepoUrl": "...",
    "gitDefaultBranch": "main",
    "isPinned": true,
    "teamLead": "Owner"
  },
  "agents": [
    { "agentName": "Alice", "role": "backend", "preferredModel": "sonnet" }
  ],
  "mcpServers": [
    { "serverName": "multiterminal-mcp", "isEnabled": true }
  ],
  "specialistAgents": [
    { "agentType": "verifier", "isEnabled": true, "customPrompt": null }
  ],
  "paths": [
    { "pathType": "source", "pathValue": "H:\\DevLaptop\\...", "description": "Main source" }
  ],
  "prompts": [
    { "promptType": "system", "promptText": "...", "displayOrder": 0 }
  ],
  "skills": [
    { "skillName": "kanban-task", "isEnabled": true }
  ]
}

curl

curl http://localhost:5050/api/projects/proj-123/context
GET /api/projects/contexts

List all project contexts with their full association data.

Response

{
  "count": 3,
  "contexts": [ ... ]
}

curl

curl http://localhost:5050/api/projects/contexts

Team

GET /api/team/roster

Get the team roster for a project, merged with profile data. Returns each agent's name, preferred model, instructions, role, and skills.

Query Parameters

ParamTypeRequiredDescription
projectPathstringYesAbsolute path to the project directory

Response

{
  "projectName": "MultiTerminal",
  "projectPath": "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal",
  "agents": [
    {
      "name": "Alice",
      "hasProfile": true,
      "preferredModel": "sonnet",
      "agentInstructions": "Backend systems architect specializing in C# and SQLite",
      "role": "backend",
      "skills": ["database", "api-design", "c-sharp"],
      "isOnline": true,
      "isTeamLead": false
    }
  ]
}

curl

curl "http://localhost:5050/api/team/roster?projectPath=H%3A%5CDevLaptop%5CClarionPowerShell%5CMultiTerminal"

Debug

Debug logging for system diagnostics. Endpoints are under /api/debug.

GET /api/debug/logs

Get debug log entries with filtering and pagination. Ordered by most recent first.

Query Parameters

ParamTypeDefaultDescription
countinteger50Number of entries to return
offsetinteger0Skip entries for pagination
sourcestring-Filter by component (e.g., InboxMonitor, MessageBroker)
levelstring-Trace, Info, Warning, Error
searchstring-Text search within messages (case-insensitive)

Response

{
  "total": 1234,
  "offset": 0,
  "count": 2,
  "entries": [
    {
      "timestamp": "10:30:45.123",
      "source": "InboxMonitor",
      "level": "Info",
      "message": "Nudge sent to terminal Alice for task c0ce8037"
    },
    {
      "timestamp": "10:30:44.987",
      "source": "MessageBroker",
      "level": "Trace",
      "message": "Message delivered from Bob to Alice"
    }
  ]
}

curl

curl "http://localhost:5050/api/debug/logs?count=20&source=InboxMonitor&level=Info"
DELETE /api/debug/logs

Clear all debug log entries.

Response

{ "message": "Debug logs cleared", "previousCount": 1234 }

curl

curl -X DELETE http://localhost:5050/api/debug/logs
POST /api/debug/pause

Pause debug logging. New entries are silently discarded until resumed.

Response

{ "isPaused": true }

curl

curl -X POST http://localhost:5050/api/debug/pause
POST /api/debug/resume

Resume debug logging.

Response

{ "isPaused": false }

curl

curl -X POST http://localhost:5050/api/debug/resume
GET /api/debug/status

Get debug log status.

Response

{
  "count": 1234,
  "isPaused": false,
  "maxCapacity": 10000
}

curl

curl http://localhost:5050/api/debug/status

Fast code and file search powered by ripgrep (bundled as tools/rg.exe). Endpoints are under /api/search.

POST /api/search/content

Search file contents using ripgrep regex. Returns matches with file paths, line numbers, and search statistics.

Request

{
  "pattern": "class.*Service",
  "path": "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal",
  "caseInsensitive": false,
  "glob": "*.cs",
  "fileType": null,
  "maxCount": 10,
  "context": 2,
  "before": 0,
  "after": 0,
  "multiline": false,
  "fixedStrings": false,
  "filesWithMatches": false,
  "count": false
}

Response

{
  "matchCount": 15,
  "matches": [
    {
      "filePath": "Services/RipgrepService.cs",
      "lineNumber": 10,
      "text": "    public class RipgrepService",
      "line": "Services/RipgrepService.cs:10:    public class RipgrepService"
    }
  ],
  "stats": {
    "matchedLines": 15,
    "matches": 15,
    "searchedFiles": 80,
    "elapsedMs": 12.3
  }
}

curl

curl -X POST http://localhost:5050/api/search/content \
  -H "Content-Type: application/json" \
  -d '{"pattern":"class.*Service","path":"H:\\\\project","glob":"*.cs"}'
POST /api/search/files

Find files matching a glob pattern or file type filter.

Request

{
  "path": "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal",
  "glob": "*.cs",
  "fileType": null
}

Response

{
  "fileCount": 80,
  "files": [
    "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal\\MainForm.cs",
    "..."
  ]
}

curl

curl -X POST http://localhost:5050/api/search/files \
  -H "Content-Type: application/json" \
  -d '{"path":"H:\\\\project","glob":"*.cs"}'
GET /api/search/status

Check if ripgrep is available.

Response

{ "available": true }

curl

curl http://localhost:5050/api/search/status

Task Relationships

Blocking and dependency relationships between tasks. Automatically creates inverse relationships. Endpoints are under /api/tasks/{taskId}/relationships.

POST /api/tasks/{taskId}/relationships

Add a relationship between two tasks. Automatically creates the inverse relationship (e.g., if A blocks B, then B is blocked_by A).

Request Body

{
  "targetTaskId": "d4e5f6a7",
  "type": "blocks",
  "createdBy": "Alice"
}
FieldTypeRequiredDescription
targetTaskIdstringYesTarget task ID
typestringYesblocks, depends_on, related_to
createdBystringYesWho created the relationship

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/relationships \
  -H "Content-Type: application/json" \
  -d '{"targetTaskId":"d4e5f6a7","type":"blocks","createdBy":"Alice"}'
GET /api/tasks/{taskId}/relationships

Get all relationships for a task.

Response

{
  "relationships": [
    {
      "sourceTaskId": "c0ce8037",
      "targetTaskId": "d4e5f6a7",
      "type": "blocks",
      "createdBy": "Alice"
    }
  ]
}

curl

curl http://localhost:5050/api/tasks/c0ce8037/relationships
DELETE /api/tasks/{taskId}/relationships/{relatedTaskId}

Remove a relationship between two tasks (removes both directions).

Response

200 OK (empty body)

curl

curl -X DELETE http://localhost:5050/api/tasks/c0ce8037/relationships/d4e5f6a7

Task File Links

Link files to tasks for code review context and agent orientation. Supports optional line ranges. Endpoints are under /api/tasks/{taskId}/files.

POST /api/tasks/{taskId}/files

Link a file to a task.

Request Body

{
  "filePath": "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal\\Services\\TaskDatabase.cs",
  "description": "Core persistence layer being modified",
  "lineStart": 100,
  "lineEnd": 250,
  "addedBy": "Alice"
}

Response

{ "fileCount": 3 }

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/files \
  -H "Content-Type: application/json" \
  -d '{"filePath":"H:\\\\path\\\\to\\\\file.cs","description":"Relevant file","addedBy":"Alice"}'
GET /api/tasks/{taskId}/files

Get all files linked to a task.

Response

{
  "files": [
    {
      "filePath": "H:\\DevLaptop\\...\\TaskDatabase.cs",
      "description": "Core persistence layer",
      "lineStart": 100,
      "lineEnd": 250,
      "addedBy": "Alice",
      "addedAt": "2026-03-10T10:00:00Z"
    }
  ]
}

curl

curl http://localhost:5050/api/tasks/c0ce8037/files
POST /api/tasks/{taskId}/files/unlink

Unlink a file from a task.

Request Body

{ "filePath": "H:\\DevLaptop\\...\\TaskDatabase.cs" }

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/files/unlink \
  -H "Content-Type: application/json" \
  -d '{"filePath":"H:\\\\path\\\\to\\\\file.cs"}'
GET /api/tasks/{taskId}/code-review

Get code review diff data for all linked files in a task. Returns file list with git diff output for each.

Response

{
  "taskId": "c0ce8037",
  "fileCount": 2,
  "files": [
    {
      "filePath": "H:\\DevLaptop\\...\\TaskDatabase.cs",
      "description": "Core persistence layer",
      "hasDiff": true,
      "diff": "--- a/Services/TaskDatabase.cs\n+++ b/Services/TaskDatabase.cs\n..."
    }
  ]
}

curl

curl http://localhost:5050/api/tasks/c0ce8037/code-review

Task Reports

Persisted agent reports (HTML/markdown) linked to kanban tasks. Generated by specialist agents (verifier, code-reviewer, security-auditor). Endpoints are under /api/tasks/{taskId}/reports.

GET /api/tasks/{taskId}/reports

List reports for a task (metadata only, no content).

Query Parameters

ParamTypeDefaultDescription
agentNamestring-Filter by agent name
limitinteger50Max reports to return

Response

{
  "taskId": "c0ce8037",
  "count": 2,
  "reports": [
    {
      "id": "rpt12345",
      "taskId": "c0ce8037",
      "agentName": "verifier",
      "reportType": "html",
      "verdict": "PASS",
      "score": 95,
      "createdAt": "2026-03-10T10:00:00Z",
      "createdBy": "Alice"
    }
  ]
}

curl

curl "http://localhost:5050/api/tasks/c0ce8037/reports?agentName=verifier"
GET /api/tasks/{taskId}/reports/{reportId}

Get full report content by ID.

Response

{
  "id": "rpt12345",
  "task_id": "c0ce8037",
  "agent_name": "verifier",
  "report_type": "html",
  "report_content": "<h1>Verification Report</h1>...",
  "verdict": "PASS",
  "score": 95
}

curl

curl http://localhost:5050/api/tasks/c0ce8037/reports/rpt12345
POST /api/tasks/{taskId}/reports

Save a new agent report.

Request Body

{
  "agentName": "verifier",
  "reportContent": "<h1>Verification Report</h1><p>All checks passed.</p>",
  "reportType": "html",
  "verdict": "PASS",
  "score": 95,
  "invocationId": "inv-abc123",
  "createdBy": "Alice"
}

Response

{ "reportId": "rpt12345" }

curl

curl -X POST http://localhost:5050/api/tasks/c0ce8037/reports \
  -H "Content-Type: application/json" \
  -d '{"agentName":"verifier","reportContent":"...","verdict":"PASS","score":95,"createdBy":"Alice"}'

Agent Stats

Aggregated agent performance statistics and invocation tracking. Endpoints are under /api/agents.

GET /api/agents/stats

Get aggregated performance stats per agent (invocation counts, average scores, verdicts).

Response

[
  {
    "agentName": "verifier",
    "totalInvocations": 15,
    "avgScore": 87,
    "passCount": 12,
    "failCount": 3
  }
]

curl

curl http://localhost:5050/api/agents/stats
GET /api/agents/invocations

List recent agent invocations with optional filters.

Query Parameters

ParamTypeDefaultDescription
agentNamestring-Filter by agent name
taskIdstring-Filter by task
limitinteger50Max results (max 500)

Response

[
  {
    "id": "inv-abc123",
    "agentName": "verifier",
    "taskId": "c0ce8037",
    "invokedBy": "Alice",
    "modelUsed": "opus",
    "verdict": "PASS",
    "score": 95,
    "findingsCount": 0,
    "durationMs": 45000,
    "invokedAt": "2026-03-10T10:00:00Z",
    "completedAt": "2026-03-10T10:00:45Z"
  }
]

curl

curl "http://localhost:5050/api/agents/invocations?agentName=verifier&limit=20"
POST /api/agents/invocations

Record a new agent invocation.

Request Body

{
  "agentName": "verifier",
  "taskId": "c0ce8037",
  "invokedBy": "Alice",
  "modelUsed": "opus",
  "verdict": "PASS",
  "score": 95,
  "findingsCount": 0,
  "durationMs": 45000,
  "reportSummary": "All checks passed"
}

Response

{ "invocationId": "inv-abc123" }

curl

curl -X POST http://localhost:5050/api/agents/invocations \
  -H "Content-Type: application/json" \
  -d '{"agentName":"verifier","taskId":"c0ce8037","invokedBy":"Alice","verdict":"PASS","score":95}'

Notifications

Runtime notifications from Claude Code hooks. Stores events in the DB and forwards them to the in-process Multi-Connect gateway, which delivers Web Push (VAPID) notifications to your phone. Rate limited to 100/minute. Endpoints are under /api/notifications.

POST /api/notifications

Receive a Claude Code runtime notification. Stores in the DB, fires a broker event, and forwards to the in-process Multi-Connect gateway for Web Push delivery to the phone.

Request Body

{
  "notification_type": "task_complete",
  "title": "Task completed",
  "message": "Alice finished 'Add dark mode'",
  "session_id": "abc123",
  "agent_name": "Alice",
  "cwd": "H:\\DevLaptop\\ClarionPowerShell\\MultiTerminal"
}

Response

{ "id": "ntf12345" }

curl

curl -X POST http://localhost:5050/api/notifications \
  -H "Content-Type: application/json" \
  -d '{"notification_type":"task_complete","title":"Task completed","message":"Alice finished task"}'
GET /api/notifications

Query notification history.

Query Parameters

ParamTypeDefaultDescription
limitinteger50Max notifications (max 500)
unreadOnlybooleanfalseOnly return unread notifications

Response

[
  {
    "id": "ntf12345",
    "notificationType": "task_complete",
    "title": "Task completed",
    "message": "Alice finished 'Add dark mode'",
    "agentName": "Alice",
    "readAt": null,
    "createdAt": "2026-03-10T10:00:00Z"
  }
]

curl

curl "http://localhost:5050/api/notifications?unreadOnly=true&limit=20"
POST /api/notifications/{id}/read

Mark a notification as read.

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/notifications/ntf12345/read
GET /api/notifications/unread-count

Get count of unread notifications.

Response

{ "count": 5 }

curl

curl http://localhost:5050/api/notifications/unread-count

Owner Profile

Owner identity and git configuration. Used by agents for git operations. Endpoints are under /api/owner-profile.

GET /api/owner-profile

Get the owner profile (git identity, GitHub config).

Response

{
  "configured": true,
  "fullName": "Jane Smith",
  "email": "user@example.com",
  "gitHubUsername": "jhickey",
  "hasGitHubToken": true,
  "createdAt": "2026-02-01T10:00:00Z",
  "updatedAt": "2026-03-01T10:00:00Z"
}

curl

curl http://localhost:5050/api/owner-profile

Removed: GET /api/owner-profile/github-token returned the stored PAT ({ "token": "ghp_xxxx..." }) for agent use during git operations. Task ea7d9cf9 deleted it, together with GET /api/source-accounts/{id}/token and the token field of GET /api/projects/{projectId}/source-account. None of the three ever had a consumer, and each fetch wrote the credential into an agent's session transcript on disk. Use hasGitHubToken above to test for presence; to do authenticated work, have the service perform the operation and return its result rather than handing out the credential.

Companions

Status of configured companion processes (external services managed by MultiTerminal). Endpoints are under /api/companions.

GET /api/companions/status

Get the status of all configured companion processes.

Response

[
  {
    "name": "MCP Gateway",
    "status": "running",
    "pid": 12345
  }
]

curl

curl http://localhost:5050/api/companions/status

MCP Gateway

Query MCP Gateway server status and discovered tools. Reads from the gateway's SQLite database. Endpoints are under /api/gateway.

GET /api/gateway/servers

List all gateway backend servers with live connection status and tool counts.

Response

{
  "servers": [
    {
      "name": "sqlite",
      "connected": true,
      "enabled": true,
      "toolCount": 12
    }
  ],
  "summary": {
    "total": 5,
    "connected": 4,
    "enabled": 5,
    "totalTools": 45
  }
}

curl

curl http://localhost:5050/api/gateway/servers
GET /api/gateway/tools

List all discovered tools across all connected gateway backends. Filter by server or profile.

Query Parameters

ParamTypeDefaultDescription
serverstring-Filter by server name
profilestring-Filter by gateway profile

Response

{
  "profile": "(all)",
  "totalTools": 45,
  "serverBreakdown": [
    { "server": "sqlite", "toolCount": 12 }
  ],
  "tools": [
    {
      "serverName": "sqlite",
      "toolName": "query",
      "description": "Execute a SQL query"
    }
  ]
}

curl

curl "http://localhost:5050/api/gateway/tools?server=sqlite"
GET /api/gateway/tools/{server__toolname}

Get a specific tool's full schema by namespaced name (format: server__toolname).

Response

{
  "serverName": "sqlite",
  "toolName": "query",
  "description": "Execute a SQL query",
  "inputSchema": { ... }
}

curl

curl http://localhost:5050/api/gateway/tools/sqlite__query

Browser Tabs

Per-terminal tabbed browser (WebView2) management. All endpoints use POST with JSON bodies. Endpoints are under /api/browser-tabs.

POST /api/browser-tabs/open

Open a new browser tab in a terminal's HUD area.

Request Body

{
  "terminalId": "Alice",
  "title": "Dashboard",
  "url": "file:///H:/docs/index.html",
  "content": null
}

Response

{ "tabId": "tab-abc123" }

curl

curl -X POST http://localhost:5050/api/browser-tabs/open \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","title":"Dashboard","content":"<h1>Hello</h1>"}'
POST /api/browser-tabs/update

Update an existing browser tab's content, URL, or title.

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123",
  "title": "Updated Dashboard",
  "content": "<h1>Updated</h1>"
}

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/browser-tabs/update \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123","content":"<h1>Updated</h1>"}'
POST /api/browser-tabs/close

Close a browser tab.

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123"
}

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/browser-tabs/close \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123"}'
POST /api/browser-tabs/execute-script

Execute JavaScript in a browser tab and return the result.

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123",
  "script": "document.getElementById('status').textContent"
}

Response

{ "result": "Ready" }

curl

curl -X POST http://localhost:5050/api/browser-tabs/execute-script \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123","script":"document.title"}'
POST /api/browser-tabs/console-logs

Get console log messages from a browser tab.

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123",
  "limit": 10
}

Response

{ "logs": "[{\"level\":\"log\",\"message\":\"Hello\",\"timestamp\":\"...\"}]" }

curl

curl -X POST http://localhost:5050/api/browser-tabs/console-logs \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123","limit":10}'
POST /api/browser-tabs/element-content

Read the content of a DOM element by CSS selector.

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123",
  "selector": "#results",
  "property": "innerHTML"
}

Response

{ "content": "<p>Results here</p>" }

curl

curl -X POST http://localhost:5050/api/browser-tabs/element-content \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123","selector":"h1","property":"textContent"}'
POST /api/browser-tabs/capture-screenshot

Capture a PNG screenshot of a browser tab's content.

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123"
}

Response

{ "imageBase64": "iVBORw0KGgoAAAANSUhEUgAA..." }

curl

curl -X POST http://localhost:5050/api/browser-tabs/capture-screenshot \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123"}'
POST /api/browser-tabs/post-message

Send a JSON message to a browser tab's page (received via window.chrome.webview.addEventListener).

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123",
  "data": "{\"type\":\"update\",\"cpu\":47}"
}

Response

200 OK (empty body)

curl

curl -X POST http://localhost:5050/api/browser-tabs/post-message \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123","data":"{\"type\":\"update\"}"}'
POST /api/browser-tabs/get-messages

Get messages sent from a browser tab's page via window.chrome.webview.postMessage().

Request Body

{
  "terminalId": "Alice",
  "tabId": "tab-abc123",
  "limit": 20
}

Response

{ "messages": "[{\"data\":{\"type\":\"click\"},\"timestamp\":\"...\"}]" }

curl

curl -X POST http://localhost:5050/api/browser-tabs/get-messages \
  -H "Content-Type: application/json" \
  -d '{"terminalId":"Alice","tabId":"tab-abc123"}'

Terminal Streaming

WebSocket endpoint for real-time terminal I/O streaming. Binary frames carry raw VT/ANSI escape sequences; text frames carry JSON control messages.

GET /api/terminal/{id}/stream

WebSocket endpoint for streaming terminal I/O. Upgrades HTTP to WebSocket. Protocol: binary frames = raw terminal I/O, text frames = JSON control messages (resize, disconnect, status).

Note

This is a WebSocket endpoint. Use a WebSocket client, not curl.

// JavaScript example
const ws = new WebSocket("ws://localhost:5050/api/terminal/my-terminal/stream");
ws.binaryType = "arraybuffer";
ws.onmessage = (e) => { /* handle terminal output */ };
GET /api/terminal/streams

List active terminal streams with subscriber counts.

Response

{
  "streams": [
    { "terminalId": "Alice", "subscriberCount": 2 },
    { "terminalId": "Bob", "subscriberCount": 1 }
  ]
}

curl

curl http://localhost:5050/api/terminal/streams

XAML Preview

Render WPF XAML to PNG images for visual preview without launching the app. Endpoints are under /api/xaml.

POST /api/xaml/render

Render a WPF XAML snippet to a base64-encoded PNG image. Runs on an STA thread for WPF rendering.

Request Body

{
  "xaml": "<Border xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' Background='#1e1e2e' Padding='20'><TextBlock Text='Hello World' Foreground='White' FontSize='24'/></Border>",
  "width": 520,
  "height": 400
}
FieldTypeRequiredDefaultDescription
xamlstringYes-WPF XAML markup (must include xmlns)
widthintegerNo520Render width in pixels
heightintegerNo400Render height in pixels

Response

{
  "imageBase64": "iVBORw0KGgoAAAANSUhEUgAA...",
  "width": 520,
  "height": 400
}

curl

curl -X POST http://localhost:5050/api/xaml/render \
  -H "Content-Type: application/json" \
  -d '{"xaml":"<Border xmlns=...>...</Border>","width":520,"height":400}'

Code Graph

Query the Roslyn-built C# code graph (symbols and their relationships). Endpoints are under /api/code-graph. Registered C# projects are indexed automatically by the CodeGraphWatcher background service — it sweeps and refreshes stale graphs shortly after app startup and re-indexes on edit, so you normally don't index by hand. Read endpoints return 503 ProblemDetails (application/problem+json) with "detail":"CodeGraph not available" only before the project has been indexed (e.g. the brief window before the startup sweep completes, or for a directory that isn't a registered project). To index any directory immediately, use POST /api/code-graph/index (or the index_code_graph MCP tool). The callers, callees, impact, and inheritance endpoints accept either symbolId (preferred, from a search result) or symbolName.

GET /api/code-graph/search

Search symbols by name, with an optional type filter.

Query Parameters

ParamTypeRequiredDescription
querystringYesSymbol name to search for
typestringNoFilter by symbol type: class, method, interface, etc.

Response

{
  "count": 1,
  "results": [
    { "id": 42, "name": "MessageBroker", "type": "class", "filePath": "MCPServer/Services/MessageBroker.cs", "line": 35 }
  ]
}

curl

curl "http://localhost:5050/api/code-graph/search?query=MessageBroker&type=class"
GET /api/code-graph/callers

Get the direct callers of a symbol.

Query Parameters

ParamTypeRequiredDescription
symbolIdintegerNo*Symbol ID (from a search result)
symbolNamestringNo*Symbol name (resolved to an ID server-side)

* Supply symbolId or symbolName. Returns 404 if the symbol is not found.

Response

{
  "symbolId": 42,
  "count": 2,
  "results": [
    { "id": 88, "name": "SendMessage", "type": "method", "filePath": "...", "line": 410 }
  ]
}

curl

curl "http://localhost:5050/api/code-graph/callers?symbolId=42"
GET /api/code-graph/callees

Get the direct callees of a symbol (what it calls). Same parameters and response shape as callers.

curl

curl "http://localhost:5050/api/code-graph/callees?symbolName=SendMessage"
GET /api/code-graph/impact

Transitive impact analysis (blast radius) — everything that transitively depends on the symbol.

Query Parameters

ParamTypeRequiredDescription
symbolIdintegerNo*Symbol ID
symbolNamestringNo*Symbol name
maxDepthintegerNoMaximum traversal depth. Default: 10

* Supply symbolId or symbolName.

Response

{ "symbolId": 42, "count": 7, "results": [ ... ] }

curl

curl "http://localhost:5050/api/code-graph/impact?symbolId=42&maxDepth=5"
GET /api/code-graph/inheritance

Inheritance / implementation tree for a type. Same symbolId/symbolName parameters as callers.

Response

{ "symbolId": 42, "count": 3, "results": [ ... ] }

curl

curl "http://localhost:5050/api/code-graph/inheritance?symbolId=42"

Branch Metadata

Per-branch outcome labels (the one-line "what this branch delivers" shown on branch rows) and the task context an agent uses to draft them. Endpoints are under /api/branch-metadata/{projectId}. The project must be registered — unknown project IDs return 404 ProblemDetails with "detail":"unknown project". The branch name travels in the body (POST) or the branch query string (GET) rather than the URL path, so names containing / (the task/<id> convention) round-trip without route-escaping issues.

POST /api/branch-metadata/{projectId}/outcome

Upsert the outcome label for a branch.

Request Body

{
  "branchName": "task/9f9c3141",
  "outcome": "Allow agents to search past sessions by meaning",
  "draftedBy": "Alice"
}

Response

{
  "projectId": "proj-123",
  "branchName": "task/9f9c3141",
  "outcome": "Allow agents to search past sessions by meaning",
  "draftedBy": "Alice",
  "updatedAt": "2026-06-27T10:00:00Z"
}

curl

curl -X POST http://localhost:5050/api/branch-metadata/proj-123/outcome \
  -H "Content-Type: application/json" \
  -d '{"branchName":"task/9f9c3141","outcome":"Allow agents to search past sessions by meaning","draftedBy":"Alice"}'
GET /api/branch-metadata/{projectId}/draft-context

Get the task context an agent needs to draft an outcome for a branch (the agent does the rewrite; this only fetches context). Resolves the source task from originatingTaskId if supplied (must belong to the same project), otherwise from the most recent task linked to the branch.

Query Parameters

ParamTypeRequiredDescription
branchstringYesBranch name
originatingTaskIdstringNoExplicit source task ID (must belong to this project)

Response

{
  "projectId": "proj-123",
  "branchName": "task/9f9c3141",
  "sourceTaskId": "9f9c3141",
  "sourceTaskTitle": "Add semantic session search",
  "sourceTaskDescription": "...",
  "promptHint": "Rewrite the supplied task title + description as a one-sentence user-facing capability..."
}

curl

curl "http://localhost:5050/api/branch-metadata/proj-123/draft-context?branch=task/9f9c3141"
GET /api/branch-metadata/{projectId}/outcomes

Get all branch outcomes for a project.

Response

{
  "projectId": "proj-123",
  "outcomes": [
    {
      "branchName": "task/9f9c3141",
      "outcome": "Allow agents to search past sessions by meaning",
      "draftedBy": "Alice",
      "updatedAt": "2026-06-27T10:00:00Z"
    }
  ]
}

curl

curl http://localhost:5050/api/branch-metadata/proj-123/outcomes