tmux voor AI-codeeragenten

tmux laat je AI-codeeragenten draaien in benoemde, loskoppelbare sessies die blijven bestaan als je terminalgesprek wordt gesloten of een SSH-verbinding wegvalt. Je krijgt één window waarin meerdere agenten draaien, send-keys om vanuit een script in elke willekeurige agent te typen, en capture-pane om de output terug te lezen. Deze combinatie is de reden waarom mensen tmux gebruiken.

Voordat je dit handmatig opbouwt, is het raadzaam om de ingebouwde methode te controleren: recente versies van Claude Code kunnen de worktree en de tmux-sessie voor je aanmaken met claude --worktree --tmux. Deze gids behandelt eerst die optie, daarna alles wat deze niet kan, en tot slot het punt waar tmux zelf ophoudt.

Waarom tmux en agenten goed samenwerken

Een codeeragent is een proces dat langdurig draait en constant met een terminal wil communiceren. Drie eigenschappen van tmux sluiten hier perfect bij aan:

  • Het overleeft disconnectie. De tmux-server is eigenaar van de pty, niet je terminalwindow. Sluit het window, verlies je SSH-verbinding of zet je laptop in slaap: de agent blijft werken en is nog steeds aanwezig wanneer je opnieuw koppelt.
  • Het houdt meerdere sessies in één window. Vier agenten worden vier benoemde sessies waar je met een toetsaanslag tussen wisselt, in plaats van vier losse windows waar je in de app-switcher naar moet zoeken.
  • Het is van buitenaf scriptbaar. Elke shell, waar dan ook, kan in een draaiende agent typen of het scherm ervan lezen. Er hoeft geen IPC gebouwd te worden en er hoeft geen API gekoppeld te worden. Dit is de eigenschap waarop mensen voortbouwen en de reden waarom tmux constant terugkomt in agent-orchestratie-scripts.

De ingebouwde vlaggen (voordat je zelf iets bouwt)

Claude Code is standaard uitgerust voor het scenario van één agent op één branch. In een recente versie van claude --help vind je deze twee vlaggen:

  • -w, --worktree [naam]: Maakt een nieuwe git worktree aan voor deze sessie (optioneel een naam opgeven).
  • --tmux: Maakt een tmux-sessie aan voor de worktree (vereist --worktree). Gebruikt iTerm2 native panes indien beschikbaar; gebruik --tmux=classic voor traditionele tmux.

De actie "isoleer deze taak en geef hem een eigen sessie" is dus één commando:

claude --worktree --tmux
# of geef de worktree een naam
claude --worktree auth-refactor --tmux

Twee details zijn belangrijk: --tmux geeft een foutmelding zonder --worktree, dus het is een worktree-functie die toevallig een sessie aanmaakt, en geen algemene sessievlag. Op iTerm2 worden native panes gebruikt in plaats van tmux, wat visueel mooier is, maar betekent dat de tmux-commando's in de rest van deze pagina geen sessie hebben om aan te koppelen. Gebruik --tmux=classic als je echt tmux onderliggend wilt hebben, wat essentieel is als je van plan bent tegen de sessie te scripten.

Voor één agent op één branch is dit de oplossing. Voor meerdere agenten in één sessie, specifieke pane-layouts, het aansturen van agenten via scripts, of gebruik op een remote box via SSH, is handmatige configuratie nodig.

Sessie per project, benoemd naar het project

De organiserende regel die dit bruikbaar houdt: één tmux-sessie per repo, benoemd naar de repo. Niet per taak, niet per agent. Taken komen en gaan; het project is het stabiele element.

# start een losgekoppelde sessie in een projectdirectory
tmux new-session -d -s api -c ~/code/api

# koppel aan de sessie (maakt deze aan als hij niet bestaat)
tmux new-session -A -s api -c ~/code/api

-A staat voor attach-or-create. Dit maakt een enkel commando veilig om herhaaldelijk uit te voeren, wat ideaal is voor een shell-functie:

# ~/.zshrc
agent() {
  local dir="${1:-$PWD}"
  local name="$(basename "$dir" | tr . -)"
  tmux new-session -A -s "$name" -c "$dir"
}

Sessienamen mogen geen . of : bevatten (tmux gebruikt deze als scheidingstekens voor targets), vandaar de tr. Daarna wordt tmux ls een echt inventarisoverzicht:

$ tmux ls
api: 3 windows (created Fri Jul 31 09:12:04 2026)
web: 2 windows (created Fri Jul 31 09:40:11 2026)
infra: 1 windows (created Fri Jul 31 11:02:55 2026)

Voor meer detail kun je een format-string gebruiken: tmux list-sessions -F '#{sessionname} windows=#{sessionwindows} attached=#{session_attached}'

Een layout voor het monitoren van meerdere agenten

Binnen een sessie geef je elke agent een eigen window, benoemd naar de taak:

tmux new-window -t api -n auth   -c ~/code/api
tmux new-window -t api -n tests  -c ~/code/api

Windows zijn beter dan panes voor agenten die je niet actief volgt, omdat een window geen schermruimte inneemt. Panes zijn voor de twee of drie die je nu naast elkaar wilt zien:

# split het huidige window en betegel de inhoud
tmux split-window -h -c '#{pane_current_path}'
tmux split-window -v -c '#{pane_current_path}'
tmux select-layout tiled

#{panecurrentpath} is belangrijk. Zonder dit opent een nieuw pane in de directory waar de sessie startte, niet in de directory waar je je nu bevindt, waardoor de agent naar de verkeerde repo verwijst.

Er zijn twee nuttige layouts: tiled voor een gelijkmatig raster van agenten, en main-vertical voor één groot pane (de agent die je aanstuurt) met de rest ernaast gestapeld.

tmux select-layout main-vertical
tmux set-window-option main-pane-width 60%

(Percentage-waarden voor main-pane-width vereisen tmux 3.2 of nieuwer. Gebruik bij oudere versies een absoluut aantal kolommen, bijv. main-pane-width 120).

Een nuttige .tmux.conf

Dit zijn de instellingen die specifiek relevant zijn voor agent-werk. Dit is geen volledige configuratie, maar de noodzakelijke aanpassingen ten opzichte van de standaardinstellingen.

# Agenten produceren veel output; een grote scrollback is nodig
set -g history-limit 100000

# 24-bit kleur, zodat agent TUIs correct renderen
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"

# Scrollen en klikken tussen panes met de muis
set -g mouse on

# Voorkom dat een draaiend proces de window hernoemt
set -g allow-rename off
set-window-option -g automatic-rename off

# 1-geïndexeerde windows komen overeen met de cijfertoetsen op het toetsenbord
set -g base-index 1
set-window-option -g pane-base-index 1
set -g renumber-windows on

# Markeer windows waar een agent output produceerde terwijl je elders was
set-window-option -g monitor-activity on
set -g visual-activity off

# Statusregel ververst vaak genoeg om als monitor te dienen
set -g status-interval 5

# Geen vertraging wanneer de TUI van een agent een escape-sequentie leest
set -sg escape-time 10

# Wissel van pane zonder de prefix-toets
bind -n M-h select-pane -L
bind -n M-j select-pane -D
bind -n M-k select-pane -U
bind -n M-l select-pane -R

# Herlaad configuratie zonder de server te herstarten
bind r source-file ~/.tmux.conf \; display-message "config reloaded"

Toelichting:

  • allow-rename off voorkomt dat een zorgvuldig benoemd "auth" window plotseling wordt hernoemd door de agent zelf.
  • escape-time 10 lost het probleem op waarbij pijltjestoetsen traag aanvoelen in interactieve TUIs. De standaardvertraging is bedoeld om een echte Escape-toets te onderscheiden van een sequentie, maar maakt TUIs "moderig".

Een agent aansturen met send-keys

send-keys typt in een pane alsof je zelf achter het toetsenbord zit. Zo kun je een agent scripten vanuit cron, een git-hook of een andere agent.

Syntax target: sessie:window.pane

tmux send-keys -t api:auth "run the test suite and fix what fails" Enter

Er zijn drie veelvoorkomende problemen bij deze methode:

  1. Interpretatie van argumenten: Woorden als Enter, C-c, Escape en Space worden gezien als toetsen, niet als tekst. Gebruik -l om een letterlijke string te verzenden:

``bash tmux send-keys -t api:auth -l "press Enter to continue was the old flow" tmux send-keys -t api:auth Enter ` (Bij -l` is de newline een tweede aanroep).

  1. Puntkomma's: Een puntkomma beëindigt het tmux-commando. Een ; in je tekst moet worden geescaped als \;.
  2. Timing: Agent TUIs hebben vaak een moment nodig tussen de tekst en de newline (vanwege debouncing of re-rendering bij het plakken). Het betrouwbare patroon is:

``bash tmux send-keys -t api:auth -l "$PROMPT" sleep 0.3 tmux send-keys -t api:auth Enter ``

Een weggelopen agent onderbreken werkt via hetzelfde mechanisme: tmux send-keys -t api:auth C-c

Een agent uitlezen met capture-pane

capture-pane dumpt de inhoud van een pane naar stdout. Dit is het leesgedeelte van de interactie.

# Het zichtbare scherm
tmux capture-pane -p -t api:auth

# De laatste 200 regels, waarbij omgebroken regels weer worden samengevoegd
tmux capture-pane -p -J -S -200 -t api:auth

# De gehele scrollback
tmux capture-pane -p -J -S - -t api:auth

# Behoud de kleur-escape-sequenties
tmux capture-pane -p -e -t api:auth

De -J vlag is cruciaal. Zonder deze vlag wordt een regel die is omgebroken op basis van de terminalbreedte als twee aparte regels teruggegeven, waardoor grep op de output fouten maakt.

Voor een continue log in plaats van een momentopname kun je pipe-pane gebruiken: tmux pipe-pane -o -t api:auth 'cat >> ~/agent-logs/api-auth.log' (Gebruik hetzelfde commando zonder de rest om het te stoppen; -o werkt als een toggle).

De statusregel-monitor

Veel gebruikers van meerdere agenten bouwen uiteindelijk een statusregel die aangeeft welke agenten werken en welke wachten. Dit gebeurt via #() in de statusregel, wat een shell-commando uitvoert en de output interpoleert.

set -g status-interval 5
set -g status-right '#(~/bin/tmux-agent-status) | %H:%M'
set -g status-right-length 100

Het bijbehorende script (~/bin/tmux-agent-status):

#!/usr/bin/env bash
out=""
while read -r target; do
  screen="$(tmux capture-pane -p -J -S -8 -t "$target" 2>/dev/null)"
  name="${target%%:*}"
  case "$screen" in
    *"Do you want"*|*"❯ 1."*) out+="⏸ $name " ;;   # Wachten op prompt
    *"esc to interrupt"*)      out+="● $name " ;;   # Bezig
    *)                         out+="○ $name " ;;   # Idle
  esac
done < <(tmux list-panes -a -F '#{session_name}:#{window_index}.#{pane_index}')
printf '%s' "$out"

Dit script werkt via string-matching op de gerenderde frame van de TUI. Een lichtere variant gebruikt tmux' eigen activiteitstracking: monitor-silence geeft een melding wanneer een pane N seconden geen output produceert.

set-window-option -g monitor-silence 30
set -g visual-silence on
set-hook -g alert-silence 'run-shell "osascript -e \"display notification \\\"agent idle\\\"\""'

Loskoppelen, herkoppelen en persistentie

  • tmux detach-client (of prefix, dan d)
  • tmux attach -t api
  • tmux switch-client -t web (vanuit een andere sessie)
  • tmux kill-session -t api

Wat overleeft wat?

GebeurtenisAgenten blijven draaien?
Terminalwindow sluitenJa
Client loskoppelen (detach)Ja
SSH-verbinding valt wegJa
tmux kill-sessionNee
tmux kill-serverNee
RebootNee
macOS "Open windows opnieuw" na restartNee

De tmux-server is een proces dat eigendom is van de gebruiker. Niets in tmux zorgt ervoor dat het een reboot overleeft. Als transcripten belangrijk zijn, gebruik dan pipe-pane naar een bestand.

Let op: Een losgekoppelde sessie behoudt de grootte van de laatste gekoppelde client (of 80x24). Dit kan leiden tot weergavefouten bij het opnieuw koppelen. set-window-option -g aggressive-resize on helpt wanneer meerdere clients met verschillende schermgroottes zijn gekoppeld.

tmux via SSH

Dit is waar tmux bijna onvervangbaar is. Agenten draaien op een remote box over een onbetrouwbare verbinding:

ssh devbox -t tmux new-session -A -s agents

Als de verbinding wegvalt, voer je hetzelfde commando opnieuw uit en ben je direct terug in de sessie terwijl de agent is blijven werken. Combineer dit met mosh bij zeer slechte verbindingen.

Het "nested-tmux" probleem: Als je tmux lokaal én op de remote box draait, gebruiken beide dezelfde prefix. Oplossingen zijn een andere prefix op de remote (set -g prefix C-a) of de prefix twee keer indrukken (bind C-b send-prefix).

De beperkingen van tmux

tmux is uitstekende software voor multiplexing en persistentie, maar het is niet specifiek gebouwd voor AI-agenten.

  • Geen inzicht in agent-status: Een agent die wacht op goedkeuring ziet er hetzelfde uit als een agent die nadenkt of een agent die al twintig minuten klaar is. De statusregel-hack is een poging dit op te lossen via scraping.
  • Geen notificaties bij voltooiing: Er is geen event voor "de agent is klaar", omdat tmux niet weet wat een agent is.
  • Fragiele screen scraping: capture-pane geeft het gerenderde frame (met spinners, ANSI-kleuren, etc.), niet de gestructureerde data. Elke UI-wijziging van de agent breekt de parser.
  • Geen gedeelde staat: Twee agenten in verschillende sessies kunnen elkaar niet zien.
  • Geheugengebruik: Een hoge history-limit over een dozijn panes kost aanzienlijk veel geheugen.
  • Geen overleving na reboot: Alle sessies en transcripten zijn weg na een herstart.

Waar crystl het overneemt

crystl is een macOS-terminal gebouwd voor de workload waar tmux niet voor is ontworpen: veel agenten tegelijk, waarvan de meeste off-screen zijn, maar die elk af en toe jouw aandacht nodig hebben.

  • Zichtbare goedkeuringen: In plaats van begraven te raken in een pane, verschijnen goedkeuringsverzoeken als zwevende kaarten (floating cards), kleurgecodeerd per project.
  • Agent-status als eersteklas signaal: Het activity-paneel toont de status van elke sessie (bezig, wacht op jou, idle, klaar) zonder scraping.
  • Gestructureerde output: crystl captureert elke beurt, tool-aanroep en resultaat als typed records. Geschiedenis is doorzoekbaar over alle sessies heen.
  • Project-gebaseerde persistentie: Projecten en sessies overleven het sluiten van een window of het herstarten van de Mac.
  • Isolatie via Git Worktrees: Parallel werk aan één repo is geïsoleerd via echte git worktrees, zodat agenten niet met elkaar conflicteren.

Aanbeveling: Blijf tmux gebruiken voor remote boxen, langlopende processen op servers en situaties waarbij de SSH-verbinding het zwakke punt is. Maar wanneer je zes agenten beheert die elk onvoorspelbaar een beslissing van je nodig hebben, is het probleem verschoven van multiplexing naar orchestratie.