How to Implement the Handoff Protocol Using `swarmhandoff.sh` in Swarm-Forge

Run swarmhandoff.sh <draft-file> from a role worktree to parse, validate, and queue a .handoff file for delivery to one or more recipient roles.

The handoff protocol in unclebob/swarm-forge enables structured work transfer between project roles (architect, specifier, coder, cleaner, archiver). The swarmhandoff.sh script—implemented in swarmforge/scripts/swarm_handoff.sh—serves as the primary entry point for creating these handoffs. This guide explains how to implement the handoff protocol using swarmhandoff.sh with complete technical details from the source code.

What swarmhandoff.sh Does

The script at swarmforge/scripts/swarm_handoff.sh is a thin wrapper that launches the Babashka script swarm_handoff.bb. Together they perform eight distinct operations:

  1. Load dependencies — imports handoff-lib.bb for Git and role utilities
  2. Parse the draft — extracts key-value headers from your draft file
  3. Fill missing fields — injects Git commit SHA, resolves task ID, sets default priority
  4. Validate the handoff — enforces constraints on roles, commits, duplicates, and board state
  5. Handle audit workflow — fingerprints the invocation and writes or re-queues audit records
  6. Write .handoff files — creates prioritized, timestamped files in the outbox
  7. Create reverse handoffs — for git_handoff type, generates upstream notifications
  8. Cleanup — deletes the draft and marks current task complete when applicable

Draft File Requirements

Draft files must reside in the worktree's tmp/ directory—the function require-worktree-tmp-draft! enforces this constraint. Only header lines are parsed; content after the first blank line is ignored.

Valid Draft Format

type: git_handoff
to: coder,cleaner
priority: 50
task: my-feature

Header Fields

Field Required Description
type Yes git_handoff or note
to Yes Comma-separated recipient role names
priority No Two-digit priority (00-99); defaults to 50
task Yes* Stable task name, ≤80 characters
message Yes* For note type, ≤80 characters

*Required field varies by type: task for git_handoff, message for note.

Auto-Populated Fields

For git_handoff type, prepare-headers automatically adds:

  • commit: — short SHA of HEAD in the sender's worktree (from git-root / git-common-dir helpers)
  • task_id: — resolved from the board or taken from draft

Running the Handoff Protocol

Step-by-Step Implementation


# Navigate to your role worktree

cd /path/to/coder-worktree

# Create a draft in the tmp/ directory

cat > ./tmp/login-feature-handoff.txt <<'EOF'
type: git_handoff
to: cleaner
priority: 30
task: login-feature
EOF

# Execute the handoff protocol

swarmhandoff.sh ./tmp/login-feature-handoff.txt

Expected Output

HANDOFF QUEUED: /home/user/.swarmforge/handoffs/outbox/30_20240901T123456_000001_from_coder_to_cleaner.handoff

The filename format is: <priority>_<timestamp>_<sequence>_from_<sender>_to_<recipients>.handoff

Validation and Error Handling

The validate function in swarmforge/scripts/swarm_handoff.bb performs comprehensive checks:

  • Required headers present — type, to, plus type-specific fields
  • Recipient roles known — verified against roles.txt via role-known?
  • Commit format valid — SHA format for git_handoff type
  • No duplicate active handoffs — prevents double-submission
  • Ancestry constraints — ensures logical task progression
  • Board-state compatibility — validates against current board

On validation failure, the script outputs:

HANDOFF INVALID:
  - Missing required field: task
  - Unknown recipient role: "designer"
Usage: swarmhandoff.sh <draft-file>

Audit and Idempotency

The handoff protocol implements audit-driven idempotency through invocation-fingerprint and submit-after-audit!:

  • Each invocation is fingerprinted from draft content and context
  • If the same handoff was previously audited, it is re-queued without duplicate audit records
  • New audits trigger user review prompts and increment the board's audit counter via pack_board.sh

This prevents accidental duplicate handoffs while maintaining complete audit history.

Reverse Handoffs for Git Operations

When type: git_handoff is used, write-handoff! automatically creates reverse handoffs for all upstream roles. These notify predecessors that their work has been advanced.

Example: Forward and Reverse Handoffs

$ swarmhandoff.sh ./tmp/payment.handoff
HANDOFF QUEUED: /home/me/.swarmforge/handoffs/outbox/40_20240901T140012_000042_from_architect_to_specifier_archiver.handoff
HANDOFF QUEUED: /home/me/.swarmforge/handoffs/outbox/00_20240901T140012_000042_from_architect_to_architect.handoff

The 00 priority reverse handoff targets the upstream architect role, created via reverse-roles calculation in handoff-lib.bb.

File Naming and Priority

The next-sequence function generates six-digit monotonic sequence numbers ensuring unique filenames even with identical priorities and timestamps. Priority determines processing order—lower numbers process first.

Priority conventions in Swarm-Forge:

  • 00 — System/reverse handoffs
  • 01-49 — Urgent work
  • 50 — Default priority
  • 51-99 — Deferred or background work

Key Helper Functions in handoff-lib.bb

Function Purpose
sender-role Determines current worktree's role
role-known? Validates role exists in roles.txt
git-root / git-common-dir Locate Git repository boundaries
commit-artifacts Lists changed files between base and current commit
next-sequence Generates unique six-digit sequence numbers
reverse-roles Calculates upstream roles for reverse propagation

Integration with Daemon Processing

Handoff files in .swarmforge/handoffs/outbox/ are consumed by handoffd.bb, the Swarm-Forge daemon. The daemon:

  • Moves task cards to recipient inboxes
  • Updates board state
  • Archives processed handoffs

Handoffs remain queued until the daemon processes them—swarmhandoff.sh does not perform direct delivery.

Complete Workflow Example


# 1. Verify current role and task status

$ sender-role
coder

# 2. Stage changes and commit

$ git add -A && git commit -m "Complete login form validation"

# 3. Create handoff draft

$ cat > ./tmp/handoff-to-cleaner.txt <<'EOF'
type: git_handoff
to: cleaner
priority: 20
task: login-form-validation
EOF

# 4. Execute handoff protocol

$ swarmhandoff.sh ./tmp/handoff-to-cleaner.txt
HANDOFF QUEUED: /home/user/.swarmforge/handoffs/outbox/20_20240901T143022_000015_from_coder_to_cleaner.handoff

# 5. Task automatically marked complete via done_with_current.sh

Summary

  • swarmhandoff.sh launches swarm_handoff.bb to implement the handoff protocol
  • Draft files must live in tmp/ and use key-value header syntax
  • git_handoff type auto-populates commit SHA and task ID, creates reverse handoffs
  • Validation enforces role existence, commit format, and board-state constraints
  • Audit system prevents duplicates via fingerprinting and submit-after-audit!
  • Output files use prioritized, sequenced naming in .swarmforge/handoffs/outbox/
  • Daemon handoffd.bb processes queued handoffs asynchronously

Frequently Asked Questions

What happens if I run swarmhandoff.sh from outside a role worktree?

The script fails with an error from require-worktree-tmp-draft!. Draft files must reside in ./tmp/ relative to a valid role worktree so that sender-role, git-root, and other context-dependent functions resolve correctly.

Can I hand off to multiple recipients at once?

Yes. Use comma-separated roles in the to: field: to: specifier,coder,cleaner. The script creates one .handoff file targeting all listed recipients, plus reverse handoffs for upstream roles when using git_handoff type.

Why does my handoff get rejected for "duplicate active handoff"?

The validate function checks for existing handoffs with identical task, sender, and recipient that haven't been processed yet. Either wait for handoffd.bb to process the pending handoff, or use a different task identifier if this represents genuinely new work.

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 →