How `ready_for_next.sh` Dispatches to Task vs Batch Helpers in Swarm-Forge

ready_for_next.sh delegates to a Babashka script that inspects the current role's receive mode, then dispatches to either ready_for_next_task.sh for single-task processing or ready_for_next_batch.sh for batch processing.

The ready_for_next.sh dispatcher is a critical orchestration component in the swarm-forge project by Uncle Bob. This shell-to-Babashka dispatch pattern enables clean separation between task-oriented and batch-oriented work handoffs, with the routing decision determined dynamically at runtime based on role configuration.

The Dispatch Chain: From Shell to Helper

The execution flow follows a consistent four-step pattern that keeps the shell layer thin and pushes logic into Clojure-based Babashka scripts.

Step 1: Shell Entry Point

ready_for_next.sh performs minimal setup before handing off control. It changes to its directory and executes ready_for_next.bb with any arguments passed through.

#!/bin/bash

# ready_for_next.sh - swarm-forge dispatcher entry point

cd "$(dirname "$0")"
bb ready_for_next.bb "$@"

This pattern appears throughout the swarm-forge scripts: shell wrappers provide portability while Babashka scripts contain the actual dispatch logic.

Step 2: Mode Detection via handoff-lib

Inside ready_for_next.bb, the handoff-lib library is loaded via require. This library exposes two essential functions:

  • handoff-lib/role — returns the current role name
  • handoff-lib/role-receive-mode — returns "task", "batch", or another configured value

The role's receive mode is the single source of truth for dispatch routing.

Step 3: Case-Based Dispatch

A case expression in ready_for_next.bb matches the receive mode to the appropriate helper:

;; ready_for_next.bb - core dispatch logic
(ns ready-for-next
  (:require [handoff-lib :as h]))

(defn run-helper! [script]
  (babashka.process/exec script))

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

The dispatch is exhaustive and strict — any unrecognized mode triggers an immediate exit with code 2, surfacing configuration errors rather than failing silently.

Step 4: Helper Execution

Selected helpers are launched via babashka.process/exec, which replaces the current process. Both helpers follow the same pattern as the parent:

Helper Script Purpose Underlying Implementation
ready_for_next_batch.sh Batch work handoffs ready_for_next_batch.bb
ready_for_next_task.sh Single-task handoffs ready_for_next_task.bb

Each helper is itself a thin wrapper, maintaining architectural consistency across the codebase.

Key Source Files and Their Responsibilities

Understanding the file structure clarifies where dispatch logic resides versus where execution happens:

Running the Dispatcher

Invoke the dispatcher directly from the repository root:


# Execute with default role resolution

./swarmforge/scripts/ready_for_next.sh

# Pass arguments through to the underlying handlers

./swarmforge/scripts/ready_for_next.sh --verbose

The actual helper executed depends entirely on the current role's receive mode configuration in handoff_lib.bb.

Design Rationale: Why This Dispatch Pattern?

The swarm-forge architecture separates dispatch concerns from execution concerns for several maintainability benefits:

  • Role-driven configuration — Receive modes are data, not code
  • Minimal shell surface area — Easy to port or wrap
  • Explicit failure modes — Invalid modes halt immediately with diagnostic output
  • Symmetric helper structure — Task and batch paths share identical wrapper patterns

This design allows operators to change processing semantics by modifying role configuration rather than shell scripts.

Summary

  • ready_for_next.sh is a thin shell wrapper that forwards to ready_for_next.bb
  • Dispatch routing depends on handoff-lib/role-receive-mode, which returns "task" or "batch"
  • A case expression in ready_for_next.bb selects and executes the appropriate helper
  • Invalid modes cause immediate termination with exit code 2
  • Both task and batch helpers maintain architectural consistency with shell wrappers around Babashka implementations

Frequently Asked Questions

How does ready_for_next.sh know which mode to use?

The mode is not passed as an argument or hardcoded. Instead, ready_for_next.bb calls handoff-lib/role to determine the current role, then queries handoff-lib/role-receive-mode with that role name. This function returns a string that drives the case dispatch.

What happens if a role has an invalid receive mode?

The case expression includes a fallback clause that calls babashka.core/exit! with code 2 and an error message containing the invalid mode and role name. This prevents silent misrouting and surfaces configuration problems immediately.

Can I run the batch or task helpers directly?

Yes, though this bypasses the role-based dispatch logic. Both ready_for_next_batch.sh and ready_for_next_task.sh are executable independently. However, direct invocation is generally discouraged in production since it ignores the role's configured receive mode.

Why use Babashka for dispatch instead of pure Bash?

Babashka provides structured data handling, a case expression with exhaustiveness checking, and reusable library code via require. The handoff-lib abstraction would be significantly more verbose and error-prone to replicate in shell, particularly for role and mode resolution logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →