# Quest Coordination

> How agents communicate, route messages, and share context.

Quest coordination handles how messages flow between you, agents, and the system during a quest. This page covers the messaging protocol, delivery order, @mention routing, and the underlying file format.

## Sequential Delivery

When you send a message to the party, Quest does not blast it to all agents simultaneously. Instead, it delivers the message one agent at a time in priority order:

1. The first agent in the party receives the message
2. Crystl monitors that agent's hook activity to detect when it stops working
3. Once the agent finishes, the next agent in the party receives the message
4. This continues through all agents

### Why Sequential

Simultaneous delivery causes problems:

- Agents make the same change independently, creating conflicts
- Agents don't see each other's responses, leading to duplicated work
- In open mode, agents overwrite each other's file edits

Sequential delivery ensures each agent sees the responses from agents before it. The second agent knows what the first agent did. The third agent knows what both previous agents did. This produces coordinated work without explicit synchronization.

### Priority Order

Agents receive messages in the order they appear in the party template. When creating a custom template, put the agent whose work others depend on first. For example, a planner or architect should go before implementers.

## The quest_msg Protocol

Agents communicate with each other and with you using the `quest_msg` shell function. Crystl automatically adds this function to each agent's PATH when a quest starts.

### Syntax

```bash
quest_msg "target" "message"
```

The first argument is the target — a hero name, `you`, or `all`. The second argument is the message text.

### Examples

```bash
# Send a message to the human user
quest_msg "you" "Found a bug in the auth flow — need your input"

# Send a message to a specific agent
quest_msg "ranger" "Can you handle the CSS for this component?"

# Broadcast a status update to the party
quest_msg "all" "Status update: API endpoints are live"
```

### How It Works

When an agent calls `quest_msg`, the function:

1. Constructs a JSON message object with the sender, target, text, and timestamp
2. Appends it to `.crystl/quest/messages.jsonl`
3. Crystl's file watcher detects the change and routes the message to the appropriate chat channel
4. If the target is a specific agent, the message appears in the DM channel
5. If the target is `you`, a floating notification appears for the human user
6. If the target is `all`, the message appears in #quest but is **not** injected into agent terminals (preventing feedback loops)

## Coordination Verbs

Beyond `quest_msg`, agents have five verbs for managing async work. These are bash shell commands — always run them via the Bash tool.

### quest_heartbeat

```bash
quest_heartbeat "<what you're working on>" [--status ready|working|blocked]
```

Call at the start of every task so the team dashboard reflects your current status. Required before beginning any new piece of work.

### quest_task

```bash
quest_task <shard> '<task title>' [--priority high|normal|low]
```

Delegate work to another shard. Always create a task record with this verb — never delegate via `quest_msg` alone. Returns a `task_id` needed for `quest_summary` and `quest_handoff`.

### quest_summary

```bash
quest_summary --task-id <id> '<short digest>'
```

Call when you finish a task or reach a significant milestone. Appends to `v2/summaries.jsonl` so the whole team can track progress without re-reading the full chat. Only the task's assignee should call this.

### quest_handoff

```bash
quest_handoff --task <id> [--to <shard>] [--decision "..."] [--blocker "..."] [--next "..."]
```

Transfer a task to another shard — use when your context drops below ~20%, you're blocked, or the work needs a different specialty. Omit `--to` for an open handoff that the healer or user can assign.

### quest_announce

```bash
quest_announce '<message>'
```

Broadcast to every shard at once. Use for shared decisions — port assignments, API shape, design tokens — anything the whole team needs to align on simultaneously.

## @Mention Routing

Messages with @mentions are routed based on the target:

### @name (Direct Message)

```
@wizard Can you review the layout I just pushed?
```

Routes the message to Wizard only. The message appears in:

- The #quest channel (visible to everyone)
- The Wizard DM channel (for easy reference)
- Wizard's terminal as an injected prompt

### @you / @me (Human Notification)

```
quest_msg "you" "The migration is ready for review"
```

When an agent sends a message targeting `you` or `me`, Crystl triggers a floating notification panel so the human user sees it immediately, even if the quest panel is closed.

### @all (Broadcast)

```
quest_msg "all" "All endpoints are tested and passing"
```

Appears in the #quest channel for everyone to see. Crucially, @all messages are **not injected into agent terminals**. This prevents a loop where agents react to broadcasts by sending more broadcasts.

## Message File Format

Quest messages are stored in `.crystl/quest/messages.jsonl` — one JSON object per line (JSONL format).

### Message Schema

```json
{
  "id": "uuid-v4",
  "sender": "wizard",
  "text": "I'll start with the header component",
  "ts": 1712419200,
  "target": "all"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | UUID v4 unique identifier |
| `sender` | string | Hero name of the sender, or your quest username |
| `text` | string | The message content |
| `ts` | number | Unix timestamp (seconds) |
| `target` | string | `"all"`, `"you"`, or a specific hero name |

### Reading the Log

You can inspect the raw message log at any time:

```bash
cat .crystl/quest/messages.jsonl
```

Each line is a self-contained JSON object. Tools like `jq` work well for filtering:

```bash
# All messages from wizard
cat .crystl/quest/messages.jsonl | jq 'select(.sender == "wizard")'

# All DMs to you
cat .crystl/quest/messages.jsonl | jq 'select(.target == "you")'
```

## Status Tracking

Agent status is tracked in `.crystl/quest/status.json`. This file contains the current state of each agent in the party:

- **Name and role** — The hero identity
- **Context health** — Percentage of token budget remaining
- **Status** — ready, working, or idle
- **Last activity** — Timestamp of the last detected hook event

The [Healer](/docs/quest-heroes) reads this file to monitor team health and trigger context recovery when an agent drops below 50%.

## Healer Recovery Flow

When the Healer detects low context health on any agent:

1. Reads `.crystl/quest/messages.jsonl` and writes a compressed summary to `QUEST-LOG.md`
2. Writes `HANDOFF.md` for agents approaching their token limit — a concise briefing so a fresh session can continue the work
3. Updates `DECISIONS.md` with choices that have been settled, preventing re-discussion
4. Rewrites bloated files to save tokens where possible

The Healer runs on the Haiku model, keeping it lightweight and fast. It checks status regularly and acts automatically without needing instructions from you.

## File Locations

All quest coordination files live under `.crystl/quest/` in the project root:

| Path | Purpose |
|------|---------|
| `messages.jsonl` | Full v1 message log (JSONL, monitored by Crystl's file watcher) |
| `status.json` | Current agent status and health (legacy v1) |
| `QUEST-LOG.md` | Compressed conversation summary (written by Healer) |
| `HANDOFF.md` | Context handoff notes for agents near their limit |
| `DECISIONS.md` | Settled decisions to prevent re-discussion |
| `v2/status/<shard>.json` | Per-shard status, role, and last-active info |
| `v2/progress/<shard>.json` | Per-shard context remaining and current task |
| `v2/tasks/` | Task records created by `quest_task` |
| `v2/summaries.jsonl` | Milestone summaries appended by `quest_summary` |
| `v2/cursors/messages.cursor` | File watcher byte-offset cursor (persists across restarts) |

### Reading v2 Status

```bash
# Check a shard's status
cat .crystl/quest/v2/status/wizard.json

# See live summaries
cat .crystl/quest/v2/summaries.jsonl

# Catch up without replaying the full chat log
tail .crystl/quest/v2/summaries.jsonl
```

## SSH Hook Delivery

When running a quest over SSH, `quest_msg` and `quest_announce` include a retry loop: up to three attempts to deliver the hook notification to the local Crystl bridge, with a 1-second pause between retries. If all three attempts fail, a warning is printed to stderr:

```
[quest] hook delivery failed — message may not reach host
```

The message is still written to `messages.jsonl` — delivery failure only affects the live notification, not the permanent record.

## Related Docs

- [Crystl Quest](/docs/crystl-quest) — Overview of the quest system
- [Quest Chat Panel](/docs/quest-chat) — The chat interface where messages appear
- [Quest Heroes](/docs/quest-heroes) — Hero catalog and the Healer role
- [Starting a Quest](/docs/starting-a-quest) — Setup flow and party configuration

---
Source: https://crystl.dev/docs/quest-coordination/
