# How SwarmForge Handles Agent Communication Through Its Layered Constitution System

> Discover how SwarmForge's layered constitution system manages agent communication. Explore core rules, behavioral articles, and role configurations for efficient interaction.

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

---

**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`](https://github.com/unclebob/swarm-forge/blob/main/swarm_handoff.sh):

```bash

# 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`](https://github.com/unclebob/swarm-forge/blob/main/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`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh), which dispatches based on the role's receive mode from `.swarmforge/roles.tsv`:

```bash

# 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`](https://github.com/unclebob/swarm-forge/blob/main/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`](https://github.com/unclebob/swarm-forge/blob/main/done_with_current.sh), which dispatches to mode-specific handlers:

```bash
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`](https://github.com/unclebob/swarm-forge/blob/main/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:

```clojure
;; 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`](https://github.com/unclebob/swarm-forge/blob/main/swarm_handoff.sh), [`ready_for_next.sh`](https://github.com/unclebob/swarm-forge/blob/main/ready_for_next.sh), and [`done_with_current.sh`](https://github.com/unclebob/swarm-forge/blob/main/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`](https://github.com/unclebob/swarm-forge/blob/main/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`](https://github.com/unclebob/swarm-forge/blob/main/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