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:
- Load dependencies — imports
handoff-lib.bbfor Git and role utilities - Parse the draft — extracts key-value headers from your draft file
- Fill missing fields — injects Git commit SHA, resolves task ID, sets default priority
- Validate the handoff — enforces constraints on roles, commits, duplicates, and board state
- Handle audit workflow — fingerprints the invocation and writes or re-queues audit records
- Write
.handofffiles — creates prioritized, timestamped files in the outbox - Create reverse handoffs — for
git_handofftype, generates upstream notifications - 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 ofHEADin the sender's worktree (fromgit-root/git-common-dirhelpers)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.txtviarole-known? - Commit format valid — SHA format for
git_handofftype - 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.shlaunchesswarm_handoff.bbto implement the handoff protocol- Draft files must live in
tmp/and use key-value header syntax git_handofftype 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.bbprocesses 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →