.swarmforge/ Runtime Directory: Purpose and Structure in SwarmForge

The .swarmforge/ directory serves as the local runtime state hub for SwarmForge projects, storing tmux sockets, role configurations, handoff queues, and daemon state to enable reliable multi-agent orchestration.

When you initialize a swarm using the unclebob/swarm-forge framework, the system generates a hidden .swarmforge/ folder at your project root. This directory acts as the central nervous system for active swarms, isolating all mutable runtime data from your source code while enabling the handoff protocol that coordinates multiple AI agents. Understanding the .swarmforge/ runtime directory structure is essential for debugging agent communication, monitoring handoff flows, and ensuring clean teardown of swarm sessions.

Core Purposes of the .swarmforge/ Directory

The .swarmforge/ directory fulfills four critical functions that keep SwarmForge operations isolated and recoverable.

Isolate Swarm State

SwarmForge creates this hidden folder to keep all mutable data—tmux sockets, handoff files, daemon information, and role-mode tables—confined within the project directory. As documented in the repository README, this approach ensures "multiple swarms can coexist without interfering with each other" by maintaining strict workspace isolation【/cache/repos/github.com/unclebob/swarm-forge/main/README.md#L100】.

Drive the Handoff Daemon

The handoff daemon (handoffd.bb) relies on files within .swarmforge/ to exchange messages between agents rather than sending tmux commands directly. According to the handoff protocol specification, the daemon "watches each agent worktree for outbound handoff files" in the designated subdirectories【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/handoff-protocol.md#L13-L18】.

Persist Runtime Configuration

Dynamic data that changes during swarm execution—including the tmux socket path and role receive modes—gets written to flat files like tmux-socket and roles.tsv. The startup script swarmforge.bb explicitly writes the tmux socket location to .swarmforge/tmux-socket during initialization【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/scripts/swarmforge.bb#L246-L250】 and populates roles.tsv based on the static swarmforge.conf configuration【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/scripts/swarmforge.bb#L284-L285】.

Provide a Durable Audit Trail

Handoff files move through lifecycle subdirectories (outbox, inbox, sent, failed) creating a persistent record of agent interactions. This file-based queue system allows work to be inspected, retried, or recovered after unexpected crashes, as detailed in the directory layout documentation【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/handoff-protocol.md#L28-L38】.

Directory Structure and Key Files

The .swarmforge/ directory follows a strict hierarchy that separates socket information, role metadata, daemon state, and message queues:


.swarmforge/
├─ tmux-socket                # Absolute path to project-specific tmux socket

├─ roles.tsv                  # Runtime table mapping roles to receive modes

├─ sessions.tsv               # Mapping of tmux session IDs to roles

├─ daemon/
│   ├─ handoffd.pid          # Process ID of the handoff daemon

│   └─ stop                  # Graceful shutdown flag

└─ handoffs/
    ├─ outbox/
    │   ├─ tmp/               # Staging area for new handoffs

    │   └─ ...                # Files moved to sent/failed after delivery

    ├─ sent/                  # Successfully delivered handoffs

    ├─ failed/                # Undeliverable handoffs

    └─ inbox/
        ├─ new/               # Incoming handoffs awaiting acceptance

        ├─ in_process/        # Handoffs currently being processed

        └─ completed/         # Finished handoffs

The tmux-socket file stores the absolute path to the Unix socket used for tmux communication, while roles.tsv maintains the dynamic receive mode (task or batch) for each configured role. The daemon/ subdirectory contains the handoffd.pid file used by stop_handoff_daemon.bb to manage graceful shutdowns【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/scripts/stop_handoff_daemon.bb#L20-L22】, and the handoffs/ tree implements the durable queue mechanism.

Runtime Lifecycle Integration

Understanding how SwarmForge interacts with this directory during the swarm lifecycle clarifies its operational role.

Initialization Phase

During startup, swarmforge.bb creates the .swarmforge/ structure, writes the tmux socket path to tmux-socket, and generates roles.tsv from the static configuration. This initialization sequence establishes the runtime environment that agents will reference throughout the session【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/scripts/swarmforge.bb#L246-L250】【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/scripts/swarmforge.bb#L284-L285】.

Agent Execution

Each role's scripts—such as swarm_handoff.sh and ready_for_next.sh—read and write files within .swarmforge/handoffs/ to communicate state. Agents check roles.tsv to determine their receive mode, as implemented in ready_for_next.bb【/cache/repos/github.com/unclebob/swarm-forge/main/ready_for_next.bb#L34-L38】.

Daemon Operations

The handoffd.bb process monitors .swarmforge/handoffs/outbox/ for new handoff files, validates them, and copies them to recipient inbox/ directories. After delivery attempts, it moves files to sent/ or failed/ and uses the socket file to send minimal wake-up notifications to tmux sessions.

Cleanup

When terminating a swarm, the close-swarm command removes the socket file and optionally the entire .swarmforge/ directory, ensuring no stale runtime data persists between sessions.

Working with .swarmforge/ Files

Access runtime state programmatically using Babashka (Clojure) scripts or standard shell commands.

Retrieve the current tmux socket path:

(require '[babashka.fs :as fs])

;; Query the tmux socket path written by swarmforge.bb
(let [socket-file (fs/path ".swarmforge" "tmux-socket")]
  (when (fs/exists? socket-file)
    (slurp socket-file)))

This references the state directory pattern used in swarmforge.bb【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/scripts/swarmforge.bb#L481-L485】.

List pending handoffs for the current role:


# List all new handoffs awaiting processing

ls .swarmforge/handoffs/inbox/new/*.handoff 2>/dev/null || echo "No pending handoffs"

Query role receive modes from the runtime table:

(require '[clojure.string :as str]
         '[babashka.fs :as fs])

;; Read role entries from the runtime table
(let [roles-file (fs/path ".swarmforge" "roles.tsv")]
  (when (fs/exists? roles-file)
    (let [roles (str/split-lines (slurp roles-file))]
      (doseq [r roles]
        (println "Role receive mode:" r)))))

This pattern mirrors the file access in ready_for_next.bb【/cache/repos/github.com/unclebob/swarm-forge/main/ready_for_next.bb#L34-L38】.

Summary

  • The .swarmforge/ directory acts as the isolated runtime state hub for active SwarmForge swarms, created automatically at project startup.
  • Core files include tmux-socket (Unix socket path), roles.tsv (runtime role configuration), and sessions.tsv (tmux session mappings).
  • Handoff queues reside in handoffs/ with subdirectories for outbox, sent, failed, and inbox (containing new, in_process, and completed states).
  • Daemon state in daemon/ tracks the handoffd.pid process and supports graceful shutdown via flag files.
  • Lifecycle integration spans initialization (swarmforge.bb), agent execution (role scripts), daemon management (handoffd.bb), and cleanup (close-swarm).

Frequently Asked Questions

What happens if I manually delete the .swarmforge/ directory while a swarm is running?

Deleting .swarmforge/ while agents are active severs the runtime state connection. The tmux socket path becomes unavailable, causing swarm_handoff.sh and other scripts to fail when attempting communication. The handoff daemon loses its PID file and queue tracking, potentially leaving orphaned tmux sessions. Always use the close-swarm command to ensure graceful termination.

How does SwarmForge prevent conflicts between multiple projects?

Each project maintains its own isolated .swarmforge/ directory under its respective root. By storing tmux sockets and handoff queues locally rather than in global /tmp or system directories, SwarmForge ensures that Project A's daemon never processes Project B's handoff files, even when both swarms run simultaneously on the same machine【/cache/repos/github.com/unclebob/swarm-forge/main/README.md#L100】.

Where does the handoff daemon store its process ID?

The daemon writes its PID to .swarmforge/daemon/handoffd.pid during startup. The stop_handoff_daemon.bb script checks this file to send the appropriate termination signal and optionally reads the daemon/stop flag file to trigger graceful shutdown sequences【/cache/repos/github.com/unclebob/swarm-forge/main/swarmforge/scripts/stop_handoff_daemon.bb#L20-L22】.

Can I inspect handoff failures after a swarm crashes?

Yes. The .swarmforge/handoffs/failed/ directory retains handoff files that could not be delivered to their target agents. Additionally, completed handoffs remain in .swarmforge/handoffs/sent/ and inbox/completed/, providing a full audit trail for debugging inter-agent communication issues even after unexpected termination.

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 →