# How SwarmForge Handles tmux Copy Mode Interference with Visible Windows

> Discover how SwarmForge prevents tmux copy mode interference. Learn about its detect-and-recover strategy and watchdog process for seamless visible window management.

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

---

**SwarmForge uses a detect-and-recover strategy that checks for tmux copy mode before sending commands and automatically restarts stuck windows via a watchdog process.**

SwarmForge runs each agent inside its own **tmux session**, and when a window is declared **visible** (`window …`), the platform attaches a terminal surface to that session. However, tmux copy mode can swallow keyboard input meant for the agent, creating interference that disrupts the user experience. This article explains how SwarmForge handles tmux copy mode interference with visible windows through detection logic, automatic recovery, and session isolation.

## Detecting tmux Copy Mode Before Command Execution

When tmux enters **copy mode**, keystrokes intended for the agent are intercepted by tmux instead of reaching the running process. SwarmForge addresses this by explicitly checking the tmux mode state before assuming an agent is stuck.

According to the SwarmForge documentation, users are advised to **check copy mode** when copy/paste behavior feels unexpected. The platform detects whether tmux copy mode is active by querying tmux options on the project-specific socket.

```clj
;; Example: Detecting copy mode before sending a command
(defn send-to-agent [session cmd]
  (let [mode (run {:dir "."} "tmux" "-S" session "show-options" "-gv" "mode")]
    (when (= mode "copy")
      (println "tmux is in copy‑mode – exiting copy mode before sending.")
      (run {:dir "."} "tmux" "-S" session "send-keys" "q"))
    (run {:dir "."} "tmux" "-S" session "send-keys" cmd "C-m")))

```

This detection logic ensures that copy mode does not permanently block agent communication. The `-S` flag specifies the **tmux socket path**, which SwarmForge isolates per project to prevent cross-contamination between tmux servers.

## Window Watchdog Automatic Recovery

For visible windows that end up in unexpected tmux states—including copy mode—SwarmForge deploys a **window-watchdog** process implemented in `swarmforge/scripts/swarm_window_watchdog.bb`. This Babashka script monitors tmux session health and can **re-open** windows when state abnormalities are detected.

```clj
;; watchdog snippet (swarm_window_watchdog.bb)
(ns swarm-window-watchdog
  (:require [babashka.process :as process]
            [babashka.fs :as fs]))

(defn restart-window! [socket win-id]
  (println "Restarting window" win-id "because tmux state was abnormal")
  (process/process ["tmux" "-S" socket "kill-window" "-t" win-id])
  (process/process ["tmux" "-S" socket "new-window" "-t" win-id]))

```

The watchdog preserves **agent state and history** by re-attaching to the same tmux session rather than creating an entirely new session. This recovery mechanism is documented in the README.md window behavior section and provides resilience against stuck windows without requiring manual user intervention.

## Per-Project tmux Socket Isolation

SwarmForge prevents copy mode interference from unrelated tmux workspaces through **socket isolation**. Each project writes its tmux socket path to `.swarmforge/tmux-socket`:

```sh

# .swarmforge/tmux-socket creation (part of startup)

#!/usr/bin/env bash
TMUX_SOCKET="$(mktemp -u /tmp/swarmforge-tmux-XXXXX.sock)"
tmux -S "$TMUX_SOCKET" start-server
echo "$TMUX_SOCKET" > .swarmforge/tmux-socket

```

All windows within a project share this socket, keeping their tmux sessions isolated from:

- Other SwarmForge projects
- User's personal tmux workspaces
- System-wide tmux servers

This isolation guarantees that copy mode activation in an unrelated tmux server cannot steal focus from SwarmForge visible windows. The socket path is referenced throughout the codebase using the `-S` flag in all tmux commands.

## Terminal Backend Contracts and Limitations

The **terminal-backend adapters** located in `swarmforge/scripts/terminal-adapters/` (e.g., [`terminal-app.sh`](https://github.com/unclebob/swarm-forge/blob/main/terminal-app.sh)) launch tmux sessions without embedding custom key handling. This design decision means:

- SwarmForge relies on **tmux's native copy mode behavior**
- The watchdog provides the primary recovery mechanism
- If a backend cannot track windows, the watchdog is **disabled**

When the watchdog is unavailable, users must manually manage copy mode state. This fallback behavior is documented in the README.md terminal adapter section, which explains that not all terminal surfaces support automatic window tracking.

## Key Files and Their Roles

| File | Purpose |
|------|---------|
| [`README.md`](https://github.com/unclebob/swarm-forge/blob/main/README.md#L451-L560) | Documents copy mode warnings and watchdog recovery behavior |
| `swarmforge/scripts/swarm_window_watchdog.bb` | Implements automatic window restart for abnormal tmux states |
| `.swarmforge/tmux-socket` (runtime) | Stores project-specific tmux socket path for session isolation |
| `swarmforge/scripts/terminal-adapters/*.sh` | Defines terminal surface launching without custom key handling |

## Summary

- **Detection** – SwarmForge checks tmux mode state before sending commands to avoid copy mode interference
- **Recovery** – The `swarm_window_watchdog.bb` process automatically restarts windows stuck in abnormal tmux states
- **Isolation** – Per-project tmux sockets in `.swarmforge/tmux-socket` prevent cross-session interference
- **Delegation** – Terminal backends rely on tmux native behavior rather than custom key handling

## Frequently Asked Questions

### How does SwarmForge know if tmux copy mode is active?

SwarmForge queries tmux options using `tmux -S <socket> show-options -gv mode` on the project-specific socket. If the returned mode equals `"copy"`, the platform recognizes that keystrokes would be intercepted and can exit copy mode before sending commands to the agent.

### What happens if a visible window gets stuck in copy mode?

The `swarm_window_watchdog.bb` process detects abnormal tmux states and automatically **re-opens** the affected window. It kills the stuck window and creates a new window attached to the same tmux session, preserving agent state and scrollback history without user intervention.

### Can copy mode in my personal tmux sessions interfere with SwarmForge?

No. SwarmForge uses **per-project tmux sockets** stored in `.swarmforge/tmux-socket` that isolate project sessions from each other and from any other tmux workspaces. Copy mode activation in an unrelated tmux server cannot affect SwarmForge visible windows.

### What if my terminal backend doesn't support window tracking?

If the terminal backend cannot track windows—as documented in the `terminal-adapters/*.sh` section of the README—the watchdog is **disabled**. In this configuration, users must manually manage tmux copy mode state and manually recover stuck windows.