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

> Easily implement the handoff protocol with swarmhandoff.sh. Parse, validate, and queue .handoff files for delivery to recipient roles directly from your worktree.

- Repository: [Robert C. Martin/swarm-forge](https://github.com/unclebob/swarm-forge)
- Tags: how-to-guide
- Published: 2026-09-01

---

**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](https://github.com/unclebob/swarm-forge) enables structured work transfer between project roles (architect, specifier, coder, cleaner, archiver). The [`swarmhandoff.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmhandoff.sh) script—implemented in [`swarmforge/scripts/swarm_handoff.sh`](https://github.com/unclebob/swarm-forge/blob/main/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`](https://github.com/unclebob/swarm-forge/blob/main/swarmhandoff.sh) with complete technical details from the source code.

## What [`swarmhandoff.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmhandoff.sh) Does

The script at [`swarmforge/scripts/swarm_handoff.sh`](https://github.com/unclebob/swarm-forge/blob/main/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

```text
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

```bash

# 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

```text
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`](https://github.com/unclebob/swarm-forge/blob/main/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:

```text
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`](https://github.com/unclebob/swarm-forge/blob/main/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

```bash
$ 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`](https://github.com/unclebob/swarm-forge/blob/main/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`](https://github.com/unclebob/swarm-forge/blob/main/swarmhandoff.sh) does not perform direct delivery.

## Complete Workflow Example

```bash

# 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`](https://github.com/unclebob/swarm-forge/blob/main/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`](https://github.com/unclebob/swarm-forge/blob/main/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.