docs/messaging.md
Beads supports messaging as a first-class issue type, enabling inter-agent and human-agent communication within the same system used for issue tracking.
Mail commands (bd mail) delegate to an external mail provider (typically gt mail in an orchestrator). Beads stores messages as issues with type: message, threading via replies_to dependencies, and ephemeral lifecycle via the ephemeral flag.
This design separates concerns:
Configure the mail delegate (one-time):
# Environment variable (recommended for agents)
export BEADS_MAIL_DELEGATE="gt mail"
# Or per-project config
bd config set mail.delegate "gt mail"
# Send mail (delegates to gt mail)
bd mail send worker/ -s "Review needed" -m "Please review bd-abc"
# Check inbox
bd mail inbox
# Read a message
bd mail read msg-123
# Reply to a thread
bd mail reply msg-123 -m "Reviewed and approved"
Messages are issues with type: message:
| Field | Purpose |
|---|---|
type | message |
sender | Who sent the message |
assignee | Recipient |
title | Subject line |
description | Message body |
status | open (unread) / closed (read) |
ephemeral | If true, eligible for bulk cleanup |
Messages form threads via replies_to dependencies. View a full thread:
bd show msg-123 --thread
This traces the replies_to chain to find the root message, then collects all replies via BFS, displaying the conversation with proper indentation.
Thread display shows:
Messages marked ephemeral: true are transient - they can be bulk-deleted after a swarm completes:
# Clean up closed ephemeral messages
bd cleanup --ephemeral --force
# Preview what would be deleted
bd cleanup --ephemeral --dry-run
# Only delete ephemeral messages older than 7 days
bd cleanup --ephemeral --older-than 7 --force
Ephemeral messages are:
bd ready by defaultThe actor identity (used for sender on messages) is resolved in order:
--actor flag on the commandBEADS_ACTOR environment variableBD_ACTOR environment variable (deprecated alias)git config user.name$USER environment variable"unknown"Scripts in .beads/hooks/ run after certain events:
| Hook | Trigger |
|---|---|
on_create | After bd create |
on_update | After bd update |
on_close | After bd close |
Hooks receive event data as JSON on stdin. This enables orchestrator integration (e.g., notifying services of new messages) without beads knowing about the orchestrator.
Creates with initial labels preserve the legacy hook sequence: on_create receives the issue snapshot before labels, followed by one or more on_update events with cumulative label snapshots. The labels are already persisted before those hooks run, so hook scripts that need the create-time sequence should rely on the JSON payload instead of re-reading the issue from the store during the hook.
Batch creates with initial dependencies emit on_update for each persisted
dependency after the create-time hooks. Each payload carries a cumulative
dependency snapshot in request order, matching the event shape produced by
explicit post-create dependency additions; dependencies skipped because their
target was not persisted do not produce hooks.