Files
gastown/docs/beads-native-messaging.md
gastown/crew/max 4f02abb535 fix(mail): add channel routing to router.Send()
The router was missing support for beads-native channel addresses.
When mail_send.go resolved an address to RecipientChannel, it set
msg.To to "channel:<name>" but router.Send() had no handler for this
prefix, causing channel messages to fail silently.

Added:
- isChannelAddress() and parseChannelName() helper functions
- sendToChannel() method that creates messages with proper channel:
  labels for channel queries
- Channel validation before sending
- Retention enforcement after message creation

Also updated docs/beads-native-messaging.md with more comprehensive
documentation of the beads-native messaging system.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 07:23:34 -08:00

202 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Beads-Native Messaging
This document describes the beads-native messaging system for Gas Town, which replaces the file-based messaging configuration with persistent beads stored in the town's `.beads` directory.
## Overview
Beads-native messaging introduces three new bead types for managing communication:
- **Groups** (`gt:group`) - Named collections of addresses for mail distribution
- **Queues** (`gt:queue`) - Work queues where messages can be claimed by workers
- **Channels** (`gt:channel`) - Pub/sub broadcast streams with message retention
All messaging beads use the `hq-` prefix because they are town-level entities that span rigs.
## Bead Types
### Groups (`gt:group`)
Groups are named collections of addresses used for mail distribution. When you send to a group, the message is delivered to all members.
**Bead ID format:** `hq-group-<name>` (e.g., `hq-group-ops-team`)
**Fields:**
- `name` - Unique group name
- `members` - Comma-separated list of addresses, patterns, or nested group names
- `created_by` - Who created the group (from BD_ACTOR)
- `created_at` - ISO 8601 timestamp
**Member types:**
- Direct addresses: `gastown/crew/max`, `mayor/`, `deacon/`
- Wildcard patterns: `*/witness`, `gastown/*`, `gastown/crew/*`
- Special patterns: `@town`, `@crew`, `@witnesses`
- Nested groups: Reference other group names
### Queues (`gt:queue`)
Queues are work queues where messages wait to be claimed by workers. Unlike groups, each message goes to exactly one claimant.
**Bead ID format:** `hq-q-<name>` (town-level) or `gt-q-<name>` (rig-level)
**Fields:**
- `name` - Queue name
- `status` - `active`, `paused`, or `closed`
- `max_concurrency` - Maximum concurrent workers (0 = unlimited)
- `processing_order` - `fifo` or `priority`
- `available_count` - Items ready to process
- `processing_count` - Items currently being processed
- `completed_count` - Items completed
- `failed_count` - Items that failed
### Channels (`gt:channel`)
Channels are pub/sub streams for broadcasting messages. Messages are retained according to the channel's retention policy.
**Bead ID format:** `hq-channel-<name>` (e.g., `hq-channel-alerts`)
**Fields:**
- `name` - Unique channel name
- `subscribers` - Comma-separated list of subscribed addresses
- `status` - `active` or `closed`
- `retention_count` - Number of recent messages to retain (0 = unlimited)
- `retention_hours` - Hours to retain messages (0 = forever)
- `created_by` - Who created the channel
- `created_at` - ISO 8601 timestamp
## CLI Commands
### Group Management
```bash
# List all groups
gt mail group list
# Show group details
gt mail group show <name>
# Create a new group with members
gt mail group create <name> [members...]
gt mail group create ops-team gastown/witness gastown/crew/max
# Add member to group
gt mail group add <name> <member>
# Remove member from group
gt mail group remove <name> <member>
# Delete a group
gt mail group delete <name>
```
### Channel Management
```bash
# List all channels
gt mail channel
gt mail channel list
# View channel messages
gt mail channel <name>
gt mail channel show <name>
# Create a channel with retention policy
gt mail channel create <name> [--retain-count=N] [--retain-hours=N]
gt mail channel create alerts --retain-count=100
# Delete a channel
gt mail channel delete <name>
```
### Sending Messages
The `gt mail send` command now supports groups, queues, and channels:
```bash
# Send to a group (expands to all members)
gt mail send my-group -s "Subject" -m "Body"
# Send to a queue (single message, workers claim)
gt mail send queue:my-queue -s "Work item" -m "Details"
# Send to a channel (broadcast with retention)
gt mail send channel:my-channel -s "Announcement" -m "Content"
# Direct address (unchanged)
gt mail send gastown/crew/max -s "Hello" -m "World"
```
## Address Resolution
When sending mail, addresses are resolved in this order:
1. **Explicit prefix** - If address starts with `group:`, `queue:`, or `channel:`, use that type directly
2. **Contains `/`** - Treat as agent address or pattern (direct delivery)
3. **Starts with `@`** - Special pattern (`@town`, `@crew`, etc.) or beads-native group
4. **Name lookup** - Search for group → queue → channel by name
If a name matches multiple types (e.g., both a group and a channel named "alerts"), the resolver returns an error and requires an explicit prefix.
## Key Implementation Files
| File | Description |
|------|-------------|
| `internal/beads/beads_group.go` | Group bead CRUD operations |
| `internal/beads/beads_queue.go` | Queue bead CRUD operations |
| `internal/beads/beads_channel.go` | Channel bead + retention logic |
| `internal/mail/resolve.go` | Address resolution logic |
| `internal/cmd/mail_group.go` | Group CLI commands |
| `internal/cmd/mail_channel.go` | Channel CLI commands |
| `internal/cmd/mail_send.go` | Updated send with resolver |
## Retention Policy
Channels support two retention mechanisms:
- **Count-based** (`--retain-count=N`): Keep only the last N messages
- **Time-based** (`--retain-hours=N`): Delete messages older than N hours
Retention is enforced:
1. **On-write**: After posting a new message, old messages are pruned
2. **On-patrol**: Deacon patrol runs `PruneAllChannels()` as a backup cleanup
The patrol uses a 10% buffer to avoid thrashing (only prunes if count > retainCount × 1.1).
## Examples
### Create a team distribution group
```bash
# Create a group for the ops team
gt mail group create ops-team gastown/witness gastown/crew/max deacon/
# Send to the group
gt mail send ops-team -s "Team meeting" -m "Tomorrow at 10am"
# Add a new member
gt mail group add ops-team gastown/crew/dennis
```
### Set up an alerts channel
```bash
# Create an alerts channel that keeps last 50 messages
gt mail channel create alerts --retain-count=50
# Send an alert
gt mail send channel:alerts -s "Build failed" -m "See CI for details"
# View recent alerts
gt mail channel alerts
```
### Create nested groups
```bash
# Create role-based groups
gt mail group create witnesses */witness
gt mail group create leads gastown/crew/max gastown/crew/dennis
# Create a group that includes other groups
gt mail group create all-hands witnesses leads mayor/
```