# How the Swarm-Forge `ready_for_next.sh` Script Dispatches Between Task and Batch Modes

> Learn how the Swarm-Forge ready_for_next.sh script dispatches between task and batch modes by checking the SWARMFORGE_ROLE environment variable. Understand its delegation logic for efficient workflow management.

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

---

**The [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) script dispatches between task and batch modes by delegating to a Babashka script that reads the `SWARMFORGE_ROLE` environment variable, looks up its receive mode in `.swarmforge/roles.tsv`, and executes either [`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) accordingly.**

Swarm-Forge, an open-source multi-agent workflow framework created by Robert C. Martin ("Uncle Bob"), uses a role-based configuration system to determine how agents consume work. The [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) script serves as the primary entry point for agents requesting their next unit of work, with behavior dynamically determined by role configuration rather than hard-coded logic.

## The Shell Wrapper: [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh)

The [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) script is intentionally minimal. It acts as a thin launcher that hands off execution to the Babashka runtime.

This design keeps the dispatch logic in a more expressive language (Clojure/Babashka) while maintaining a simple shell interface for users and agent scripts.

## The Dispatch Logic in `ready_for_next.bb`

The actual mode detection and dispatching occurs in `swarmforge/scripts/ready_for_next.bb`. This script performs three sequential operations:

### Step 1: Locate the Project Root

The script walks up the directory tree to find the Git repository root, then validates that a `.swarmforge/roles.tsv` file exists. This establishes the configuration context for the entire dispatch operation.

### Step 2: Read the Role's Receive Mode

The `receive-mode` function (lines 44-56 in `ready_for_next.bb`) implements the core lookup logic:

- Extracts the `SWARMFORGE_ROLE` environment variable
- Parses `.swarmforge/roles.tsv` to find the matching role entry
- Returns the *receive mode* column value: either **task** or **batch**

According to the Swarm-Forge source code, this function handles TSV parsing and returns the mode as a string keyword used in the subsequent dispatch decision.

### Step 3: Dispatch to the Appropriate Helper

The `run-helper!` function (lines 60-64 in `ready_for_next.bb`) branches based on the receive mode:

- **task** mode → executes [`ready_for_next_task.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_task.sh)
- **batch** mode → executes [`ready_for_next_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_batch.sh)

This branching is the sole dispatch point; no other logic in the script path makes mode-dependent decisions.

## Visual Flow of the Dispatch Process

```text
ready_for_next.sh
   └─ exec bb ready_for_next.bb
               ├─ locate project root → verify .swarmforge/roles.tsv
               ├─ read SWARMFORGE_ROLE environment variable
               ├─ lookup receive mode (task|batch) in roles.tsv
               └─ invoke run-helper!:
                     • ready_for_next_task.sh  (if mode == "task")
                     • ready_for_next_batch.sh (if mode == "batch")

```

The two helper paths diverge significantly after this point:

| Mode | Helper Script | Behavior |
|------|-------------|----------|
| **task** | [`ready_for_next_task.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_task.sh) | Returns the next single handoff file immediately |
| **batch** | [`ready_for_next_batch.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_batch.sh) | Groups handoffs into a batch directory, returns batch metadata |

## Practical Usage Examples

### Configuring and Running a Task-Mode Role

```sh

# Define a role that processes individual tasks

export SWARMFORGE_ROLE=worker

# Verify role configuration in .swarmforge/roles.tsv:

# worker    some-model    task    /path/to/prompt

# Execute the dispatcher

./swarmforge/scripts/ready_for_next.sh

# → ready_for_next_task.sh launches ready_for_next_task.bb

# → prints path to next available handoff file

```

### Configuring and Running a Batch-Mode Role

```sh

# Define a role that collects batches of work

export SWARMFORGE_ROLE=collector

# Verify role configuration in .swarmforge/roles.tsv:

# collector    some-model    batch    /path/to/prompt

# Execute the dispatcher

./swarmforge/scripts/ready_for_next.sh

# → ready_for_next_batch.sh launches ready_for_next_batch.bb

# → creates batch directory, moves matching handoffs, prints batch info

```

The batch implementation in `ready_for_next_batch.bb` (lines 12-47) handles directory creation, file selection, and metadata generation, making it substantially more complex than the task path.

## Key Implementation Details

- **No hard-coded roles**: The `ready_for_next.bb` script contains no preset knowledge of which roles use which mode; all decisions flow from `roles.tsv`
- **Environment-driven**: The `SWARMFORGE_ROLE` variable is the only runtime input affecting dispatch behavior
- **Consistent interface**: Both helpers present the same stdout contract to callers, despite vastly different internal implementations

## Summary

- [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh) is a shell wrapper that launches `ready_for_next.bb` via Babashka
- Dispatch between task and batch modes is determined by the `receive-mode` function reading `.swarmforge/roles.tsv`
- The `run-helper!` function executes either [`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 the configured mode
- Task mode returns single handoffs; batch mode aggregates multiple handoffs with metadata
- All behavior is configuration-driven through the `SWARMFORGE_ROLE` environment variable and `roles.tsv`

## Frequently Asked Questions

### What happens if `SWARMFORGE_ROLE` is not set?

The `receive-mode` function will fail to find a matching entry in `roles.tsv`, causing the dispatch to error before any helper script executes. The script expects this environment variable to be explicitly defined.

### Can a role switch between task and batch modes dynamically?

No. The receive mode is static configuration stored in `.swarmforge/roles.tsv`. Changing a role's mode requires editing this file and restarting any running agents. The `ready_for_next.bb` script reads this configuration fresh on every invocation.

### Where is the actual task-selection logic implemented?

The task-specific selection logic resides in `ready_for_next_task.bb` (called via [`ready_for_next_task.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next_task.sh)), not in the dispatcher. The dispatcher's only responsibility is choosing which helper to execute based on the role's configured receive mode.

### Is there performance overhead to this two-layer dispatch?

Minimal. The shell wrapper adds negligible overhead, and the Babashka startup is the dominant cost. The configuration lookup in `roles.tsv` is a simple file parse; no network or database operations are involved.