# SOP: Broadcast System ## Purpose Send system-wide announcements to agents and users. Broadcasts are priority-tagged messages at `/api/broadcasts` that agents can poll for unread items, making them useful for coordinating fleet-wide changes, urgent alerts, and informational updates without requiring individual notifications. ## Prerequisites - Veritas Kanban server running - API access (localhost:3001 by default) - Agent name for unread tracking (optional but recommended) ## Concepts | Term | Definition | | ---------------------- | ------------------------------------------------------------------------------------------------ | | **Broadcast** | A durable system-wide message with a priority level, optional sender, and optional tags | | **Priority** | `info` (default), `action-required`, or `urgent` | | **Read tracking** | Each agent marks broadcasts read independently — unread state is per-agent | | **WebSocket delivery** | New broadcasts are pushed via WebSocket in real-time; polling is available as fallback | | **Notification** | Recipient-specific task/system event at `/api/notifications`; separate from durable broadcasts | | **Squad Chat** | Local conversation log at `/api/chat/squad`; separate from broadcasts and external wake behavior | ## Step-by-Step: Send a Broadcast ### Standard info broadcast ```bash curl -s -X POST http://localhost:3001/api/broadcasts \ -H 'Content-Type: application/json' \ -d '{ "message": "Deployment complete: VK 4.0.0 is now running. All agents should reload their task context.", "priority": "info", "from": "VERITAS", "tags": ["release"] }' ``` → Returns `201` with the broadcast record including its `id`. The WebSocket event fires immediately — all connected clients receive it. ### Urgent broadcast requiring agent action ```bash curl -s -X POST http://localhost:3001/api/broadcasts \ -H 'Content-Type: application/json' \ -d '{ "message": "API quota exhausted for OpenAI. All agents: pause LLM calls until further notice.", "priority": "urgent", "from": "VERITAS", "tags": ["incident", "openai"] }' ``` ## Step-by-Step: Read and Acknowledge Broadcasts ### List all recent broadcasts (any priority) ```bash curl -s "http://localhost:3001/api/broadcasts?limit=10" ``` ### List unread broadcasts for a specific agent ```bash curl -s "http://localhost:3001/api/broadcasts?agent=TARS&unread=true" ``` > **Note:** `unread=true` requires the `agent` parameter. Omitting `agent` with `unread=true` returns a 400 error. ### Mark a broadcast as read ```bash curl -s -X PATCH http://localhost:3001/api/broadcasts/bcast_abc123/read \ -H 'Content-Type: application/json' \ -d '{ "agent": "TARS" }' ``` → Returns `{ "success": true }`. ### Get a single broadcast by ID ```bash curl -s "http://localhost:3001/api/broadcasts/bcast_abc123" ``` ## Step-by-Step: Agent Broadcast Polling Integrate into an agent's startup or polling loop: ```typescript // On agent startup or heartbeat cycle async function checkBroadcasts(agentName: string): Promise { const response = await fetch(`${VK_API_URL}/api/broadcasts?agent=${agentName}&unread=true`); const broadcasts = await response.json(); for (const broadcast of broadcasts) { console.log(`[BROADCAST] [${broadcast.priority.toUpperCase()}] ${broadcast.message}`); // Handle action-required or urgent broadcasts if (broadcast.priority === 'urgent') { await pauseCurrentWork(); // surface to operator / human } // Mark as read await fetch(`${VK_API_URL}/api/broadcasts/${broadcast.id}/read`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agent: agentName }), }); } } ``` ## Step-by-Step: Filter Broadcasts ### By priority ```bash # Only urgent broadcasts curl -s "http://localhost:3001/api/broadcasts?priority=urgent" # Action-required only curl -s "http://localhost:3001/api/broadcasts?priority=action-required" ``` ### Since a timestamp ```bash # Broadcasts in the last hour curl -s "http://localhost:3001/api/broadcasts?since=2026-03-21T13:00:00Z" ``` ### Combined filters ```bash # Unread urgent broadcasts for TARS since noon curl -s "http://localhost:3001/api/broadcasts?agent=TARS&unread=true&priority=urgent&since=2026-03-21T12:00:00Z" ``` ## Priority Guide | Priority | When to use | Agent response | | ----------------- | --------------------------------------------------------------------------- | -------------------------------- | | `info` | Routine announcements (deployments, completions, status updates) | Acknowledge when convenient | | `action-required` | Something needs attention but isn't critical (config change, review needed) | Address before starting new work | | `urgent` | Immediate action required (quota exhausted, production incident, failure) | Stop current work and respond | ## API Endpoints Used | Method | Path | Purpose | | ------- | -------------------------- | ---------------------- | | `POST` | `/api/broadcasts` | Send a broadcast | | `GET` | `/api/broadcasts` | List broadcasts | | `GET` | `/api/broadcasts/:id` | Get a single broadcast | | `PATCH` | `/api/broadcasts/:id/read` | Mark read for an agent | ## Common Issues / Troubleshooting | Issue | Cause | Fix | | ------------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `400` on `unread=true` | Missing `agent` param | Add `?agent=` to the query | | `400` on create | Payload uses stale fields or invalid priority | Use `message`, optional `priority`, optional `from`, and optional `tags`; priorities are `info`, `action-required`, `urgent` | | Broadcast not appearing real-time | Agent isn't connected via WebSocket | Check WebSocket connection; fall back to polling | | Broadcast created but no agent wakes | Broadcasts are durable messages, not wake/reply commands | Use Squad Chat Webhook or OpenClaw Direct for external wake behavior | | Agent sees same broadcasts repeatedly | Not calling the `/read` endpoint after processing | Always mark broadcasts read after handling them | | Old broadcasts cluttering the list | No TTL/expiry in v4.0 | Use `?since=` to filter by recency | ## Related Docs - [docs/features/broadcasts.md](features/broadcasts.md) — Feature deep-dive - [SOP-agent-task-workflow.md](SOP-agent-task-workflow.md) — How broadcasts fit into the agent task lifecycle - [SOP-lifecycle-hooks.md](SOP-lifecycle-hooks.md) — Hooks can trigger broadcasts on task events