HTTP API and WebSocket
The Domscribe relay server exposes a REST API for annotation management and manifest queries, plus a WebSocket server for real-time events. The relay runs on localhost and is accessed by both the browser overlay and coding agents.
The default base URL is http://127.0.0.1:<port>/api where the port is dynamically assigned (or configured via the relay.port option).
HTTP API Routes
Health and Status
GET /api/health
Health check endpoint. Returns 200 if the relay is running.
GET /api/status
Returns relay status including manifest statistics and annotation queue counts.
Response:
{
"status": "ok",
"uptime": 3600,
"manifest": {
"entryCount": 142,
"fileCount": 28,
"componentCount": 35
},
"annotations": {
"queued": 2,
"processing": 1,
"processed": 5,
"failed": 0,
"archived": 3
},
"browserConnected": true
}
Annotations
POST /api/annotations
Create a new annotation. Typically called by the browser overlay when a user clicks an element and submits a description.
Request body:
{
"interaction": {
"mode": "ELEMENT_CLICK",
"elementId": "A1B2C3D4",
"selector": "main > div > button",
"boundingRect": { "x": 100, "y": 200, "width": 80, "height": 32 }
},
"context": {
"url": "http://localhost:3000/dashboard",
"viewport": { "width": 1920, "height": 1080 },
"userAgent": "Mozilla/5.0 ...",
"manifestSnapshot": { "..." },
"runtimeContext": { "..." }
},
"message": "Make this button use the primary color"
}
Response: The created annotation object with status QUEUED.
GET /api/annotations/:id
Get a single annotation by ID.
Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Annotation ID (ann_* format) |
PATCH /api/annotations/:id
Update an annotation. Used by agents to claim (atomically transition from QUEUED to PROCESSING).
Request body:
{
"status": "PROCESSING"
}
GET /api/annotations
List annotations with optional filters.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: QUEUED, PROCESSING, PROCESSED, FAILED, ARCHIVED |
DELETE /api/annotations/:id
Delete an annotation by ID.
PATCH /api/annotations/:id/respond
Attach the agent's response to an annotation and transition it to PROCESSED.
Request body:
{
"response": "Updated the button to use the primary color from the design system tokens."
}
PATCH /api/annotations/:id/status
Manually update an annotation's status.
Request body:
{
"status": "ARCHIVED"
}
POST /api/annotations/search
Full-text search across annotation content.
Request body:
{
"query": "button color"
}
Manifest
GET /api/manifest
Query manifest entries by file path, component name, or element ID.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
file | string | Filter by file path |
componentName | string | Filter by component name |
id | string | Look up a specific entry ID |
GET /api/manifest/:id
Resolve a single manifest entry by its data-ds ID.
POST /api/v1/manifest/resolve-by-source
Query the manifest by source file and line number, optionally including live runtime context from the browser.
Request body:
{
"file": "src/components/Button.tsx",
"line": 12,
"column": 4,
"tolerance": 0,
"includeRuntime": true
}
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
file | string | Yes | -- | Absolute file path as stored in the manifest |
line | number | Yes | -- | Line number (1-indexed) |
column | number | No | -- | Column number (0-indexed) |
tolerance | number | No | 0 | Max line distance to consider a match |
includeRuntime | boolean | No | true | Query live runtime context via WebSocket |
Response:
{
"found": true,
"entryId": "A1B2C3D4",
"sourceLocation": {
"file": "src/components/Button.tsx",
"start": { "line": 12, "column": 4 },
"end": { "line": 12, "column": 42 },
"tagName": "button",
"componentName": "Button"
},
"runtime": {
"rendered": true,
"componentProps": { "variant": "secondary", "onClick": "[Function]" },
"componentState": { "hook_0": false, "hook_1": "idle" },
"domSnapshot": {
"tagName": "button",
"attributes": { "class": "btn-secondary", "type": "submit" },
"innerText": "Save changes"
}
},
"browserConnected": true
}
When includeRuntime is true and a browser is connected via WebSocket, the relay sends a CONTEXT_REQUEST to the overlay client and includes the live runtime context in the response.
WebSocket Events
Connect to the WebSocket at /api/ws for real-time event streaming.
Connection Lifecycle
| Event | Direction | Description |
|---|---|---|
CONNECT | Client to Server | Initial connection request |
CONNECTED | Server to Client | Connection established |
DISCONNECTED | Server to Client | Connection closed |
ERROR | Server to Client | Connection error |
Annotation Events
| Event | Direction | Payload | Description |
|---|---|---|---|
ANNOTATION_CREATED | Server to Client | Annotation | A new annotation was created |
ANNOTATION_UPDATED | Server to Client | Annotation | An annotation's status or response changed |
These events are broadcast to all connected clients. The overlay uses them to update annotation status in real time -- for example, showing the agent's response as soon as it is submitted.
Manifest Events
| Event | Direction | Payload | Description |
|---|---|---|---|
MANIFEST_UPDATED | Server to Client | { entryCount } | The manifest file changed on disk |
Context Query Events
| Event | Direction | Description |
|---|---|---|
CONTEXT_REQUEST | Server to Client | Relay asks the browser for live runtime context |
CONTEXT_RESPONSE | Client to Server | Browser responds with captured props, state, and DOM |
These events power the domscribe.query.bySource MCP tool. When an agent queries a source location, the relay forwards a CONTEXT_REQUEST to the connected browser overlay. The overlay queries the runtime adapter (React fiber or Vue VNode) and sends the captured context back as a CONTEXT_RESPONSE.
WebSocket Message Format
{
"type": "ANNOTATION_CREATED",
"payload": { "..." },
"timestamp": "2026-03-15T10:30:00.000Z"
}
Clients can subscribe to specific events:
{
"type": "subscribe",
"events": ["ANNOTATION_CREATED", "ANNOTATION_UPDATED", "MANIFEST_UPDATED"]
}