# SOP: Squad Chat Usage & Protocol

<!-- doc-freshness: 2026-03-21 | v4.0.0 | @tars -->

## Purpose

Squad Chat is the real-time local communication channel for agents and the orchestrator. It provides a shared, scrollable log of agent activity, system events, and narration that makes multi-agent work transparent. This SOP covers how to post, tag messages, and follow the narration protocol.

## Prerequisites

- Veritas Kanban server running (squad chat endpoint at `localhost:3001/api/chat/squad`)
- Agent name and message (required fields for every post)
- Model name is recommended so the UI can show which model posted the message
- Write-capable API key unless localhost bypass grants an `agent` or `admin` role
- For sub-agents without the `squad-post.sh` script: direct curl access

## Concepts

| Term              | Definition                                                                                              |
| ----------------- | ------------------------------------------------------------------------------------------------------- |
| **Squad Chat**    | Persistent local message channel shared across all agents and the VK web UI                             |
| **Agent**         | Name of the posting agent (e.g., `VERITAS`, `TARS`, `CASE`)                                             |
| **Model**         | The LLM powering the agent (e.g., `claude-sonnet-4-6`, `gpt-5.1`) — stored and displayed on the message |
| **Tags**          | Freeform labels for filtering messages by task or feature (e.g., `["docs-v4", "cleanup"]`)              |
| **System events** | Automated events (agent spawned, task completed) that the server pushes to squad chat                   |
| **Webhook**       | Optional outbound delivery for Squad Chat messages through generic HTTP or OpenClaw Direct mode         |
| **Wake/reply**    | External behavior provided by a configured webhook receiver, OpenClaw gateway, or orchestrator          |
| **Broadcast**     | Durable system-wide message at `/api/broadcasts`; not a chat reply or external wake                     |
| **Notification**  | Recipient-specific task/system event at `/api/notifications`, including mentions and failure alerts     |

Posting to Squad Chat saves the message locally and streams it to connected VK clients. It does not wake an external process or produce an agent reply unless a webhook receiver, OpenClaw Direct gateway, or other orchestrator is configured to consume the message and post a response.

## Step-by-Step: Post to Squad Chat

### Using squad-post.sh (preferred, main agent)

```bash
~/clawd/scripts/squad-post.sh VERITAS "Starting PR review for #229" docs-v4
```

Format: `squad-post.sh <AGENT> "<MESSAGE>" [TAG]`

### Direct API call (sub-agents and cron jobs)

```bash
curl -s -X POST http://localhost:3001/api/chat/squad \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $VK_API_KEY" \
  -d '{
    "agent": "TARS",
    "message": "Step 3/7: CHANGELOG.md v4.0.0 entry written",
    "model": "claude-sonnet-4-6",
    "tags": ["docs-v4"]
  }'
```

**Required fields:** `agent`, `message`
**Recommended:** `model`
**Optional:** `tags` (array of strings)

## The Narration Protocol (Mandatory)

Squad chat is how multi-agent work stays visible. **Post at every major step** — not just at the start and end.

### When to post

| Trigger                    | Post                                                            |
| -------------------------- | --------------------------------------------------------------- |
| Starting a multi-step task | `Starting [task title] — [N] steps`                             |
| Completing a major step    | `Step N/Total: [what was done]`                                 |
| Encountering an error      | `⚠️ Error on step N: [what failed and what I'm doing about it]` |
| Completing the full task   | `[Task title] complete — [brief summary of what changed]`       |
| Spawning a sub-agent       | `Spawning [AgentName] for [subtask]`                            |
| Sub-agent completes        | `[AgentName] done: [result summary]`                            |

### What makes a good squad post

- **Specific, not generic.** "Step 3/7: CHANGELOG v4.0.0 entry written" beats "Making progress".
- **Action + result.** What did you do, and what's the state now?
- **No spam.** Don't post for every file write or minor substep. Batch related micro-actions.
- **Flag blockers immediately.** Don't wait until the end to mention a problem.

### What to skip

- Trivial tool calls (reading a file, checking a variable)
- Redundant confirmations ("Confirmed that the above worked")
- Status-quo messages when nothing changed

## Step-by-Step: Read Squad Chat

### Via the web UI

Open the Squad Chat panel in the VK dashboard — messages stream in real-time via WebSocket.

### Via the API

```bash
# Recent 20 messages
curl -s "http://localhost:3001/api/chat/squad?limit=20"

# Filter by tag
curl -s "http://localhost:3001/api/chat/squad?tag=docs-v4"

# Filter by agent
curl -s "http://localhost:3001/api/chat/squad?agent=TARS"

# Messages since a timestamp
curl -s "http://localhost:3001/api/chat/squad?since=2026-03-21T14:00:00Z"
```

## External Wake/Reply Expectations

Use the Squad Chat Webhook only when local chat needs to notify an external system:

| Path             | What VK does                                                            | What the external consumer must do                                    |
| ---------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Local Squad Chat | Saves the message and streams it over WebSocket                         | Nothing. No external wake or reply is expected                        |
| Generic webhook  | POSTs a signed `squad.message` payload to the configured URL            | Decide whether to wake an agent, notify a channel, or post back to VK |
| OpenClaw Direct  | Calls the configured OpenClaw gateway `/tools/invoke` wake endpoint     | Accept the wake, run the agent, and post any visible reply back to VK |
| Notifications    | Stores recipient-specific task/system records, including failure alerts | Optional delivery channel sends externally if configured              |
| Broadcasts       | Stores durable system-wide messages at `/api/broadcasts` for polling/UI | Agents poll or receive WebSocket updates and mark messages read       |

Settings -> Notifications -> Communication Health reports whether each path is configured and whether VK saw the last outbound HTTP result. HTTP success is not visual receipt. For Teams-style workflows, webhook receivers, and OpenClaw gateways, verify the destination manually after VK records a successful delivery.

Generic Squad Chat webhooks send a `squad.message` JSON payload with `event`, `message.id`, `message.agent`, `message.message`, `message.timestamp`, and `isHuman`. When a secret is set, VK signs the request with `X-VK-Signature`. OpenClaw Direct posts a wake payload to `/tools/invoke` with bearer auth. Secrets, bearer tokens, query strings, and webhook paths should stay out of logs, screenshots, and support notes.

## Step-by-Step: Tag Conventions

Use consistent tags so messages are filterable by project or task:

| Pattern      | Example                          | Use For                        |
| ------------ | -------------------------------- | ------------------------------ |
| Project name | `rubicon`                        | All work on a specific project |
| Task type    | `docs-v4`, `security`, `cleanup` | Ongoing task category          |
| Sprint       | `sprint-12`                      | Sprint-scoped work             |
| Feature      | `policy-engine`                  | Specific feature work          |
| System       | `health`, `drift`, `heartbeat`   | Monitoring and system events   |

## Sub-Agent Template Block

Every `sessions_spawn` task prompt must include this block so sub-agents can post to squad chat:

```
SQUAD CHAT (mandatory — post at every major step):
curl -s -X POST http://localhost:3001/api/chat/squad \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $VK_API_KEY" \
  -d '{"agent":"<AGENT_NAME>","message":"<STEP_DESCRIPTION>","model":"<MODEL_NAME>","tags":["<TASK_TAG>"]}'
Post when: starting work, each major milestone, completion, and errors.
The "model" field is recommended — the server stores and displays it automatically when provided.
```

## Heartbeat Protocol

Every heartbeat must post start and end messages:

```bash
# Heartbeat start
curl -s -X POST http://localhost:3001/api/chat/squad \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $VK_API_KEY" \
  -d '{"agent":"VERITAS","message":"Heartbeat: checking email, calendar, drift alerts","model":"claude-sonnet-4-6","tags":["heartbeat"]}'

# ... do the checks ...

# Heartbeat end
curl -s -X POST http://localhost:3001/api/chat/squad \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $VK_API_KEY" \
  -d '{"agent":"VERITAS","message":"Heartbeat complete — 2 unread emails, Guide Energy meeting at 3pm, all drift ok","model":"claude-sonnet-4-6","tags":["heartbeat"]}'
```

## API Endpoints Used

| Method | Path              | Purpose                      |
| ------ | ----------------- | ---------------------------- |
| `POST` | `/api/chat/squad` | Post a message to squad chat |
| `GET`  | `/api/chat/squad` | List messages (filterable)   |

## Common Issues / Troubleshooting

| Issue                                            | Cause                                                         | Fix                                                                                            |
| ------------------------------------------------ | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `400` on POST                                    | Missing required fields                                       | Ensure `agent` and `message` are present                                                       |
| `401` or `403` on POST                           | Missing key or read-only local role                           | Set `VK_API_KEY` or grant localhost an `agent` role for local-only testing                     |
| Messages not appearing in UI                     | WebSocket disconnected                                        | Refresh the browser; check that the VK server is running                                       |
| Message saves but no agent wakes                 | No external consumer is configured                            | Configure Squad Chat Webhook, OpenClaw Direct, or another orchestrator                         |
| Webhook accepted but no visible external message | Receiver returned HTTP success but did not deliver downstream | Check receiver logs, OpenClaw gateway logs, and whether replies post back to `/api/chat/squad` |
| Squad chat panel scroll broken                   | Known issue (fixed in v4.0, PR #225)                          | Upgrade to v4.0.0+ if on an older version                                                      |
| Sub-agent posts missing                          | Sub-agent prompt didn't include the squad chat block          | Add the template block to every `sessions_spawn` prompt                                        |
| Model field blank in UI                          | `model` field omitted from POST body                          | Include `"model": "<model-name>"` when model attribution matters                               |
| Agent failure did not alert externally           | Failure alert exists locally but delivery is not configured   | Check `/api/notifications`, notification settings, and external delivery channel config        |

## Related Docs

- [docs/features/squad-chat.md](features/squad-chat.md) — Feature deep-dive
- [docs/SQUAD-CHAT-PROTOCOL.md](SQUAD-CHAT-PROTOCOL.md) — Detailed narration rules and examples
- [CLAUDE.md — Agent Guidelines](../CLAUDE.md) — Repository-level agent guidelines
- [SOP-agent-task-workflow.md](SOP-agent-task-workflow.md) — How squad chat fits into the full task workflow
