# Batch vs Task Receive Mode in Swarm‑Forge Handoff Processing

> Understand the Swarm-Forge handoff processing difference: batch vs task receive modes. Learn how to process handoffs atomically or individually for efficient workflow management.

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

---

**Batch receive mode groups multiple handoffs into a single atomic unit processed together, while task receive mode handles each handoff individually with separate lifecycle tracking.**

Swarm‑Forge's handoff protocol lets each role declare a **receive mode** in [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf). This mode dictates how the runtime consumes inbound handoffs—either as isolated units or as grouped batches. The distinction directly impacts queue management, dashboard visualization, and completion semantics.

## Task Mode: One Handoff at a Time

**Task mode** is the default receive mode. When a role operates in this mode, the daemon treats every handoff as an independent card requiring individual processing.

The flow works as follows:

1. [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) executes and dispatches to [`ready_for_next_task.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_task.sh)
2. The helper scans `inbox/new/` for the earliest handoff file
3. That single file moves atomically to `inbox/in_process/`
4. The role processes it and calls [`done_with_current_task.sh`](https://github.com/unclebob/swarm-forge/blob/main/done_with_current_task.sh)

As implemented in `swarmforge/scripts/ready_for_next.bb` (lines 24‑28), the dispatcher reads the role's configured mode and routes accordingly:

```clojure
(let [role-name (handoff-lib/role)
      mode (handoff-lib/role-receive-mode role-name)]
  (case mode
    "batch" (run-helper! "ready_for_next_batch.sh")
    "task"  (run-helper! "ready_for_next_task.sh")
    (exit! 2 (str "INVALID_RECEIVE_MODE: " mode " for role " role-name))))

```

**Typical use case:** Simple pipelines where each handoff represents a complete unit of work—single‑step reviewers, isolated transformations, or any role where ordering between handoffs doesn't matter.

## Batch Mode: Atomic Group Processing

**Batch receive mode** aggregates multiple handoffs into a directory-based batch, processing them as one logical task with shared identity.

When [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) runs on a batch‑configured role:

1. The dispatcher invokes [`ready_for_next_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_batch.sh)
2. The helper scans `inbox/in_process/` for directories matching `batch_*`
3. It selects the first available batch (or sole batch when only one exists)
4. All handoffs in that batch move together with the same task name

The **top‑batch‑task**—the first handoff file in the batch directory—supplies the task name for the entire group. This logic resides in `swarmforge/scripts/swarm_handoff.bb` (lines 144‑152) and is exposed through `handoff_lib.bb` via the `role‑receive‑mode` function.

**Batch directory structure:**

```

.swarmforge/handoffs/inbox/in_process/
└─ batch_20260824T150500Z_000001/
    ├─ 10_20260824T150500Z_000001_from_sender_to_receiver.handoff
    ├─ 20_20260824T150600Z_000002_from_sender_to_receiver.handoff
    …

```

Completion requires [`done_with_current_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/done_with_current_batch.sh), signaling the entire batch is finished.

**Typical use case:** Roles that must handle several equal‑priority cards as a unified unit. The Swarm‑Forge reference configuration uses batch mode for the six‑pack roles: `cleaner`, `architect`, `hardender`, and `QA`.

## Configuration Syntax

The receive mode is declared in [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf) using the **window** directive, documented in `swarmforge/handoff‑protocol.md`:

```text
window <role> <agent> <worktree> [task|batch] [forward-only|back-one|back-all] [extra-cli-args…]

```

- **Receive mode** defaults to `task` when omitted
- **Propagation token** defaults to `forward-only` when omitted

**Example configuration for batch mode with backward propagation:**

```text
window cleaner codex cleaner batch back-all

```

This defines the `cleaner` role to receive handoffs in batch mode and propagate them backwards to all earlier windows. See the reference implementation in the repository's [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf) (lines 69‑85).

## Dashboard and UI Implications

The receive mode directly affects how Swarm‑Forge presents work:

| Aspect | Task Mode | Batch Mode |
|--------|-----------|------------|
| Dashboard rows | One row per handoff | One row per batch, expandable to show contained cards |
| Task identity | Derived from individual handoff filename | Derived from top‑batch‑task filename |
| Completion tracking | Individual card lifecycle | Batch‑level lifecycle |

Tests in `test/swarmforge/handoff_test.clj` verify these behaviors: batch‑mode senders block batch creation while outbound approval is active (lines 604‑607), and batch cards correctly share the same batch ID (lines 1365‑1366).

## Key Source Files

| File | Responsibility |
|------|--------------|
| `swarmforge/handoff‑protocol.md` | Specification of receive‑mode syntax and semantics |
| `swarmforge/scripts/swarmforge.bb` | Parses and validates the `receive-mode` token |
| `swarmforge/scripts/ready_for_next.bb` | Dispatches to appropriate helper based on mode |
| `swarmforge/scripts/handoff_lib.bb` | Provides `role-receive-mode` accessor |
| `test/swarmforge/handoff_test.clj` | Verifies batch‑mode blocking and ID sharing |

## Summary

- **Task mode** processes handoffs individually—simple, isolated, default behavior
- **Batch mode** groups handoffs into atomic directories with shared task identity
- The dispatcher in `ready_for_next.bb` routes to [`ready_for_next_task.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_task.sh) or [`ready_for_next_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_batch.sh) based on `role-receive-mode`
- Configuration uses optional third token in the `window` directive; defaults to `task`
- Batch mode affects dashboard aggregation and requires [`done_with_current_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/done_with_current_batch.sh) for completion

## Frequently Asked Questions

### What happens if I omit the receive mode in [`swarmforge.conf`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge.conf)?

The runtime defaults to **task mode**. As documented in `swarmforge/handoff‑protocol.md`, the window directive's fourth token is optional, and unconfigured roles behave as single‑handoff processors.

### Can I mix batch and task modes in the same pipeline?

Yes. Each role declares its own receive mode independently. A batch‑mode role can hand off to a task‑mode role and vice versa—the protocol translates between the representations automatically.

### How does batch mode affect handoff ordering?

Within a batch, handoffs maintain their original sequence based on filename timestamps. The **top‑batch‑task** (first file) determines the batch's task name, but all contained handoffs preserve their relative order during processing.

### Why would I choose batch mode over task mode?

Choose batch mode when your role must process multiple related handoffs as a single logical unit—when splitting them would create dashboard clutter or when atomic completion across several cards is required. The six‑pack roles (`cleaner`, `architect`, `hardender`, `QA`) demonstrate this pattern for handling equal‑priority work bundles.