# 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, how messages reach agents, @mention routing, and the underlying file format.

## Simultaneous delivery

When you send a message to the party, Quest delivers it to **every agent at once**. The message is broadcast to all party shards at the same time, not handed out one agent at a time. Each agent replies through `quest_msg`, so the whole party (and you) can see what everyone is doing.

### How the party stays coordinated

Coordination comes from the agents talking to each other, not from a delivery order. Each hero has a defined role and works in its own lane. Heroes post key decisions (tech stack, architecture, file layout) over `quest_msg` (broadcasting to the whole party with `quest_msg "all"`), and they read the message log plus survey the repo before writing code, so a teammate who already set something up isn't duplicated. For shared files, an agent calls `quest_claim` to flag a file before editing it, so the rest of the party avoids silent conflicts. Together these keep the party aligned without a human assigning lanes.

## 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, so 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 it 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_claim

```bash
quest_claim '<path>'          # claim a file before editing it
quest_claim --release '<path>' # release it when you're done
quest_claim --list             # see what's claimed across the party
```

Flag a file before editing so the rest of the party avoids silent conflicts. Release it when you're done; claims expire automatically after 30 minutes. Check `quest_claim --list` before touching a file another shard might own.

To broadcast a shared decision (port assignments, API shape, design tokens) to the whole team at once, use `quest_msg "all" "..."` — see [@all](#all-broadcast) below.

## @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` includes 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.

## Coordination via the crystl CLI

`quest_msg` is the in-quest primitive, but party members can also reach outside the quest using the [crystl CLI](/docs/cli) to inspect or drive sibling shards directly. The two surfaces complement each other:

| Use `quest_msg` for | Use `crystl` for |
|---------------------|------------------|
| In-party chat (the quest record) | Spawning a fresh shard outside the party |
| @mention routing across heroes | Reading what's on another shard's screen |
| Status updates the party should record | Programmatically approving or denying a pending tool call |
| Party-wide broadcast semantics | Streaming bridge events as JSON without polling |

Useful CLI patterns for agents in a quest:

```bash
# What is another shard doing right now?
crystl screen --gem $CRYSTL_GEM --shard ranger

# Spawn an isolated worktree shard and seed it with a task
crystl shard create --gem $CRYSTL_GEM --isolated --crystal-name jade --prompt "add tests"

# Block until any permission request comes in, then handle it
crystl wait pending --json | jq -r '.tool_name'
```

The CLI snippet that crystl injects into each gem's `CLAUDE.md` and `AGENTS.md` makes these commands discoverable to every agent in the party without quest setup having to teach them.

## 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
- [crystl CLI](/docs/cli): drive gems, shards, and approvals from any shell

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