Mavis coordination protocols
Audience: Any Mavis (Helper or doer) that needs to communicate with another Mavis or with the operator.
TL;DR
- Helper coordinates. Doers execute. Don't blur the line.
- Lanes are role-gated Mavis sessions, not separate agent identities. Top-level agents are
General,Coder,Verifier. Lane sessions (cards, chrome, fvre, helper) inherit from one of these with a lane-scoped system prompt. - Cross-session communication uses the
communicatetool. To reach a lane, send to the lane's session ID. To spin up a one-shot, usespawn. - The operator is the cross-Mavis bus. When in doubt, surface to the operator.
- Prompts and replies are archived in
prompts/. Every cross-session message gets a record. ???is the check-in code. Type???in any Mavis session to trigger the wake-up / check-in protocol. See below.
The roster model
| Concept | What it is | Example |
|---|---|---|
| Top-level agent | The identity registered in agent list | General, Coder, Verifier |
| Mavis session | A long-lived thread with a system prompt | session 412100071272671 (Helper) |
| Lane | A Mavis session with a lane-scoped system prompt | cards, chrome, fvre, helper |
| Role | What a Mavis does in a session | manager, doer, verifier |
Three role tiers:
- Manager — Helper. Plans, tracks, routes, reports. Does not write code or push.
- Doer — cards, chrome, fvre. Writes code, runs tests, builds, pushes. Stays in lane.
- Verifier — spawned one-shot. Reviews, audits, tests. Reports back, exits.
Communication patterns
Pattern 1: Helper → doer lane (route a plan)
When Helper has work to do and a doer lane should do it:
Helper session 412100071272671
↓ communicate (to_session=<doer-session-id>)
Doer session 404483248046205
↓ does the work
↓ writes a report to docHub (or reports back)
Doer session 404483248046205
↓ communicate (to_session=412100071272671)
Helper session 412100071272671
↓ updates overview + memory
The doer doesn't push the report via chat — they write it to docshub/dev/reports/<date>-<slug>.md and reply with a one-line ack. The full record is on disk.
Pattern 2: Helper → operator (status check-in)
When the operator pings Helper for status:
Operator → Helper (chat)
Helper reads bootstrap.json + recent reports
Helper replies with TLDR + next-step verb
No spawn, no relay. Just the operator + Helper in a 1:1 thread.
Pattern 3: Doer → doer (cross-lane work)
When one doer needs another doer (e.g., chrome drafts wording, cards applies it):
- Direct:
communicatetool with the other lane's session ID. - Routed: Send to Helper, Helper forwards.
- Operator-relayed: Oldest, slowest, but useful when both lanes are deep in their own work.
Default: direct. If it fails, escalate to operator-relayed.
Pattern 4: Verifier (one-shot)
When a doer's work needs adversarial review:
Helper or doer
↓ communicate (spawn={agent_name: "Verifier", ...})
Verifier session (one-shot)
↓ does the review
↓ reports back to spawner
Verifier session exits
The verifier does NOT continue working after reporting. They audit and exit.
What Helper does NOT do
- Write code. If a plan needs code, route to a doer.
- Push to GitHub. If a plan needs a push, route to a doer.
- Deploy. If a plan needs a deploy, route to a doer.
- Run tests. If a plan needs test results, route to a doer.
Helper's job: hold the big picture, surface state, route work, archive records. The doers do the work.
Exception: Helper may write small scripts or fixtures that are docHub-internal (e.g., the build script that regenerates manifest.json from frontmatter). That's maintenance, not feature work.
What doers do NOT do
- Plan across lanes. A doer should stay in their lane. Cross-lane planning is Helper's job.
- Touch the overview + roadmap directly. They write reports; Helper updates the index.
- Spawn other doers. A doer can spawn a Verifier for review, but not another doer. That's Helper's call.
Exception: a doer CAN update decisions/ if a decision is theirs (e.g., a D-XXX that they wrote and own). The cross-lane decisions/D-056+ are constitutional and need a Helper ack.
The prompt archive
Every cross-session message gets filed at docshub/dev/prompts/<date>-<from>-to-<to>-<slug>.md. The file has:
- Frontmatter: from/to/sent/status/subject
- Body: the prompt sent (verbatim)
- Reply: appended when status moves to
replied
The prompt archive is the long-term record of how the Mavis team has coordinated. New Mavis sessions can read it to see "what did Helper ask cards to do last week, and what came back?"
The dangerous protocol
If a Mavis is about to do something destructive (delete, force-push, mass-edit, token rotation, repo cleanup):
- Read
dangerous/first. Always. - State the plan to Helper or operator. No silent destructive actions.
- Verify the target is what you think it is. For GitHub:
GETthe repo first, inspect contents. - Run a dry-run if available.
wrangler ... --dry-run,gh ... --dry-run,git push --dry-run. - Have a recovery plan. If this is irreversible, know how to recover BEFORE you do it.
The 2026-06-22 case-variant-dup cleanup is the canonical failure case. Don't repeat it.
Session lifecycle
| Phase | What happens | Where it's recorded |
|---|---|---|
| Spawn | New Mavis session created | First prompts/ entry + bootstrap state |
| Active | Mavis does work | Reports + decisions + prompts |
| Parked | Mavis idle, waiting on operator or another lane | Last reports/ entry notes parked-on |
| Closing | Mavis writes final report, hands off | Final report is the handoff record |
When a Mavis session closes, the most recent report IS the handoff. Next session reads that report to resume.
The ??? check-in protocol
Wake-up code: three question marks. ???
The operator (or any Mavis) types ??? in any Mavis session to trigger a wake-up / check-in. The Mavis that sees ??? runs the protocol below.
Why ???
- Shortest possible
- No autocomplete collision
- Hard to typo (any keyboard)
- Visually distinct from normal text
- Works in any chat context (Mavis, operator relay, etc.)
The protocol
When a Mavis sees ??? (the only text in the user message, or clearly the trigger), it executes:
1. Inbox scan
- Read
docshub/mavis/prompts/for any files withstatus: sentthat target this Mavis's lane - For each unprocessed prompt: read it, decide if you can act on it, reply via a new file in
prompts/(with the original prompt's ID + status flipped toreplied) OR viacommunicateto the sender's session - Update the original prompt's frontmatter
status: acknowledgedwhile you're working on it, thenrepliedwhen done
2. Memory refresh
- Read
docshub/mavis/_meta/bootstrap.json(regenerated bynode build.mjs) - Read any new reports in
docshub/mavis/reports/since your last session (sort byupdatedfield, take the top 5) - Read any new decisions in
docshub/mavis/decisions/ - Update your in-memory working state to match
3. State report
Reply with one of these forms:
- No blockers:
✅ checkin complete, no blockers. Inbox: N processed, M new reports, K new decisions. State: <one-line summary>. - Blockers:
✅ checkin complete. Blocker: <description>. Blocked on: <lane or operator>. Awaiting: <specific input needed>. - Errors:
⚠️ checkin incomplete. Failed at step <N>: <error>. State: <what you did manage>.
4. Idle
- Don't wait for more input. End the turn after the state report.
- The operator (or another Mavis) can issue a follow-up
???to chain check-ins across lanes.
What ??? does NOT do
- It does NOT spawn a new Mavis. The Mavis that sees
???is the one that runs the protocol. - It does NOT force a dormant Mavis to wake up. A dormant Mavis that never gets attention will never see
???. - It does NOT bypass any auth or access control.
- It is not a special chat command on the Mavis platform — it's just a convention each Mavis's system prompt understands.
Why this matters
Mavis sessions are not continuous processes. They're threads that get attention when something triggers a model invocation. Cross-Mavis messages sit unread in dormant sessions. The ??? code:
- Makes it cheap to trigger a check-in (one keystroke + 3 chars)
- Gives a clear, observable action the operator can take
- Provides a known protocol each Mavis follows (no improvising)
- Creates a paper trail (the inbox scan + state report)
If a Mavis is genuinely dormant, ??? won't help. But it makes the common case (active session, just needs nudge) reliable.
When to use ???
- You sent a message to a Mavis hours ago and got no reply. Type
???in that Mavis's thread. - You want to know the current state across all lanes. Visit each lane thread, type
???in each. They each report back. - A new Mavis session just spawned. Type
???to trigger the wake-up protocol (the Mavis reads inbox, refreshes memory, reports state). - You're parking a Mavis for a while. No
???needed — the parking report inmavis/reports/is the handoff.
Operator-as-bus fallback
If ??? doesn't reach a Mavis (because the thread is dormant), the operator can act as the bus:
- Read the Mavis's last
reports/entry to know current state - Surface the question to the operator directly
- The operator relays the answer back to whoever needs it
The operator relay is slower than ??? but always works. Use it when ??? fails.
Cross-cutting examples
Scenario: Helper needs cards Mavis to confirm Region Schema state
Helper → cards Mavis (via communicate)
Status: sent, no reply for 2 hours
Operator → cards Mavis thread
Types: ???
Cards Mavis wakes, runs protocol:
- Inbox scan: finds Helper's pending message
- Processes it
- Updates status to replied
- Reports: "✅ checkin complete. Region Schema: confirmed committed at 081e2f3. Unblocks OQ-1."
Operator → Helper
Relays: "Region Schema: committed at 081e2f3, OQ-1 unblocked."
Scenario: a new Helper session starts, needs to get up to speed
Operator → new Helper thread
Types: ???
New Helper runs protocol:
- Inbox scan: empty
- Memory refresh: reads bootstrap.json, top 5 reports, recent decisions
- State report: "✅ checkin complete. State: docHub Phase 5 in progress, awaiting deploy. 3 open questions (OQ-1, OQ-2, OQ-3). 1 pending cross-Mavis ping to cards."
- Idles
Scenario: a lane Mavis is dormant, no ??? works
Operator tries ??? — Mavis doesn't wake
Operator reads the lane's last reports/ entry — knows the state from disk
Operator relays the question to the operator-channel directly
Operator relays the answer back
The third pattern is the fallback. It works because docHub state is on disk, not in the Mavis's head.