A role-based messaging system for multi-model AI collaboration in CLI/TUI coding environments.
This project enables AI models running in different CLI tools (Claude Code, OpenAI Codex, Gemini, OpenCode) to communicate using standard email protocols (Maildir format).
Key insight: Use standard email (Maildir) so you can use existing email clients like Mutt!
📖 For architecture, design decisions, and comparison to the old protocol, see DESIGN.md.
# List available roles
./scripts/msg roles
# Send a message
./scripts/msg send --from coordinator --to explorer-claude \
--subject "Question" --content "What do you think?"
# Check for messages
./scripts/msg poll --role explorer-claude
# Read a message
./scripts/msg read --role explorer-claude <message-id>
# Use Mutt to read/send messages
mutt -f .messages/coordinatorMessages are between roles, not specific models:
coordinator- You (human facilitator)monitor- Observer (auto-BCC'd on all messages)explorer-claude,explorer-gpt5,explorer-gemini,explorer-grok- AI explorers
Roles can be reassigned to different models via config/role-config.json.
Standard email directory structure:
.messages/
coordinator/
new/ # Unread
cur/ # Read
tmp/ # Delivery
monitor/ # BCC copy of ALL messages
explorer-claude/
...
RFC-compliant email with custom headers:
From: explorer-claude@multimodel.local
To: coordinator@multimodel.local
Subject: Design thoughts
X-Role: explorer-claude
X-Artifacts: specs/*/auth.md
In-Reply-To: <msg-abc@multimodel.local>
[Content...]
Use glob patterns so links survive state transitions:
X-Artifacts: specs/*/auth.md
This works whether the spec is in proposed/, doing/, or done/.
1. Participant (coordinator mailbox):
- Your active inbox/outbox
- Send and receive messages
- Engage in conversations
2. Observer (monitor mailbox):
- Auto-BCC'd on ALL messages
- Watch entire conversation flow
- Read-only monitoring
Open both in separate terminals:
# Terminal 1: Active participation
mutt -f .messages/coordinator
# Terminal 2: Passive observation
mutt -R -f .messages/monitormsg send --from <role> --to <roles> --subject "..." --content "..."
[--cc <roles>] [--reply-to <msg-id>] [--artifacts <paths>]msg poll --role <role> [--all] [--wait] [--timeout N]Flags:
--all: Show all messages (cur/ and new/), not just unread--wait: Block until messages arrive (for persistent agents)--timeout N: Optional timeout in seconds for --wait mode (default: wait forever)
msg read --role <role> <message-id> [--headers]Note: Messages are automatically marked as read when you read them (moved from new/ to cur/).
msg reply --from <role> <message-id> [--to <roles>] [--content "..."]Note: Replying to a message automatically marks it as read.
Messages are stored in standard Maildir format:
- new/ - Unread messages
- cur/ - Read messages
- tmp/ - Temporary (during delivery)
- Read:
msg readautomatically marks messages as read (moves fromnew/tocur/) - Reply:
msg replyautomatically marks the original message as read
The mu email indexer is available for complex searches:
# Search for messages from coordinator about evaluators
mu find from:coordinator subject:evaluator maildir:/.messages/claude
# Find all messages from gpt-5
mu find from:gpt-5 maildir:/.messages/claude
# Find messages with artifacts
mu find 'x-artifacts:*' maildir:/.messages/claude
# Complex query: unread messages from last week
mu find date:7d..now flag:unread maildir:/.messages/claude/newThe msg commands handle common cases. Use mu when you need powerful search/filtering.
Have exploratory conversations where models collaborate:
- You or any model initiates
- Models respond to each other directly
- Natural DAG emerges via reply-to
- You observe and/or participate
Unlike pure chat, models can:
- Write code
- Run tests
- Read/edit files
- All the things CLI tools can do
Integrate with artifact workflows:
- Writer finishes → sends review request
- Reviewer polls → writes review → responds
- Blocking or async modes
The --wait flag enables true persistent agents that run continuously:
# Agent runs indefinitely in interactive mode
while True:
# Block until messages arrive
msg poll --role explorer-claude --wait
# Process messages
# Respond as needed
# Loop (never ends response)- Launch interactive session:
./scripts/run-role.sh -i explorer-claude - Agent initialization: Checks for existing unread messages
- Enter wait loop: Blocks on
msg poll --wait - Message arrives: Poll returns with messages
- Process and respond: Agent reads, thinks, responds
- Return to waiting: Loop back to step 3
- Termination: Ctrl-C or close terminal
- Truly persistent agents (not one-shot)
- No resource waste (blocks efficiently)
- Fast response (already running)
- User can still interrupt (send message to role)
- Clean lifecycle (Ctrl-C to stop)
Terminal 2: Claude Explorer
$ ./scripts/run-role.sh -i explorer-claude
Starting continuous monitoring for role: explorer-claude
Checking for existing messages...
No unread messages.
Waiting for messages... (blocking)
[... user sends message ...]
Received 1 message:
From: coordinator
Subject: Design question
Reading message...
[thinks and responds]
Sent reply: <msg-abc123>
Waiting for messages... (blocking)
[continues indefinitely until Ctrl-C]
Use the provided launcher scripts with preconfigured settings:
# Coordinator mailbox (your active inbox)
./scripts/mutt-coordinator.sh
# Monitor mailbox (read-only observer)
./scripts/mutt-monitor.shThese scripts use project-local configuration files (config/muttrc-coordinator and config/muttrc-monitor) with proper threading, colors, and UI settings.
If you prefer to configure your own ~/.muttrc:
set folder="~/Projects/MultiModelCLIEmail/.messages"
set spoolfile="+coordinator"
mailboxes +coordinator +monitor +claude +gpt-5 +gemini +grok
set sort=threads
Then:
mutt -f .messages/coordinator # Your active mailbox
mutt -R -f .messages/monitor # Observer mode (read-only)Why Maildir?
- Standard, battle-tested format
- Works with existing tools (Mutt, mu, notmuch)
- Simple (just files)
- Atomic, debuggable
Why auto-BCC to monitor?
- Separates participation from observation
- You can watch all traffic without being in every conversation
- Clean separation of concerns
Why roles not models?
- Same model can play different roles
- Roles can be reassigned
- Maps to existing workflow concepts
Why glob patterns for artifacts?
- Artifacts move as state changes (
proposed/→doing/→done/) - Globs keep references valid
Working:
- Maildir structure
- Basic CLI (send, poll, read, reply)
- Auto-BCC to monitor
- Standard email format
- Glob artifact references
- Blocking wait (
msg poll --wait) for persistent agents - Role instruction files (example: explorer-claude)
TODO:
- Launcher script (run-role.sh)
- Mutt configuration helpers
- Artifact glob resolver helper
- Integration with workflow system
- Additional role files (gpt5, gemini, grok)
Try it out! Send a message from coordinator to an explorer role, then see it appear in monitor.