SwarmForge Handoff Directory Layout: A Deep Dive into the File-Based Queue System
SwarmForge stores every handoff message in a durable, file-based queue located at .swarmforge/handoffs/ inside each agent's worktree, separating outbound messages in outbox/ from inbound messages in inbox/ with dedicated audit folders for sent, failed, and completed work.
The SwarmForge handoff directory structure enables reliable inter-agent communication through atomic filesystem operations. According to the unclebob/swarm-forge source code, this design guarantees durability, auditability, and clear ownership boundaries between agents and the handoff daemon.
The Core Directory Structure
The handoff layout is formally specified in [swarmforge/handoff-protocol.md](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/handoff-protocol.md#L24-L38). Each agent's worktree contains a hidden .swarmforge/handoffs/ directory with this hierarchy:
.swarmforge/handoffs/
├── outbox/ # Handoffs the agent wants to send
│ └── tmp/ # Staging area for drafts (ignored by the daemon)
├── sent/ # Successfully delivered outbound handoffs
├── failed/ # Outbound handoffs that could not be delivered
└── inbox/
├── new/ # Incoming handoffs waiting to be processed
├── in_process/ # Handoffs currently being worked on
└── completed/ # Handoffs that have been finished
This structure separates concerns by direction: outbound folders (outbox/, sent/, failed/) for messages the local agent originates, and inbound folders (inbox/new/, inbox/in_process/, inbox/completed/) for messages received from other agents.
Outbound Handoff Flow
Creating and Queueing Outbound Handoffs
Agents prepare handoffs in the staging area before atomic enqueueing. The [swarm_handoff.sh](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/swarm_handoff.sh) script handles validation and queuing:
# Inside an agent worktree - create a draft in tmp/
echo "type: git_handoff" > ./tmp/handoff.txt
echo "to: cleaner" >> ./tmp/handoff.txt
echo "priority: 50" >> ./tmp/handoff.txt
echo "task: task-1-cave-setup" >> ./tmp/handoff.txt
echo "commit: a1b2c3d9e8" >> ./tmp/handoff.txt
# Validate and atomically move to outbox/
swarm_handoff.sh ./tmp/handoff.txt
The swarm_handoff.sh script performs two critical operations:
- Validates the handoff file format and recipient
- Atomically renames the file from
outbox/tmp/tooutbox/
Atomic renaming prevents partial writes from being picked up by the daemon.
Daemon Processing and Audit Trails
The handoffd.bb daemon watches outbox/ and executes the delivery protocol:
- Validates the handoff file
- Copies it to each recipient's
inbox/new/directory - Sends a tmux wake-up signal to notify the recipient
- Moves the original file to
sent/on success, orfailed/on error
This provides immutable audit trails: sent/ confirms delivery, while failed/ enables retry logic or dead-letter inspection.
Inbound Handoff Flow
Consuming New Tasks
Agents process incoming work through helper scripts in [ready_for_next.sh](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/ready_for_next.sh):
# Single-task mode
ready_for_next.sh # Dispatches to ready_for_next_task.sh
# Batch mode
ready_for_next_batch.sh
These scripts:
- Select the highest-priority file from
inbox/new/ - Atomically move it to
inbox/in_process/ - Return the file path to the caller
The atomic move prevents race conditions when multiple agent instances compete for work.
Completing Tasks
After processing, [done_with_current.sh](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/done_with_current.sh) finalizes the handoff:
done_with_current.sh # Dispatches to done_with_current_task.sh
# Moves file from inbox/in_process/ to inbox/completed/
The inbox/completed/ folder preserves a complete processing history, enabling debugging and compliance verification.
Design Guarantees
The SwarmForge handoff directory structure delivers three architectural properties:
- Durability — All state persists on disk; system crashes cannot lose pending work
- Auditability —
sent/,failed/, andcompleted/folders provide complete handoff lifecycle visibility - Clear ownership — The daemon exclusively manages
outbox/; agents interact only with their owninbox/through provided scripts
This separation eliminates entire classes of coordination bugs: agents cannot accidentally corrupt the outbound queue, and the daemon never writes to inbox processing folders.
Directory Layout Visualization
$ tree -a .swarmforge/handoffs
.swarmforge/handoffs
├── outbox
│ └── tmp
├── sent
├── failed
└── inbox
├── new
├── in_process
└── completed
8 directories, 0 files
Summary
.swarmforge/handoffs/lives in each agent's worktree as the root of all handoff stateoutbox/tmp/stages drafts before atomic enqueueing viaswarm_handoff.shoutbox/,sent/,failed/handle outbound message lifecycle with daemon ownershipinbox/new/,inbox/in_process/,inbox/completed/manage inbound work with agent ownership- Atomic file moves at every transition guarantee consistency without locks
- Audit folders (
sent/,failed/,completed/) enable operational debugging and compliance
Frequently Asked Questions
What happens if the handoff daemon crashes during delivery?
The daemon's atomic copy-then-move protocol ensures durability. If it crashes after copying to inbox/new/ but before moving to sent/, the restart will detect the orphaned outbox/ file and retry. Recipients may receive duplicates, which they must handle idempotently per the handoff protocol specification.
Can multiple agent instances safely share one inbox?
Yes, through atomic filesystem operations. The ready_for_next_task.sh helper uses atomic renames when moving files from inbox/new/ to inbox/in_process/. Only one instance succeeds per file; others receive ENOENT and retry with the next available handoff.
Why use a tmp/ subdirectory instead of writing directly to outbox/?
The staging area prevents the daemon from observing partially-written handoffs. Agents compose multi-line handoff files incrementally; the daemon only processes complete, validated files after swarm_handoff.sh performs the atomic rename from tmp/ to outbox/.
How does SwarmForge handle handoff priority?
Files in inbox/new/ are processed by lexical filename order. Agents encode priority in the filename prefix (e.g., 050-task-1-cave-setup.handoff for priority 50). The ready_for_next_* scripts select the lexicographically first file, effectively implementing priority queue semantics without additional indexing structures.
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 →