SwarmForge Handoff Protocol: Complete File-Based Communication System for AI Agents
The SwarmForge handoff protocol is a durable, file-based communication channel that lets AI agents exchange work-items without direct tmux socket access or manual git coordination.
The handoff protocol, as implemented in unclebob/swarm-forge, replaces legacy log-book and resend-queue mechanisms with an atomic, auditable system. Agents communicate through structured files that survive crashes and provide complete lifecycle tracking.
Core Architecture of the SwarmForge Handoff Protocol
Directory Layout and File Organization
Each agent's work-tree contains a hidden .swarmforge/handoffs/ directory with four subdirectories:
outbox/— staging area for outbound handoffssent/— archive of successfully delivered handoffsfailed/— quarantine for undeliverable handoffsinbox/— incoming messages withnew/,in_process/, andcompleted/subfolders
The handoffd daemon watches outbox/ and copies new handoffs into recipients' inbox/new/ directories. This design, documented in swarmforge/handoff-protocol.md lines 24-38, ensures durability through simple filesystem operations.
Handoff Filename Format
Every handoff uses a strictly ordered filename that enables deterministic processing:
<priority>_<timestamp>_<seq>_from_<sender>_to_<recipients>.handoff
The sequence number guarantees total ordering when timestamps collide. Priority prefixes allow high-urgency handoffs to surface first without complex queue management.
File Structure: Headers and Body
A handoff file contains two sections separated by a blank line:
id: hand-20260615-140531-abc123
from: architect
to: cleaner
type: git_handoff
priority: 50
created_at: 2026-06-15T14:05:31Z
[opaque body content — not parsed by the system]
Critical headers (id, from, to, type) are injected by swarm_handoff.sh. The body is treated as opaque payload—agents may include shell commands, commit hashes, or free-form instructions without protocol constraints.
Supported Message Types
The protocol currently defines two message types per handoff-protocol.md lines 30-48:
| Type | Purpose | Authorization |
|---|---|---|
git_handoff |
Request to forward a commit to another role | Automatic for role transitions |
note |
Short free-form message | Explicit authorization only |
Key Components of the SwarmForge Handoff Protocol
Outbound Gate: swarm_handoff.sh
Located at swarmforge/scripts/swarm_handoff.sh, this script is the sole entry point for creating handoffs. It performs:
- Draft validation against protocol schema
- Reserved header injection (
id,from,created_at) - Commit hash validation (10 hexadecimal characters)
- Atomic write to
outbox/tmp/, then rename tooutbox/*.handoff
The atomic rename guarantees that handoffd never sees partially written files.
Delivery Daemon: handoffd.bb
The Babashka-based daemon (swarmforge/scripts/handoffd.bb) implements the delivery engine:
- Scans each agent's
outbox/for new.handofffiles - Validates file integrity and recipient existence
- Copies to each recipient's
inbox/new/with injectedrecipientandenqueued_atheaders - Sends tmux wake-up:
"You have new handoff mail. If idle, run ready_for_next.sh." - Moves source file to
sent/on success,failed/on error
All operations are idempotent—duplicates are detected via id header and skipped.
Queue Helper Scripts
The protocol provides abstraction scripts that shield agents from directory manipulation:
ready_for_next.sh— entry point that dispatches based on role's receive modeready_for_next_task.sh— single-task processingready_for_next_batch.sh— batch processingdone_with_current.sh— completion dispatcherdone_with_current_task.sh/done_with_current_batch.sh— specific completion handlers
These helpers, defined in handoff-protocol.md lines 62-70, own all inbox state transitions and timestamp injection.
SwarmForge Handoff Protocol Lifecycle
Step 1: Create
Agents draft handoffs in ./tmp/ and submit via swarm_handoff.sh:
# Draft a git_handoff request
cat > ./tmp/handoff.txt <<'EOF'
type: git_handoff
to: cleaner
priority: 50
task: task-1-cave-setup
commit: a1b2c3d9e8
EOF
# Validate and queue
swarm_handoff.sh ./tmp/handoff.txt
Output: .swarmforge/handoffs/outbox/50_20260615T140531Z_000042_from_architect_to_cleaner.handoff
Step 2: Deliver
handoffd.bb detects the file, copies to recipient inbox, injects delivery metadata, and notifies via tmux. No agent action required.
Step 3: Consume
Recipient fetches work through the helper chain:
ready_for_next.sh
This reads .swarmforge/roles.tsv to determine receive mode, then executes the appropriate handler. The helper moves file(s) to inbox/in_process/ and adds dequeued_at timestamp.
Example output:
TASK: .swarmforge/handoffs/inbox/in_process/50_20260615T140531Z_000042_from_architect_to_cleaner.handoff
FROM: architect
TYPE: git_handoff
PRIORITY: 50
TASK_NAME: task-1-cave-setup
PAYLOAD:
Re-read your role and constitution.
merge_and_process.sh architect a1b2c3d9
Step 4: Complete
After work finishes:
done_with_current.sh
Updates completed_at, archives to inbox/completed/, and prints status: COMPLETED, MAIL_WAITING, or NO_TASK.
Audit Trail and Header Lifecycle
The SwarmForge handoff protocol captures complete provenance through header evolution:
| Stage | Header Added | Script Responsible |
|---|---|---|
| Creation | id, from, created_at, type |
swarm_handoff.sh |
| Delivery | recipient, enqueued_at |
handoffd.bb |
| Consumption | dequeued_at |
ready_for_next_*.sh |
| Completion | completed_at |
done_with_current_*.sh |
This immutable progression enables forensic reconstruction of any handoff's journey.
Design Goals and Protocol Guarantees
The SwarmForge handoff protocol achieves four primary objectives:
- Durability — Handoff files survive process restarts; filesystem is the single source of truth
- Auditability — Complete timestamp chain from creation through completion
- Agent Simplicity — No tmux socket manipulation, no direct git operations, minimal API surface
- Extensibility — New message types via header schema extension and daemon validation updates
Atomic operations prevent duplicate deliveries even if handoffd crashes mid-transaction. State transitions use move/rename semantics that are atomic on POSIX filesystems.
Summary
- SwarmForge handoff protocol replaces fragile log-based coordination with durable file-system queues
- Four directory states (
outbox/,sent/,failed/,inbox/with subfolders) provide clear handoff lifecycle management swarm_handoff.shis the only valid entry point for creating handoffs; it enforces schema and performs atomic writeshandoffd.bbdelivers handoffs idempotently, injecting delivery metadata and sending tmux notifications- Helper scripts (
ready_for_next.sh,done_with_current.sh) abstract queue state machines from agent logic - Complete audit trail through headers:
created_at→enqueued_at→dequeued_at→completed_at
Frequently Asked Questions
How does the SwarmForge handoff protocol prevent duplicate deliveries?
The daemon uses the id header as a deduplication key. Before copying to any inbox, handoffd.bb checks if a handoff with that id already exists in the recipient's new/, in_process/, or completed/ folders. Combined with atomic file moves and POSIX rename semantics, this ensures exactly-once delivery semantics even across daemon restarts.
What happens if a handoff fails to deliver?
Failed deliveries move the source file from outbox/ to failed/ with an appended error reason. The original handoff remains intact for manual inspection or retry. Recipients that are temporarily unreachable do not block delivery to other recipients—each copy operation is independent.
Can agents send handoffs to multiple recipients simultaneously?
Yes. The filename to field and internal to header support comma-separated recipient lists. The daemon iterates through recipients, creating independent copies with individualized recipient headers. Each recipient receives their own enqueued_at timestamp reflecting actual delivery time.
How do agents know when new handoffs arrive?
The handoffd daemon sends a generic tmux message to the recipient's pane: "You have new handoff mail. If idle, run ready_for_next.sh." Agents poll by running ready_for_next.sh when convenient—there is no forced interrupt or callback mechanism, keeping agent logic simple and synchronous.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →