Skip to main content
The ManticsCore WebSocket endpoint lets you subscribe to multiple entity channels over a single connection. Rather than opening a separate HTTP streaming request for each job, you connect once and subscribe to any mix of research runs, build graphs, Forge executions, chat sessions, and more.

Connecting

Pass your session token as a query parameter. You can also pass a Clerk JWT — the server auto-mints a session token for the lifetime of the connection.
ManticScore allows one WebSocket connection per user. Opening a new connection evicts the previous one with close code 4003. Make sure your client handles reconnection gracefully rather than opening multiple connections.
After a successful upgrade, the server immediately sends a connected frame:

Catchup frame

If you have any in-flight or recently completed work, the server sends a catchup frame right after connected. This lets you know what to subscribe to without polling the REST API first.
Use in_flight[].last_event_seq as your cursor when subscribing, so you don’t re-receive events you already have.

Client messages

Send JSON text frames to control your subscriptions:
Subscribe to a channel for a specific entity. The server replays events after cursor, sends a subscribed confirmation, then streams live events.
Pass the seq of the last event you received as cursor to resume without gaps.
Stop receiving events for an entity. The server auto-unsubscribes when it forwards a done event, but you can also unsubscribe manually.
Send a client-side keepalive. The server replies with a pong frame.

Server messages

Entity events carry the same payloads as their HTTP NDJSON counterparts. See NDJSON streaming protocol for event shapes.

Auto-progression events

Several entity events are emitted by background hooks rather than direct user action. They follow the same envelope as any other entity event but are worth calling out so clients know to render them: Clients must ignore unknown event types so older builds remain forward-compatible — additional auto-progression events may be added without a version bump.

Available channels

The project channel does not have terminal statuses — it stays open as long as the project exists and fans in events from every per-domain channel that carries a project_id. Subscribe with entity_id set to the project UUID. Use GET /projects/:id/home to bootstrap the screen, then pass the returned ws.last_event_seq as cursor to resume without gaps. Per-domain channels remain available for clients that only need a single domain’s events.
The cards channel is per-user, not per-entity. Subscribe with entity_id set to the authenticated user’s Clerk id (not a UUID). The server does not replay events on subscribe — use GET /v1/cards for cold-launch and reconnect catch-up, then subscribe to receive only live cards going forward. The subscribed confirmation always reports replayed: 0 for this channel.

Connection lifecycle

  • Idle timeout: 90 seconds. Keep the connection alive by sending ping frames or subscribing to active channels.
  • Server heartbeat: the server sends a ping frame every 30 seconds.
  • Auth revalidation: your session is re-checked every 5 minutes. If it has expired, you receive an auth_expired frame followed by close code 4001. Re-authenticate and reconnect.

Close codes

JavaScript example

This example connects, handles the catchup frame, subscribes to a research job, and processes incoming events:
If you use the WebSocket for long sessions, set up a client-side ping interval (every 60s or so) to prevent the 90-second idle timeout from closing your connection.