# How Propagation Tokens Work in SwarmForge: `forward-only`, `back-one`, and `back-all` Explained

> Understand SwarmForge propagation tokens like forward-only back-one and back-all. Learn how they control handoffs after role processing for efficient workflow management.

- Repository: [Robert C. Martin/swarm-forge](https://github.com/unclebob/swarm-forge)
- Tags: deep-dive
- Published: 2026-08-29

---

**Propagation tokens in SwarmForge control how handoffs are distributed after a role finishes processing, with three modes: `forward-only` (default, next role only), `back-one` (next role plus immediate predecessor), and `back-all` (next role plus all preceding roles).**

In SwarmForge, a **pack** is a sequence of roles (or "windows") that process work in stages. When one role hands off a task to the next, the **propagation token** determines exactly which roles receive copies of that handoff. This mechanism—implemented in the `unclebob/swarm-forge` open-source project—enables flexible workflow patterns beyond simple linear pipelines.

---

## What Propagation Tokens Control

Each role in a pack can declare a propagation token that governs **handoff distribution**. The token answers one question: after this role finishes, who else should see the result?

| Token | Behavior | Typical Use Case |
|-------|----------|----------------|
| **`forward-only`** | Handoff sent **only to the next role**; earlier roles receive nothing | Standard linear flow (e.g., `coder → cleaner → architect`) |
| **`back-one`** | Handoff sent to **next role** and **immediate predecessor** | Verification loops or quick back-and-forth between adjacent roles |
| **`back-all`** | Handoff sent to **next role** and **broadcast to all earlier roles** | Final QA or reporting steps that must notify everyone upstream |

If omitted, `forward-only` is the default.

---

## Where Propagation Tokens Are Parsed

The parser resides in **`swarmforge/scripts/swarmforge.bb`**, where the `receive-fields` function extracts the token from window configuration lines.

First, the valid tokens are defined as a Clojure set:

```clojure
(def propagation-modes #{"forward-only" "back-one" "back-all"})

```

Then `receive-fields` parses the trailing arguments after the required window parameters:

```clojure
(defn receive-fields [trailing]
  (let [[receive-mode after-receive]
        (if (receive-modes (first trailing))
          [(first trailing) (rest trailing)]
          ["task" trailing])
        [propagation extra]
        (if (propagation-modes (first after-receive))
          [(first after-receive) (rest after-receive)]
          ["forward-only" after-receive])]
    [receive-mode propagation extra]))

```

The parser checks if the next token matches `propagation-modes`. If not, it substitutes `"forward-only"` as the default. This ensures every role has a valid propagation setting at runtime.

---

## How Tokens Are Stored at Runtime

After parsing, the propagation value is persisted to **`.swarmforge/roles.tsv`**—the authoritative runtime configuration for launched packs.

The function `role-propagation` in **`swarmforge/scripts/handoff_lib.bb`** retrieves this value:

```clojure
(defn role-propagation [role-name]
  (let [mode (nth (role-row role-name) 7 "")]
    (if (str/blank? mode) "forward-only" mode)))

```

This makes `.swarmforge/roles.tsv` the **single source of truth** that handoff scripts consult when determining recipient lists.

---

## How Tokens Influence Handoff Creation

When a role emits a handoff, **`swarmforge/scripts/swarm_handoff.bb`** uses the sender's propagation mode to compute destinations:

```clojure
(case (handoff-lib/role-propagation sender)
  "forward-only"  …   ; only the next role receives the handoff
  "back-one"      …   ; next role + immediate predecessor
  "back-all"      …)  ; next role + all earlier roles

```

The resulting recipient list is encoded in the handoff's `to:` header. The handoff daemon then places copies in each target role's inbox directory, guaranteeing that every designated role receives an identical copy of the handoff file.

---

## End-to-End Example: Coder → Cleaner → Architect

Consider a three-role pack with different propagation settings per role:

| Configuration Line | Parsed Propagation |
|--------------------|------------------|
| `window coder claude master forward-only` | `"forward-only"` — only `cleaner` receives |
| `window cleaner claude master back-one` | `"back-one"` — `architect` **and** `coder` receive |
| `window architect claude master back-all` | `"back-all"` — `architect` receives, plus broadcast to `cleaner` and `coder` |

When `cleaner` (with `back-one`) finishes:

```clojure
;; Parsed configuration for cleaner
{:role "cleaner"
 :agent "claude"
 :receive-mode "task"
 :propagation "back-one"
 :extra-args nil}

```

`swarm_handoff.bb` creates two handoff copies:

- One addressed `to: architect` — the normal forward direction
- One addressed `to: coder` — the backward copy to the immediate predecessor

The daemon delivers both to their respective inboxes. Each role then processes its copy according to its own **receive mode** (`task` or `batch`).

---

## Key Implementation Files

| File | Responsibility |
|------|--------------|
| `swarmforge/scripts/swarmforge.bb` | Defines `propagation-modes` set and parses tokens via `receive-fields` |
| `swarmforge/scripts/handoff_lib.bb` | Reads stored tokens via `role-propagation` from `.swarmforge/roles.tsv` |
| `swarmforge/scripts/swarm_handoff.bb` | Switches on token value to build recipient lists at handoff time |
| [`swarmforge/handoff-protocol.md`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/handoff-protocol.md) | Documents token semantics and default behavior |

---

## Summary

- **Propagation tokens** are per-role settings that control handoff distribution in SwarmForge packs
- **`forward-only`** (default) creates linear pipelines; **`back-one`** enables adjacent-role loops; **`back-all`** broadcasts to all upstream roles
- Tokens are parsed in `swarmforge.bb`, stored in `.swarmforge/roles.tsv`, and applied by `swarm_handoff.bb` using a `case` expression
- The mechanism supports complex workflows—verification loops, multi-party notifications, and hybrid patterns—without requiring pack reconfiguration

---

## Frequently Asked Questions

### What happens if I don't specify a propagation token for a role?

The parser automatically assigns `"forward-only"` as the default. This is hardcoded in `receive-fields` within `swarmforge.bb` and confirmed by the fallback logic in `role-propagation` within `handoff_lib.bb`.

### Can I use `back-one` or `back-all` on the first role in a pack?

Technically yes, but practically limited. `back-one` on the first role has no predecessor, so it behaves like `forward-only`. `back-all` similarly has no earlier roles to broadcast to. Both tokens still send to the next role normally.

### How does `back-all` differ from just listing multiple roles manually?

`back-all` dynamically targets **all roles defined before the current one in the pack order**, regardless of pack size or composition. This makes packs reusable: you can insert or remove roles without reconfiguring propagation settings. Manual recipient lists would require editing every role's configuration when the pack structure changes.

### Is the propagation token related to the receive mode (`task` vs `batch`)?

No—these are orthogonal settings. **Receive mode** controls *how* a role consumes incoming handoffs (individual tasks or batched queues). **Propagation token** controls *where* outgoing handoffs are sent. A role can combine any receive mode with any propagation token (e.g., `batch` receiving with `back-all` distribution).