Resources
1Install
npx skillscat add bobmatnyc/claude-mpm/mpm-message Install via the SkillsCat registry.
Cross-Project Messaging
Send asynchronous messages to other Claude MPM instances running in different projects.
Important: Always use
claude-mpm messageCLI commands or theMessageServicePython API.
Never querymessaging.dbdirectly — the database location is an implementation detail.
How It Works
- Send: Message written to shared SQLite database (
~/.claude-mpm/messaging.db) - Detect: Target project's message check hook detects unread messages periodically
- Read: PM reads message and decides what local tasks to create
- Reply: PM sends reply back to originating project
All messages flow through a single shared database at ~/.claude-mpm/messaging.db. No per-project databases.
Usage
Quick Send (Skill Syntax)
/mpm-message <project-path> <message>CLI
# Send a message
claude-mpm message send <project-path> \
--body "message content" \
--subject "message subject" \
--type [task|request|notification|reply] \
--priority [low|normal|high|urgent] \
--to-agent [pm|engineer|qa|ops|etc]
# For complex bodies with quotes, use --body-file
claude-mpm message send <project-path> --body-file message.txt --subject "subject"
echo "body text" | claude-mpm message send <project-path> --body-file - --subject "subject"
# Inbox operations
claude-mpm message check # Quick unread count
claude-mpm message list # List all messages
claude-mpm message list --status unread # List unread only
claude-mpm message read <message-id> # Read a message
claude-mpm message reply <message-id> --body "response"
claude-mpm message reply <message-id> --body-file reply.txt # From file
claude-mpm message archive <message-id>
claude-mpm message sessions # List active sessionsPython API (PREFERRED fallback for all versions)
from pathlib import Path
from claude_mpm.services.communication.message_service import MessageService
service = MessageService(Path.cwd())
msg = service.send_message(
to_project='/path/to/target/project',
to_agent='pm',
message_type='notification', # task | request | notification | reply
subject='Subject here',
body='Body content here',
priority='high', # urgent | high | normal | low
from_agent='pm',
)
print(f"Sent: {msg.id}")
# List unread
unread = service.list_messages(status="unread")
for m in unread:
print(f"[{m.priority}] {m.subject}")
# Read and reply
message = service.read_message("msg-id-here")
reply = service.reply_to_message("msg-id-here", subject="Re: ...", body="Done!")Note:
send_message()takesmessage_type=(nottype=) — this matches the DB schema column name.
⚠️ Anti-Pattern: Never Write Directly to messaging.db
Do NOT use raw SQLite INSERT statements to send messages. This bypasses the abstraction layer and will break when the Huey message bus migration lands (#311).
Wrong:
# ❌ NEVER DO THIS
conn.execute("INSERT INTO messages (type, ...) VALUES ...")Right:
# ✅ ALWAYS USE MessageService
service = MessageService(Path.cwd())
service.send_message(to_project=..., message_type=..., ...)The DB column is message_type, not type — direct writes get this wrong and create schema-mismatched records.
Message Types
| Type | Use Case |
|---|---|
| task | Delegate work to another project |
| request | Ask for information or assistance |
| notification | Share status updates |
| reply | Respond to received messages |
Priority Levels
- urgent - Critical, immediate attention
- high - Important, should be addressed soon
- normal - Standard priority (default)
- low - Address when convenient
Receiving Messages
Automatic Detection (via Hook)
- Session start (always)
- Every 10 commands (configurable)
- Every 30 minutes (configurable)
Reading Messages (CLI)
Always use the CLI to check messages — never query the database directly:
# Quick unread count
claude-mpm message check
# List unread messages
claude-mpm message list --status unread
# Read a specific message
claude-mpm message read <message-id>Message Storage
Single shared database: ~/.claude-mpm/messaging.db
All projects read from and write to the same database. Messages are filtered by to_project on read.
Configuration
messaging:
enabled: true
check_on_startup: true
command_threshold: 10
time_threshold: 30
auto_create_tasks: true
task_priority_filter: ["urgent", "high"]Architecture: Messages ≠ Tasks
Messages are just messages — peer-to-peer communication.
Tasks are local decisions. When PM reads a message, the local PM decides what tasks to create based on its own context.
The sending project should NOT inject tasks — it doesn't have the recipient's context.
Limitations
- Not real-time — Checked periodically (every 10 commands / 30 minutes)
- Local filesystem only — Same user, same machine
- No encryption — Plaintext SQLite storage
Forward Compatibility
The current implementation uses SQLite directly. A Huey-based message bus migration is planned (#311). Always use MessageService to ensure your code works after the migration. Do not write to messaging.db directly.
Version: 5.9.27+
Status: Stable
Issues: #305, #310, #311, #312