SwarmForge Handoff Directory Structure: A Complete Guide to the Inbox/Outbox Protocol

SwarmForge uses a dedicated .swarmforge/handoffs/ directory with fixed subdirectories (outbox/, inbox/, sent/, failed/) to enable reliable, audit-trailed work exchanges between AI agents without direct socket communication.

The SwarmForge handoff directory structure implements a durable, filesystem-based message queue that replaces traditional inter-agent networking. Each agent's worktree contains a single hidden directory where all task exchanges are staged, delivered, and archived. This design ensures restart-safe processing and deterministic order guarantees, as specified in swarmforge/handoff-protocol.md【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/handoff-protocol.md#L24-L38】.

Root Handoff Directory Location

Every agent operates within a worktree root containing:

.swarmforge/
└── handoffs/
    ├── outbox/
    ├── sent/
    ├── failed/
    └── inbox/

The .swarmforge/handoffs/ path is hardcoded and enforced by the handoff daemon (handoffd.bb) and all helper scripts. No configuration overrides this location.

Outbox Subdirectories

The outbox/ branch handles outbound handoffs created by the local agent.

outbox/

Holds validated .handoff files ready for delivery. Files here follow strict naming conventions:

00_20260615T140531Z_000042_from_architect_to_coder.handoff
└┬┘ └─────────┬────────┘ └─┬─┘ └──┬──┘ └──┬───┘
 │            │            │      │       └─ recipient agent
 │            │            │      └─ sender agent
 │            │            └─ sequence number
 │            └─ UTC timestamp
 └─ priority (00-99, lower = higher priority)

outbox/tmp/

A private scratch area for atomic file creation. The handoff daemon ignores this directory entirely. Scripts like swarm_handoff.sh write handoff contents here first, then perform an atomic move to outbox/ once fully formed. This prevents the daemon from processing incomplete files.

Delivery Archive Directories

After processing, outbound handoffs land in one of two terminal states.

sent/

Contains successfully delivered handoffs. The daemon (handoffd.bb) moves the original file here after:

  • Validating the handoff structure
  • Copying it to every recipient's inbox/new/
  • Adding audit headers (recipient, enqueued_at)

failed/

Stores undeliverable handoffs with diagnostic context. Common failure modes include:

  • Validation errors (malformed headers)
  • Missing or invalid recipient agents
  • Permission or disk space issues

Each failed handoff retains its original content plus error annotations.

Inbox Subdirectories

The inbox/ branch manages incoming work from other agents.

inbox/new/

The task queue for unclaimed handoffs. Agent helper scripts scan this directory to find the next available work item. The ready_for_next.sh entry point dispatches to ready_for_next_task.sh or ready_for_next_batch.sh based on configuration.

Selection uses priority-then-FIFO ordering: lower numeric prefixes process first; ties resolve by arrival time.

inbox/in_process/

Holds the currently active handoff (or batch directory in batch mode). When an agent claims work:

ready_for_next.sh

# Output:

# TASK: .swarmforge/handoffs/inbox/in_process/00_20260615T140531Z_000042_from_architect_to_coder.handoff

# FROM: architect

# TYPE: git_handoff

# PRIORITY: 00

# TASK_NAME: task-1-cave-setup

The atomic move from inbox/new/ to inbox/in_process/ prevents double-claiming.

inbox/completed/

Archive of finished handoffs. The done_with_current.sh script (dispatching to done_with_current_task.sh) finalizes the active work:

  • Adds completed_at timestamp
  • Records processing outcome
  • Moves file to inbox/completed/

Complete Directory Tree Example

.swarmforge/
└── handoffs/
    ├── outbox/
    │   ├── tmp/
    │   ├── 00_20260615T140531Z_000042_from_architect_to_coder.handoff
    │   └── 01_20260615T140545Z_000043_from_architect_to_tester.handoff
    ├── sent/
    │   └── 00_20260615T140500Z_000041_from_pm_to_architect.handoff
    ├── failed/
    │   └── 02_20260615T140600Z_000044_from_architect_to_invalid_agent.handoff.err
    └── inbox/
        ├── new/
        │   ├── 00_20260615T140548Z_000045_from_tester_to_architect.handoff
        │   └── 01_20260615T140555Z_000046_from_pm_to_architect.handoff
        ├── in_process/
        │   └── 00_20260615T140531Z_000042_from_architect_to_coder.handoff
        └── completed/
            ├── 00_20260615T140400Z_000040_from_coder_to_tester.handoff
            └── 01_20260615T140420Z_000039_from_tester_to_pm.handoff

Handoff File Format

Files stored throughout this structure follow a YAML frontmatter + body format:

id: 20260615T140531Z_000042_from_architect
from: architect
to: coder
recipient: coder
priority: 00
type: git_handoff
role: architect
task: task-1-cave-setup
commit: a1b2c3d9e8
created_at: 2026-06-15T14:05:31Z
enqueued_at: 2026-06-15T14:05:32Z

Re-read your role and constitution.

merge_and_process.sh architect a1b2c3d9e8

Headers are space-separated key-value pairs. The blank line separates metadata from payload. The enqueued_at field is added by the daemon during delivery—not present on creation.

Key Scripts Enforcing Structure

Script Path Function
swarm_handoff.sh swarmforge/scripts/swarm_handoff.sh Creates handoffs in outbox/tmp/, validates, atomically moves to outbox/
handoffd.bb swarmforge/scripts/handoffd.bb Daemon watching outbox/, delivering to inbox/new/, archiving to sent/ or failed/
ready_for_next.sh swarmforge/scripts/ready_for_next.sh Entry point for claiming next task; dispatches to task/batch variants
ready_for_next_task.sh swarmforge/scripts/ready_for_next_task.sh Selects from inbox/new/, atomically moves to inbox/in_process/
done_with_current.sh swarmforge/scripts/done_with_current.sh Finalizes active work, moves to inbox/completed/

These scripts embed the directory structure as constants—no runtime configuration exists to alter paths.

Summary

  • Root location: .swarmforge/handoffs/ per worktree, enforced by all scripts
  • Outbound flow: outbox/tmp/ → outbox/ → sent/ or failed/ (daemon-managed)
  • Inbound flow: inbox/new/ → inbox/in_process/ → inbox/completed/ (agent-managed)
  • Atomicity: outbox/tmp/ and atomic moves prevent partial file processing
  • Audit trail: Headers added at each stage (enqueued_at, completed_at) enable full traceability

Frequently Asked Questions

Where does SwarmForge store handoff files between agents?

Handoff files reside in .swarmforge/handoffs/ within each agent's worktree. This hidden directory contains subdirectories for outbound drafts (outbox/), delivery archives (sent/, failed/), and inbound task queues (inbox/). The structure is fixed across all agent types and enforced by the handoff daemon and helper scripts.

What prevents the daemon from processing incomplete handoff files?

The outbox/tmp/ subdirectory serves as a private staging area. Scripts write handoff content here first and only move the completed file to outbox/ once fully formed. The daemon watches only outbox/, never outbox/tmp/, ensuring atomic handoff creation without partial file hazards.

How does an agent claim the next available task?

Agents invoke ready_for_next.sh, which dispatches to ready_for_next_task.sh or ready_for_next_batch.sh. These scripts scan inbox/new/, select by priority-then-FIFO ordering, and perform an atomic move to inbox/in_process/. This prevents race conditions when multiple agent instances attempt to claim the same work item.

What happens to handoffs that fail delivery?

Failed handoffs move to failed/ with diagnostic extensions (.err files). Common causes include validation errors, missing recipients, or system resource issues. Unlike sent/, the failed/ directory preserves error context to enable debugging and potential reprocessing without original data loss.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →