# .swarmforge/ Runtime Directory: Purpose and Structure in SwarmForge

> Understand the .swarmforge/ runtime directory's purpose and structure in SwarmForge. Learn how it manages local state for reliable multi-agent orchestration.

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

---

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

```clojure
(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:

```bash

# 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:

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