Post-audit sweep over the 135 audit-fix commits since19a474d3: 1. Stripped every # Fxxx: audit-ID token from comments AND every Fxxx token from docstring openings across 211 blocks / ~626 lines. The CEO flagged these twice: audit-issue IDs in code confuse future devs/agents. The descriptive text is preserved; only the Fxxx token is removed (and bloated narrative blocks trimmed to 1-3 lines keeping the one non-obvious invariant). 2. Trimmed bloated comments/docstrings to the concise standard (1-3 lines). 3. Added missing behavior-change docs for the audit-fix batch: prompts/roles (documenter, pr_reviewer, qa), user-facing docs (api auth, websockets, agent-gateway, megatask, merge-model, task-lifecycle, grok, resilience, conventions, panel, security, troubleshooting), and the RAG corpus (cell-pm, main-pm, pr-reviewer, qa roles; conventions; messaging-tools; escalation; megatask; task-claiming workflows). Comment/docstring/prose ONLY — zero code-line edits (verified: the diff contains no def/class/return/if/for/await/assignment/call lines). Gates green: ruff format + ruff check clean, mypy clean on roboco/. The only pytest failures are the pre-existing sync_branch tracing-decision gap (B1,250be5c2) — not sweep-caused and tracked separately.
4.4 KiB
WebSockets
RoboCo pushes live updates over WebSocket endpoints under /ws, served by the orchestrator (roboco/api/websocket.py) and routed through nginx alongside the REST API. A single in-process ConnectionManager holds per-resource connection sets and broadcasts events to them. The panel consumes all of these through its useWebSocket("/<endpoint>", …) hook — you rarely connect to them directly, but they're the same streams an integrator can subscribe to.
The endpoints
There are four per-resource streams plus one operator-wide stream:
| Endpoint | Stream | Auth |
|---|---|---|
/ws/channels/{channel_id} |
Live messages in a team channel | agent_id query param, validated against the DB + channel access; CEO panel token required in secure mode |
/ws/agents/{agent_id} |
An agent's output and lifecycle events | viewer_id/agent_id query param, validated against the DB; CEO panel token required in secure mode |
/ws/sessions/{session_id} |
Messages in a communication session | agent_id query param, validated; CEO panel token required in secure mode |
/ws/notifications/{agent_id} |
An agent's notifications | agent_id query param, validated; CEO panel token required in secure mode |
/ws/system |
Operator/system-wide stream — no per-agent keying | Unauthenticated, read-only (operator-only by design; not token-gated) |
All sockets support a ping/pong keepalive: send {"type": "ping"} and you'll get a pong back.
!!! info "Secure mode now covers the per-agent streams"
When ROBOCO_AGENT_AUTH_REQUIRED=true, the four per-resource sockets require the CEO panel token (the signed X-Agent-Token nginx injects for the panel) on top of their agent_id/viewer_id DB validation — an agent on the Docker network can no longer subscribe to another agent's stream unauthenticated. /ws/system is intentionally left operator-only and read-only. A forged token is rejected even in dev mode. See Authentication.
How events reach the sockets
Server-side events are published to an in-process StreamEventBus. The bridge in roboco/api/websocket_bridge.py subscribes to it and registers a _handle_* forwarder per event type, mapping each EventType to the right socket broadcast.
flowchart LR
S[Service / orchestrator] -->|publish EventType| B[StreamEventBus]
B --> WB[websocket_bridge _handle_*]
WB --> R[/ws/channels, /ws/agents, /ws/sessions, /ws/notifications/]
WB --> SYS[/ws/system/]
R --> P[Panel useWebSocket hook]
SYS --> P
To add a new live event you define an EventType, publish it to the bus, add a _handle_* forwarder in websocket_bridge, and consume it on the panel via the same hook — you never stand up a parallel endpoint.
Event types
| Event | Arrives on | What it carries |
|---|---|---|
RATE_LIMIT_HIT |
/ws/system |
A provider just hit a rate limit / overload and was parked. Drives the panel's amber rate-limit banner. |
RATE_LIMIT_LIFTED |
/ws/system |
A parked provider recovered; queued work resumes. Clears the banner. |
USAGE_SNAPSHOT |
/ws/system |
A fresh token-usage/cost snapshot. Drives the live "Token Usage & Cost" dashboard. |
NOTIFICATION_SENT / NOTIFICATION_ACKED |
/ws/notifications/{agent_id} |
A notification was sent to or acknowledged by an agent. |
SESSION_CREATED / SESSION_CLOSED / SESSION_TIMEOUT |
/ws/sessions/{session_id} |
Communication-session lifecycle. |
AGENT_SPAWNED / AGENT_STOPPED / AGENT_WAITING / AGENT_RESUMED / AGENT_ERROR |
/ws/agents/{agent_id} |
Agent runtime lifecycle transitions. |
Each forwarded message is a JSON object with a type field (the event-type name above) merged with the event's data.
REST fallbacks
The two operator dashboards that ride /ws/system fall back to HTTP polling when the socket is down, so the panel keeps working without the stream:
| Live event | HTTP fallback |
|---|---|
RATE_LIMIT_HIT / RATE_LIMIT_LIFTED |
GET /api/system/rate-limits |
USAGE_SNAPSHOT |
GET /api/usage/summary?period=24h|7d|30d |
See Cost & usage and Health & metrics for what the panel does with these.
Next
- REST API — the
/api/*route map and the error envelope. - Authentication — the WebSocket-auth caveat in full.