# Swarm-Forge Terminal Backend Adapter Contract: How to Add New Terminal Support

> Learn the Swarm-Forge terminal backend adapter contract and easily add new terminal support. Implement the six-function shell interface for seamless session management and lifecycle queries.

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

---

**The Swarm-Forge terminal backend adapter contract is a six-function shell interface that any terminal emulator must implement to open sessions, track windows, and respond to lifecycle queries.**

Swarm-Forge creates a separate terminal surface for each role requiring a visible UI. This abstraction lives in [`swarmforge/scripts/swarm-terminal-adapter.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/swarm-terminal-adapter.sh), which delegates platform-specific work to small adapter scripts sourced from the `terminal-adapters` directory. Understanding this **terminal backend adapter contract** lets you extend Swarm-Forge to any terminal emulator your team prefers.

---

## Core Adapter Contract Functions

Every adapter must implement exactly these six functions with consistent return semantics. The core orchestration in `swarmforge/scripts/swarmforge.bb` invokes them through generic helpers: `terminal-call`, `terminal-call-ok?`, and `terminal-call-out`.

### Identity and Capability Queries

| Function | Purpose | Return Contract |
|----------|---------|---------------|
| `terminal_backend_label()` | Human-readable backend name for logging | Print string to stdout, e.g. `echo "iTerm2"` |
| `terminal_backend_can_open_sessions()` | Declares ability to launch new surfaces | `return 0` = capable, `return 1` = incapable |
| `terminal_backend_tracks_windows()` | Declares ability to provide stable window/tab identifiers | `return 0` = tracks windows, `return 1` = does not |

### Lifecycle Operations

| Function | Purpose | Return Contract |
|----------|---------|---------------|
| `terminal_open_session <session> <title> [<sibling_id>]` | Open new terminal surface attached to tmux session | Print stable window/tab identifier to stdout |
| `terminal_window_exists <window_id>` | Verify identifier still valid | `return 0` if exists, non-zero otherwise |
| `terminal_close_window <window_id>` | Terminate surface by identifier | Silently succeed; return value ignored |

---

## How Backend Detection Works

The `detect_terminal_backend` function in [`swarm-terminal-adapter.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarm-terminal-adapter.sh) resolves which adapter to load:

1. **Explicit override**: Checks environment variable `SWARMFORGE_TERMINAL`
2. **OS heuristics**: AppleScript probes for iTerm2 or Terminal.app on macOS; `wt.exe` detection for Windows Terminal; fallback to `none`
3. **Script sourcing**: `load_terminal_backend` sources the matching file from `terminal-adapters/`

Set `SWARMFORGE_TERMINAL=myterm` to force a specific adapter regardless of auto-detection.

---

## Minimal Adapter Implementation Example

Here's a complete skeleton for adding **WezTerm** support. Save as [`swarmforge/scripts/terminal-adapters/wezterm.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/terminal-adapters/wezterm.sh):

```bash
#!/usr/bin/env zsh

terminal_backend_label() {
  echo "WezTerm"
}

terminal_backend_can_open_sessions() {
  return 0
}

terminal_backend_tracks_windows() {
  return 0
}

terminal_open_session() {
  local session="$1"
  local title="$2"
  local sibling_id="${3:-}"

  # Launch WezTerm with tmux attachment; substitute actual CLI

  # that returns a stable tab identifier

  wezterm start --exec "tmux -S $TMUX_SOCKET attach-session -t $session"
  
  # Placeholder: real implementation extracts tab ID from WezTerm output

  echo "$RANDOM"
}

terminal_window_exists() {
  local window_id="$1"
  # Query WezTerm for tab existence

  test -n "$window_id"
}

terminal_close_window() {
  local window_id="$1"
  # Close specific WezTerm tab

  : # Implement with WezTerm CLI

}

```

Make the adapter executable:

```bash
chmod +x swarmforge/scripts/terminal-adapters/wezterm.sh

```

---

## Handling Partial Support: Launch-Only Backends

Not all terminals expose stable window identifiers. If your backend **can open sessions but cannot track windows**, implement the contract as follows:

```bash
terminal_backend_can_open_sessions() {
  return 0    # Yes, we can launch

}

terminal_backend_tracks_windows() {
  return 1    # No stable identifiers available

}

```

Swarm-Forge respects this combination: it will launch surfaces but **skip the watchdog** mechanism that monitors and closes windows by ID. See the README comment block around line 47 for this documented escape hatch.

---

## Reference Implementations in Source

Study these existing adapters for platform-specific patterns:

- **[`terminal-adapters/terminal-app.sh`](https://github.com/unclebob/swarm-forge/blob/main/terminal-adapters/terminal-app.sh)** — macOS Terminal.app via AppleScript
- **[`terminal-adapters/iterm2.sh`](https://github.com/unclebob/swarm-forge/blob/main/terminal-adapters/iterm2.sh)** — iTerm2 with full window tracking
- **[`terminal-adapters/windows-terminal.sh`](https://github.com/unclebob/swarm-forge/blob/main/terminal-adapters/windows-terminal.sh)** — Windows Terminal WSL (launch-only style)
- **[`terminal-adapters/ghostty.sh`](https://github.com/unclebob/swarm-forge/blob/main/terminal-adapters/ghostty.sh)** — Ghostty with complete tracking support
- **[`terminal-adapters/none.sh`](https://github.com/unclebob/swarm-forge/blob/main/terminal-adapters/none.sh)** — Fallback that attaches tmux in current shell

The generic dispatch layer in `swarmforge.bb` treats all adapters uniformly, so your implementation only needs to satisfy the six-function contract.

---

## Summary

- **Six function signatures** define the complete terminal backend adapter contract
- **Return semantics matter**: exit codes for booleans, stdout for identifiers and labels
- **`terminal_open_session` must print a stable ID** to stdout for tracking-capable backends
- **Environment variable** `SWARMFORGE_TERMINAL` bypasses auto-detection
- **`terminal_backend_tracks_windows=1`** disables watchdog when IDs are unavailable
- **Drop-in deployment**: place correctly-named executable in `terminal-adapters/` directory

---

## Frequently Asked Questions

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

Set `terminal_backend_tracks_windows()` to `return 1`. Swarm-Forge will still open terminal surfaces via `terminal_open_session`, but it will not monitor or automatically close windows. You retain full session control through tmux directly.

### Can I use multiple terminal backends simultaneously?

No. Swarm-Forge selects **one** backend at startup through detection or `SWARMFORGE_TERMINAL`. All roles in a given Swarm-Forge invocation share the same backend. Run separate Swarm-Forge instances with different environment variables if you need heterogeneous terminal support.

### How do I debug my new adapter?

Run `SWARMFORGE_TERMINAL=myadapter ./swarm` with `set -x` at the top of your adapter script. Verify each function manually: `source swarmforge/scripts/swarm-terminal-adapter.sh && terminal_backend_label` should print your label, and `terminal-call-ok? terminal_backend_can_open_sessions` should return true.

### Where is the contract formally documented?

The canonical documentation appears in the **Terminal Behavior** section of [`README.md`](https://github.com/unclebob/swarm-forge/blob/main/README.md) under **Adding a Terminal Backend**. The enforcement happens in [`swarm-terminal-adapter.sh`](https://github.com/unclebob/swarm-forge/blob/main/swarm-terminal-adapter.sh) detection logic and the `terminal-call*` helper invocations throughout `swarmforge.bb`.