# How SwarmForge Uses tmux Sessions for Role Isolation and Orchestration

> Discover how SwarmForge leverages tmux sessions for role isolation and orchestration. Manage commands, ensure cross-platform compatibility, and automate cleanup efficiently.

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

---

**SwarmForge uses dedicated tmux sessions to isolate each autonomous role (coder, cleaner, handoff daemon), with a portable socket under `/tmp/swarmforge-<user>` enabling cross-platform session management, command injection via `send-keys`, and automatic cleanup on shutdown.**

SwarmForge, an open-source autonomous coding orchestration tool in the `unclebob/swarm-forge` repository, leverages **tmux** as its core execution substrate. Rather than running roles as background processes hidden from the user, SwarmForge creates visible, attachable tmux sessions that developers can inspect, debug, and interact with in real-time. This design provides process isolation, persistent scrollback history, and a unified interface across macOS, Linux, and Windows Terminal.

## Socket Setup and Portability

SwarmForge begins by establishing a **portable tmux socket** that survives environment changes and enables non-standard tmux installations.

In `swarmforge/scripts/swarmforge.bb` at lines 768-790, the startup routine:

1. Creates a temporary directory under `/tmp/swarmforge-<username>`
2. Generates a uniquely-named socket file
3. Persists the socket path to `.swarmforge/tmux-socket` for subprocess access

```clojure
;; Simplified from swarmforge.bb L768-790
(let [socket-dir (str "/tmp/swarmforge-" (System/getenv "USER"))
      _ (fs/create-dirs socket-dir)
      socket-path (str socket-dir "/" (System/currentTimeMillis) ".sock")]
  (spit ".swarmforge/tmux-socket" socket-path)
  socket-path)

```

This socket-centric approach allows every subsequent tmux operation to target the correct server instance explicitly via the `-S` flag, preventing collisions with the user's personal tmux sessions.

## Base Index Detection for Cross-Environment Consistency

Before creating role sessions, SwarmForge **probes tmux configuration** to normalize window and pane numbering. The function at lines 88-98 spawns a temporary session to read `base-index` and `pane-base-index` values:

```bash
tmux -S <socket> start-server
tmux -S <socket> new-session -d -s probe
tmux -S <socket> display-message -p '#{base-index}'
tmux -S <socket> display-message -p '#{pane-base-index}'
tmux -S <socket> kill-session -t probe

```

These values are stored in the execution context and used by `tmux-agent-target` (lines 566-568) to construct valid target specifications regardless of the user's tmux configuration.

## Per-Role Session Creation

The `create-role-session!` function (lines 383-386) instantiates isolated environments for each SwarmForge role:

```clojure
;; Creating a role session in swarmforge.bb
(let [session "swarmforge-coder"
      socket  (:tmux-socket ctx)
      agent-window "agent"]
  (sh "tmux" "-S" socket "new-session" "-d" "-s" session "-n" agent-window)
  (sh "tmux" "-S" socket "set-option" "-t" session "history-limit" "10000")
  (sh "tmux" "-S" socket "rename-window" "-t" (str session ":" agent-window) "Coder"))

```

Each session receives:
- **Detached creation** (`-d`) to avoid blocking the orchestrator
- **History limit configuration** for scrollback retention
- **Descriptive window titles** for user clarity

Session metadata—socket path, PID, and pane ID—is written to disk for subsequent operations and cleanup tracking.

## Interactive Command Injection with send-keys

SwarmForge drives role behavior by **injecting keystrokes** into running sessions rather than executing one-shot commands. This preserves state and allows multi-step workflows:

```clojure
;; Sending "git status" to the coder pane
(let [socket (:tmux-socket ctx)
      target (tmux-agent-target "Coder" 
                               (:tmux-pane-base-index ctx) 
                               "swarmforge-coder")]
  (sh "tmux" "-S" socket "send-keys" "-t" target "-l" "git status")
  (sh "tmux" "-S" socket "send-keys" "-t" target "C-m"))

```

The `tmux-agent-target` helper translates logical role names to concrete `session:window.pane` addresses using the previously detected base indexes, ensuring commands arrive at the correct destination even when `base-index` is non-zero.

## User Attachment and Terminal Integration

SwarmForge exposes sessions to developers through multiple pathways. At launch completion (lines 841-857), it prints re-attachment commands:

```bash
tmux -S /tmp/swarmforge-username/12345.sock attach-session -t swarmforge-coder

```

Platform-specific terminal adapters in `swarmforge/scripts/terminal-adapters/` automate this for common environments:

- **iTerm2** ([`iterm2.sh`](https://github.com/unclebob/swarm-forge/blob/main/iterm2.sh) lines 47-50): Reads `TMUX_SOCKET` and `TMUX_SESSION` from environment variables, creates a new tab, and auto-attaches
- **Windows Terminal**: Equivalent PowerShell adaptation for WSL compatibility
- **Generic POSIX**: Falls back to standard tmux attach commands

These adapters enable one-click debugging of any autonomous role without manual socket path lookup.

## Session Cleanup and Lifecycle Management

Graceful shutdown is handled by [`swarm-cleanup.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarm-cleanup.sh) (lines 5-42), which accepts the socket path and session list as arguments:

```bash
#!/bin/bash
TMUX_SOCKET=$1
shift
for session in "$@"; do
  tmux -S "$TMUX_SOCKET" kill-session -t "$session" 2>/dev/null
done
rm -f "$WINDOW_IDS_FILE"

```

The orchestrator invokes this automatically when SwarmForge exits, ensuring no orphaned tmux servers consume system resources. The test suite validates this behavior in `test/swarmforge/script_test.clj` (lines 886-915), asserting that "close-swarm-kills-tmux-sessions" terminates all created sessions without affecting user tmux instances.

## Testing Infrastructure

SwarmForge's test suite exercises tmux integration through **isolated tmux servers** spun up specifically for test cases. Key coverage includes:

- Socket file creation and persistence validation
- Session lifecycle (create, attach, send-keys, destroy)
- Base index detection correctness across tmux versions
- Cleanup verification via process inspection

The `pack_ui_test.clj` file demonstrates starting and stopping tmux for UI pack testing, while `pack_web.bb` uses tmux-stub emulation for web-pack execution environments lacking full tmux.

## Summary

- **SwarmForge uses tmux sessions** to isolate autonomous roles with visible, attachable execution contexts
- **Portable socket architecture** under `/tmp/swarmforge-<user>` prevents conflicts with user tmux sessions
- **Base index probing** ensures consistent window/pane addressing across diverse tmux configurations
- **`send-keys` injection** drives role behavior while preserving interactive state and scrollback
- **Terminal adapters** provide platform-native attachment for iTerm2, Windows Terminal, and POSIX environments
- **Automatic cleanup** via [`swarm-cleanup.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarm-cleanup.sh) and validated test coverage prevents resource leaks

## Frequently Asked Questions

### How does SwarmForge prevent its tmux sessions from interfering with my existing tmux work?

SwarmForge creates a **dedicated socket file** in `/tmp/swarmforge-<username>/` rather than using the default tmux socket. Every tmux command explicitly targets this socket via the `-S` flag, completely isolating SwarmForge's server instance from your personal tmux sessions. You can verify this by running `tmux ls` (your sessions) versus `tmux -S /tmp/swarmforge-.../xxx.sock ls` (SwarmForge sessions).

### Can I attach to a running SwarmForge role to see what it's doing?

Yes. SwarmForge prints the attachment command at startup, and terminal adapters automate this. For manual attachment, use: `tmux -S $(cat .swarmforge/tmux-socket) attach-session -t swarmforge-coder`. Press `Ctrl+b` then `d` to detach without stopping the role.

### What happens to tmux sessions if SwarmForge crashes?

The [`swarm-cleanup.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarm-cleanup.sh) script is designed for graceful shutdown, but crashes may leave sessions running. You can manually clean up by locating the socket (`find /tmp -name "swarmforge-*" 2>/dev/null`) and running `tmux -S <socket> kill-server` or targeting individual sessions with `kill-session`.

### Why does SwarmForge use `send-keys` instead of `run-shell` or direct command execution?

`send-keys` **preserves interactive state**—environment variables, working directory, and shell history remain intact across commands. This enables multi-step workflows where subsequent commands depend on prior state. It also makes all activity visible in tmux scrollback, crucial for debugging autonomous agent behavior.