How SwarmForge Prevents Agents from Interfering with Each Other's tmux Sessions

SwarmForge isolates agents by giving each one a dedicated tmux session with a unique name and targeting commands to that specific session-window-pane triple, enforced through role-based session naming and precise tmux targeting.

SwarmForge is a Clojure-based multi-agent orchestration tool that manages concurrent AI agents in terminal environments. Preventing tmux session interference is critical for reliable multi-agent operation. This article examines the exact mechanisms implemented in the unclebob/swarm-forge codebase to guarantee complete isolation between agents.

Unique Session Names Per Role

Every agent receives its own tmux session through a deterministic naming scheme. In swarmforge.bb, the session-name-for-role function constructs session names from a fixed prefix plus the role identifier:

(defn session-name-for-role [role]
  (str session-prefix "-" role))        ; session-prefix = "swarmforge"

Source: swarmforge/scripts/swarmforge.bb lines 68-69

This ensures the "coder" role gets session swarmforge-coder, the "reviewer" role gets swarmforge-reviewer, and so on—no collisions possible.

Creating Isolated Sessions with Fixed Windows

Before any agent executes, SwarmForge calls create-role-session! to establish a detached tmux session dedicated to that role. The function creates the session, sets a fixed window name, and disables automatic window renaming:

(defn create-role-session! [ctx session title]
  (sh "tmux" "-S" (:tmux-socket ctx) "new-session" "-d" "-s" session "-n" agent-window)
  (sh "tmux" "-S" (:tmux-socket ctx) "rename-window"
      "-t" (str session ":" agent-window) title)
  (sh "tmux" "-S" (:tmux-socket ctx) "set-window-option"
      "-t" (str session ":" title) "allow-rename" "off"))

Source: swarmforge/scripts/swarmforge.bb lines 96-99

The -d flag creates a detached session. The allow-rename off setting prevents the agent from accidentally changing its window title and breaking targeting.

Precise Pane Targeting for Command Delivery

SwarmForge builds explicit tmux targets that pin every command to a specific session:window.pane coordinate. The tmux-agent-target function assembles this target string:

(defn tmux-agent-target [window pane-base-index session]
  (str session ":" window "." pane-base-index))

Source: swarmforge/scripts/swarmforge.bb lines 74-75

When launching an agent, the send-keys command uses this precise target. Here's the launch path from launch-role!:

(sh "tmux" "-S" (:tmux-socket ctx) "send-keys" "-t"
    (tmux-agent-target display (:tmux-pane-base-index ctx) session)
    command "Enter")

Source: swarmforge/scripts/swarmforge.bb lines 357-359

This targeting guarantees that a command sent to swarmforge-coder:swarm.0 can never reach swarmforge-reviewer:swarm.0.

Normalizing tmux Base Indexes Across Environments

tmux configurations vary: some users set base-index 1, others use the default 0. SwarmForge detects these settings at startup to maintain accurate targeting. The detect-tmux-base-indexes function probes the tmux installation and stores the actual indexes in the context:

(defn detect-tmux-base-indexes [ctx]
  (fs/create-dirs (:tmux-socket-dir ctx))
  (let [probe-session (when-not (sh-ok? "tmux" "-S" (:tmux-socket ctx) "info")
                        (let [session (str "swarmforge-probe-" (.pid (java.lang.ProcessHandle/current)))]
                          (sh "tmux" "-S" (:tmux-socket ctx) "new-session" "-d" "-s" session "sleep 60")
                          session))
        window-base (tmux-option (:tmux-socket ctx) "base-index" :session 0)
        pane-base   (tmux-option (:tmux-socket ctx) "pane-base-index" :window 0)]
    (when probe-session
      (process/sh {:continue true} "tmux" "-S" (:tmux-socket ctx) "kill-session" "-t" probe-session))
    (assoc ctx :tmux-window-base-index window-base :tmux-pane-base-index pane-base)))

Source: swarmforge/scripts/swarmforge.bb lines 87-95

The function creates a temporary probe session if needed, queries base-index and pane-base-index, cleans up, and returns the context with accurate index values. This ensures pane targeting works correctly regardless of user tmux configuration.

Cleaning Up Stale Sessions

SwarmForge prevents cross-run interference by killing any existing session before creating a new one. During startup, it checks for orphaned sessions:

(when (sh-ok? "tmux" "-S" (:tmux-socket ctx) "has-session" "-t" (:session row))
  (sh "tmux" "-S" (:tmux-socket ctx) "kill-session" "-t" (:session row)))

Source: swarmforge/scripts/swarmforge.bb lines 521-523

This eliminates the risk of an old agent process continuing to receive input intended for a newly launched agent with the same role name.

Complete Isolation Example

Here's how SwarmForge orchestrates isolation for a "coder" agent:

;; 1. Build unique session name
(def coder-session (session-name-for-role "coder"))
;; → "swarmforge-coder"

;; 2. Create dedicated tmux session
(create-role-session! ctx coder-session "Coder")

;; 3. Launch agent with precise targeting
(let [command (launch-command ctx 0 {:role "coder" :agent "claude"
                                     :session coder-session
                                     :display-name "Coder"
                                     :worktree-path (fs/path ctx :working-dir)
                                     :extra-args nil})]
  (sh "tmux" "-S" (:tmux-socket ctx) "send-keys" "-t"
      (tmux-agent-target "Coder" (:tmux-pane-base-index ctx) coder-session)
      command "Enter"))

Each step reinforces isolation: unique naming prevents session collisions, session creation establishes boundaries, targeting restricts command delivery, and cleanup removes state bleed between runs.

Summary

  • Unique session names (session-name-for-role) guarantee no two agents share a tmux session
  • Per-role session creation (create-role-session!) builds isolated environments with fixed windows
  • Explicit pane targeting (tmux-agent-target) routes every command to a specific session:window.pane coordinate
  • Base index detection (detect-tmux-base-indexes) ensures targeting accuracy across tmux configurations
  • Stale session cleanup prevents residual state from affecting new agent launches

Frequently Asked Questions

Can agents see each other's terminal output?

No. Each agent runs in its own tmux session with no shared windows or panes. The tmux session boundary is absolute—agents cannot access sessions outside their own unless explicitly configured otherwise in tmux.

What happens if two agents have the same role name?

SwarmForge prevents this through session naming and cleanup. The session-name-for-role function generates identical names for identical roles, and the startup routine kills any existing session before creating a new one. Only one agent per role can be active at a time.

Does this work with custom tmux configurations?

Yes. The detect-tmux-base-indexes function queries the actual base-index and pane-base-index values from the running tmux installation, then stores these in the context for accurate targeting. SwarmForge adapts to any valid tmux configuration.

How does SwarmForge handle tmux socket permissions?

All tmux commands use an explicit socket path via -S (:tmux-socket ctx). The socket directory is created with fs/create-dirs during initialization, and all agents share this socket for coordination while remaining isolated by session name.

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 →