# How the Two-Pack Workflow Functions in SwarmForge

> Understand SwarmForge's two-pack workflow, its coder and cleaner roles, and how tasks move through this minimal agent pipeline for efficient code management.

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

---

**The two-pack workflow is SwarmForge's minimal agent pipeline with two roles—coder and cleaner—where tasks flow coder → cleaner → Done via file-based git handoffs and a terminal broadcast mechanism.**

SwarmForge is an open-source agent orchestration framework by Robert C. Martin (unclebob) that manages software development tasks through structured multi-agent workflows. The **two-pack** is the smallest of three available pack templates, designed for rapid backend development with minimal overhead. This article explains exactly how the two-pack workflow operates, from pack definition to terminal handoff completion.

## Two-Pack Roles and Responsibilities

The two-pack workflow consists of exactly two specialized agent roles:

- **Coder**: Implements requested behavior using test-driven development (TDD) and unit tests.
- **Cleaner**: Reviews the coder's work for code quality (CRAP score, DRY violations, architectural refactoring) and returns a merge-only copy to the coder.

The task lifecycle is linear: **coder → cleaner → Done**. There are no additional handoffs or review stages. The cleaner's final action is always a `git_handoff` back to the coder, which serves as the **terminal broadcast** that marks the card complete.

## Pack Definition and Configuration

The two-pack lives on its own branch and is registered in `forge.bb`:

```clojure
;; swarmforge/scripts/forge.bb
(def pack-names ["two-pack" "four-pack" "six-pack"])

```

The default [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf) configures propagation behavior for the cleaner role:

```text
cleaner batch back-one

```

This directive tells SwarmForge that the **cleaner consumes handoffs in batches** and **copies a merge-only version back to the previous window** (the coder). The `back-one` token is critical: it creates a merge-only copy without advancing the card state. Only the explicit terminal broadcast moves the card to Done.

Source: **[forge.bb](/blob/main/swarmforge/scripts/forge.bb#L8-L16)**

## The Handoff Protocol

All inter-agent communication in SwarmForge happens through ordinary files under `.swarmforge/handoffs`. The two-pack workflow follows this exact sequence:

1. **Coder creates a handoff** using [`swarm_handoff.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarm_handoff.sh).
2. **Handoff daemon (`handoffd.bb`)** validates the draft, queues it, and delivers to the cleaner's inbox.
3. **Cleaner processes the batch** via [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) → [`ready_for_next_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_batch.sh).
4. **Cleaner completes work** with [`done_with_current_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/done_with_current_batch.sh).
5. **Terminal broadcast** (`to: coder`) moves the card to **Done**.

Source: **[handoff-protocol.md](/blob/main/swarmforge/handoff-protocol.md#L169-L187)**

### Agent Execution Loop

Agents in the two-pack follow a strict five-step loop defined in the protocol:

```text
1. ready_for_next.sh  → selects a handoff (task or batch)
2. role-specific script (e.g., ready_for_next_batch.sh)
3. work on the payload (implementation, review, refactoring)
4. done_with_current.sh → marks the handoff completed
5. if MAIL_WAITING → repeat, else stop

```

Source: **[handoff-protocol.md](/blob/main/swarmforge/handoff-protocol.md#L89-L108)**

## Creating a Two-Pack Project

The `get-swarm-forge` CLI installs all three packs under `packs/`. To instantiate a two-pack project:

```sh

# Pull SwarmForge main branch plus all pack branches

get-swarm-forge

# Start the dashboard

./swarm

# In the UI: click "New Project", name it, select "two-pack"

```

Behind the scenes, `forge.bb`'s `instantiate!` function calls `overlay-pack!` to copy shared scripts, constitution articles, and pack-specific files into `projects/<name>/`.

```clojure
;; Equivalent programmatic instantiation
(instantiate! root
  {:name "demo"
   :github false
   :pack "two-pack"
   :conf nil
   :mission "Demo of the quick backend workflow"})

```

Source: **[forge.bb](/blob/main/swarmforge/scripts/forge.bb#L52-L62)**

## Propagation Mechanics: back-one vs Terminal Broadcast

Understanding `back-one` is essential to understanding the two-pack workflow. When the cleaner's configuration specifies `back-one`:

- A **merge-only copy** of the cleaner's commit is delivered to the coder.
- The **card does not advance**—this is an intermediate handoff for review cycles.
- Only when the `to:` list contains **every other role** (here, just `coder`) does the card move to **Done**.

Source: **[handoff-protocol.md](/blob/main/swarmforge/handoff-protocol.md#L12-L20)**

## Complete Two-Pack Workflow Example

### Step 1: Coder Creates Initial Handoff

Draft file ([`tmp/handoff.txt`](https://github.com/unclebob/swarm-forge/blob/main/tmp/handoff.txt)):

```text
type: git_handoff
to: cleaner
priority: 50
task: demo-setup
commit: a1b2c3d9e8

```

Queue the handoff:

```sh
swarm_handoff.sh ./tmp/handoff.txt

# First call prints: AUDIT_REQUIRED

# Second identical call queues the handoff

```

Source: **[swarm_handoff.sh](/blob/main/swarmforge/scripts/swarm_handoff.sh)**

### Step 2: Cleaner Consumes the Batch

```sh

# In the cleaner's worktree

ready_for_next.sh

# Output: BATCH: <path>

# Cleaner performs code review, refactoring

# Then complete the batch:

done_with_current.sh

# Output: COMPLETED … MAIL_WAITING

```

The batch helper automatically groups all handoffs with matching priority into a single batch directory.

Source: **[ready_for_next.sh](/blob/main/swarmforge/scripts/ready_for_next.sh)**, **[ready_for_next_batch.sh](/blob/main/swarmforge/scripts/ready_for_next_batch.sh)**

### Step 3: Cleaner Sends Terminal Broadcast

The [`done_with_current_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/done_with_current_batch.sh) script auto-generates the final handoff:

```text
type: git_handoff
to: coder               # every other role = terminal condition

priority: 50
task: demo-setup
commit: a1b2c3d9e8

```

When the coder receives this handoff, the SwarmForge dashboard immediately marks the card **Done**.

## Key Implementation Files

| File | Purpose in Two-Pack Workflow |
|------|------------------------------|
| [`swarmforge/handoff-protocol.md`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/handoff-protocol.md) | Complete handoff type definitions, propagation tokens (`back-one`, terminal broadcast rules), agent loop specification |
| `swarmforge/scripts/forge.bb` | Pack installation, `pack-names` definition, `instantiate!` and `overlay-pack!` functions |
| `swarmforge/conf` (per-project) | Role declarations (`coder`, `cleaner`) and `cleaner batch back-one` configuration |
| [`swarmforge/scripts/swarm_handoff.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/swarm_handoff.sh) | Outbound handoff validation, audit gate enforcement, outbox writing |
| [`swarmforge/scripts/ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/ready_for_next.sh) | Handoff selection for individual tasks |
| [`swarmforge/scripts/ready_for_next_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/ready_for_next_batch.sh) | Batch selection for cleaner role |
| [`swarmforge/scripts/done_with_current_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/done_with_current_batch.sh) | Batch completion and terminal broadcast emission |
| [`README.md`](https://github.com/unclebob/swarm-forge/blob/main/README.md) (two-pack section) | High-level workflow description and role responsibilities |

## Summary

- The **two-pack workflow** is SwarmForge's minimal 2-role pipeline: **coder** implements with TDD, **cleaner** reviews and refactors.
- **Propagation** uses `back-one` for intermediate merge copies and **terminal broadcast** (`to: coder`) for completion.
- **All handoffs are files** under `.swarmforge/handoffs/`; no network protocols or manual coordination required.
- **Configuration is declarative** via [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf)—the `cleaner batch back-one` line defines the entire workflow behavior.
- **Daemon-driven execution**: `handoffd.bb` ensures reliable delivery; agents run [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) / [`done_with_current.sh`](https://github.com/unclebob/swarm-forge/blob/main/done_with_current.sh) in a loop.

## Frequently Asked Questions

### What makes the two-pack "minimal" compared to four-pack or six-pack?

The two-pack has exactly two roles and one handoff direction (coder → cleaner), while four-pack and six-pack add specialized roles like tester, documenter, and architect with more complex routing graphs. The two-pack optimizes for speed in backend development where automated testing and code quality are sufficient gates.

### Why does the cleaner send a handoff back to the coder instead of marking Done directly?

The terminal broadcast pattern ensures **every role has acknowledged completion**. In the two-pack, "every other role" is just the coder, so the cleaner's final handoff to coder satisfies this protocol requirement. This design scales consistently to larger packs where multiple roles must sign off.

### Can the two-pack workflow run without the handoff daemon?

No. The `handoffd.bb` daemon performs essential functions: validation, queuing, priority sorting, and inbox delivery. While handoffs are ordinary files, the daemon's orchestration is required for reliable, ordered processing. Manual file manipulation would break audit trails and sequence guarantees.

### What happens if the cleaner rejects the coder's implementation?

The cleaner's `back-one` propagation sends a merge-only copy with review comments. The coder receives this as a new handoff, modifies the implementation, and re-submits. This cycle repeats until the cleaner's terminal broadcast completes the card.