How SwarmForge Handles Agent Communication Through Its Layered Constitution System

SwarmForge manages agent communication through a three-layer constitution system: Core rules, Articles for behavioral sections, and Role configurations, enforced via file-based handoffs directed by shell scripts and a Babashka daemon.

SwarmForge, an open-source framework by Robert C. Martin (Uncle Bob), implements a novel approach to multi-agent coordination. Instead of direct API calls or message passing, agents communicate through a layered constitution system that defines their entire lifecycle—from startup through task execution to handoff completion. The system ensures deterministic, auditable, and language-agnostic agent interactions.

The Three Layers of the SwarmForge Constitution

SwarmForge's constitution is intentionally stacked to separate universal rules from specific behaviors and individual agent identities. This separation enables modifying workflows without touching core infrastructure, and adding new agent types without rewriting shared logic.

Core Layer: Universal Rules

The Core layer establishes mandatory directives that every agent must follow. Located in swarmforge/constitution.prompt, this single file commands all agents to read and obey every article in the swarmforge/constitution/articles/ directory.

This indirection is deliberate—it allows the runtime to evolve constitution content without modifying the core loader. The launcher (swarmforge.bb) reads this layer first, establishing the foundation for all subsequent configuration.

Articles Layer: Behavioral Specifications

The Articles layer contains specific functional domains, each implemented as a separate prompt file:

  • workflow.prompt — Worktree discipline, commit message conventions, and git workflow enforcement
  • handoffs.prompt — Handoff message formats, validation rules, priority schemes, and reserved headers
  • engineering.prompt — Shared tooling, environment setup, and engineering standards

Each article is plain text interpreted by agent LLMs. The handoff article is particularly critical—it specifies the type, to, priority, and task fields that agents must provide, plus the reserved headers (id, from, created_at, recipient, enqueued_at, completed_at) that only the infrastructure may inject.

Role Layer: Agent Identity and Configuration

The Role layer gives each agent its specific identity. Role files like swarmforge/roles/lieutenant.prompt configure:

  • Agent type — Which LLM or tool executes the role (Claude, Codex, etc.)
  • Worktree — Dedicated working directory for isolation
  • Receive mode — Whether the agent processes task (single) or batch (multiple) handoffs
  • Propagation — Whether and how handoffs forward to downstream agents

The role configuration is read last, allowing role-specific settings to reference or specialize article rules.

The Agent Communication Lifecycle

With the constitution loaded, SwarmForge agents communicate through a four-phase file-based protocol. All file paths use the worktree-relative .swarmforge/handoffs/ directory structure.

Phase 1: Outbound Handoff Creation

Agents initiate communication by drafting a handoff file in ./tmp/ and invoking swarm_handoff.sh:


# Agent creates draft handoff in temporary space

cat > ./tmp/handoff.txt <<'EOF'
type: git_handoff
to: cleaner
priority: 50
task: task-1-cave-setup
commit: a1b2c3d9e8
EOF

# Validate against handoffs.prompt rules and queue for delivery

swarm_handoff.sh ./tmp/handoff.txt

The validation script enforces article-defined rules: priority ranges, allowed types, and required fields. It injects infrastructure headers (id, from, created_at) that agents cannot forge, then moves the validated file to .swarmforge/handoffs/outbox/.

Phase 2: Daemon-Mediated Delivery

The handoff daemon (handoffd), a Babashka process, watches all outbox directories across worktrees. Per the protocol defined in swarmforge/handoff-protocol.md:

  1. Detects completed .handoff files in outbox/
  2. Copies to each recipient's inbox/new/ with injected recipient and enqueued_at headers
  3. Sends tmux wake-up message to notify waiting agents
  4. Archives original to outbox/sent/ (or failed/ on error)

This daemon provides the sole point of cross-agent file movement, creating an immutable audit trail through header injection.

Phase 3: Inbound Processing

Receiving agents poll for work via ready_for_next.sh, which dispatches based on the role's receive mode from .swarmforge/roles.tsv:


# Inside the cleaner agent's worktree

ready_for_next.sh

# Example output for task mode

TASK: .swarmforge/handoffs/inbox/in_process/00_20260615T140531Z_000042_from_architect_to_cleaner.handoff
FROM: architect
TYPE: git_handoff
PRIORITY: 00
TASK_NAME: task-1-cave-setup
PAYLOAD:
Re-read your role and constitution.

merge_and_process.sh architect a1b2c3d9

The ready_for_next_task.sh implementation (lines 91-102) atomically selects the highest-priority handoff from inbox/new/, moves it to inbox/in_process/, and prints the deterministic TASK: payload that agent LLMs consume.

Phase 4: Task Completion Signaling

After processing, agents call done_with_current.sh, which dispatches to mode-specific handlers:

done_with_current.sh

# Example output

COMPLETED: .swarmforge/handoffs/inbox/completed/00_20260615T140531Z_000042_from_architect_to_cleaner.handoff
MAIL_WAITING

The done_with_current_task.sh script (lines 22-30) adds completed_at, archives the handoff to inbox/completed/, and signals work state—MAIL_WAITING if more handoffs queue, NO_TASK if idle.

Constitution Enforcement in Code

The launcher that orchestrates this entire system resides in swarmforge/scripts/swarmforge.bb. Lines 378-424 implement the constitution loading sequence:

;; From swarmforge/scripts/swarmforge.bb
(defn start-agents [ctx]
  ;; Core prompt read first: swarmforge/constitution.prompt
  ;; Articles read second: swarmforge/constitution/articles/*.prompt
  ;; Role prompt read last: swarmforge/roles/{role}.prompt
  (doseq [role (map :role (:roles ctx))]
    (sh "tmux" "-S" (:tmux-socket ctx) "new-session"
        "-d" "-s" (:session ctx) "-n" "swarm")
    ;; Per-agent command constructed from merged constitution layers
    (sh "tmux" "-S" (:tmx-socket ctx) "send-keys"
        "-t" (str (:session ctx) ":swarm") 
        (str (agent-cmd role) " &") "C-m")))

The handoff_lib.bb helper library provides shared functions for role inference, header parsing, and TSV manipulation—ensuring consistent constitution interpretation across all shell scripts.

Key Design Benefits of Layered Agent Communication

Benefit Mechanism
Language agnosticism File-based handoffs let agents use any runtime (Clojure, Go, Python, shell)
Audit integrity Reserved headers injected only by daemon prevent spoofing
Workflow evolution Article updates apply to all agents on next launch
Role isolation Worktree + dedicated receive mode prevents cross-contamination
Deterministic ordering Priority fields + atomic in_process/ moves eliminate race conditions

Summary

  • SwarmForge's constitution has three layers: Core (universal rules), Articles (behavioral domains), and Role (per-agent configuration)
  • Communication is file-based: Agents exchange work through .handoff files in .swarmforge/handoffs/ subdirectories
  • The handoff daemon mediates all cross-agent transfers: Injecting headers and maintaining sent//failed/ archives
  • Shell scripts implement the protocol: swarm_handoff.sh, ready_for_next.sh, and done_with_current.sh enforce constitution rules at runtime
  • Constitution changes are hot-reloadable: Modified articles apply on agent restart without infrastructure changes

Frequently Asked Questions

How does the SwarmForge constitution ensure agents follow communication rules?

The constitution uses layered prompt injection: the Core mandates Article reading, Articles define valid handoff structures, and Roles specify receive behavior. The swarm_handoff.sh validation script enforces these rules before queueing, and the daemon enforces header integrity during delivery. Agents operate within tmux sessions where the merged constitution forms their system prompt.

What prevents agents from forging handoff metadata?

Reserved headers (id, from, created_at, recipient, enqueued_at, completed_at) are injected exclusively by infrastructure scripts and the daemon. The handoff article explicitly forbids agents from setting these fields. The daemon's central role as the only process writing to recipient inboxes creates a trusted boundary.

Can agents communicate across different programming languages?

Yes—the handoff protocol is language-agnostic. Agents need only write text files to ./tmp/ and invoke shell scripts. The deterministic TASK:/BATCH: output format from ready_for_next.sh lets any runtime parse work assignments. The reference implementation uses Babashka for orchestration but does not constrain agent implementation.

How do I add a new agent type with custom communication behavior?

  1. Create a role prompt in swarmforge/roles/{newrole}.prompt specifying receive mode (task or batch) and propagation rules
  2. Add the role to .swarmforge/roles.tsv with its worktree and configuration
  3. Restart agents via swarmforge.bb to reload the constitution layers
  4. Optionally modify Articles if the new role requires additional handoff types or workflow rules

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 →