A tmux session manager for running and restoring multiple Codex CLI instances (plus optional Claude wrappers), with logging and monitoring built in.
- Automated session management: Long-lived tmux session that persists across reboots
- Centralized logging: Each Codex pane logs to individual files with timestamps
- Unified monitoring: Watch all Codex instances from a single consolidated view
- Fast navigation: Optional "board" session for quick switching between instances
- Snapshot/restore: Save a manifest of windows and restore them later
- Status annotations: RUN/READY/ERR prefixes in tmux window titles (Codex/Claude READY uses prompt parsing)
- Autosave/autorestore (optional): Systemd user services to persist sessions across logins
- Claude-friendly:
claude-*wrappers use the same tmux workflow
Run the setup script to install dependencies and create helper scripts (source it to auto-reload your shell):
source ./setup.shThis will:
- Install
tmuxandmultitailusing your system's package manager - Create helper scripts in
$HOME/bin/ - Set up logging directories
- Add
$HOME/binto your PATH automatically (bash/zsh/fish) and the current session
From any project directory:
codex-addOr specify a path:
codex-add /path/to/projectClaude uses the same session with wrappers:
claude-add /path/to/projectMonitor all Codex logs in real-time:
codex-watchNotes:
- On small terminals (phones),
codex-watchauto-switches to a simpler mode. - Force simple mode:
codex-watch --simpleorCODEX_WATCH_MODE=tail codex-watch. - Force full mode:
codex-watch --mode multitail. - First run shows an optional tmux tips prompt; choose Yes to see basics. Answer "Don't show again" to persist your preference. Re-enable temporarily with
CODEX_TIPS_PROMPT=1or permanently by removing~/.local/state/codexfarm/no_tips.
Snapshot your current Codex windows:
codex-save # writes to ~/.config/codexfarm/manifest.tsvRestore them later (e.g., after reboot or on SSH login):
codex-restore -a # recreates and attaches to the sessionUse -f to force re-creation of existing-named windows.
If tmux sessions are already running (no manifest needed):
codex-resume # joins the main Codex session if presentFlags:
--boardto prefer the board session first.
codex-add can install systemd user services to autosave on logout and restore on login.
You can trigger it directly:
codex-add --install-autoserviceSet CODEX_AUTOSERVICE_CHOICE=yes to auto-accept the prompt, or no to suppress it.
codex-add auto-starts codex-annotator, which prefixes tmux window titles with RUN, READY, or ERR. For Codex/Claude panes it inspects recent output for prompts/approval selections; other panes fall back to the command-based heuristic.
Important: the READY status is best-effort and based on prompt detection. Use it as a signal, not a guarantee.
Tuning and controls:
- Disable autostart:
CODEX_ANNOTATOR_AUTOSTART=0 - Disable annotator (if started):
CODEX_ANNOTATOR_ENABLED=0 - Adjust RUN detection:
CODEX_ANNOTATOR_RUNNING_REGEX(default:(codex|node|ssh)) - Scope sessions:
CODEX_ANNOTATOR_SESSION_REGEX(default:^codex) - Ignore windows/sessions prefixed with
!(configurable viaCODEX_ANNOTATOR_IGNORE_PREFIX) - Adjust capture depth:
CODEX_ANNOTATOR_CAPTURE_LINES(default:200)
codex-add [directory]- Add new Codex instance to tmux sessioncodex-annotator- Annotate tmux window titles with RUN/READY/ERR statuscodex-watch- Monitor all Codex logs in consolidated viewcodex-status [sessions|windows|logs]- Show status informationcodex-board [create|link|switch]- Manage board session for navigationcodex-resume [--board]- Attach/switch to an existing Codex/tmux sessioncodex-save [manifest]- Snapshot current windows to a manifest (TSV)codex-restore [-a] [-f] [manifest]- Restore windows from a manifest
Claude equivalents use the same tmux workflow and accept the same flags:
claude-add, claude-annotator, claude-board, claude-restore, claude-resume, claude-save, claude-status, claude-watch.
Common:
CODEX_SESSION- tmux session name (default:codexfarm)CODEX_NAME- window name (default: directory basename)CODEX_CMD- command to run (default:codex)CODEX_ARGS- additional arguments for codexCODEX_STATE_BASENAME- state/log directory base name (default:codexfarm)CODEX_TIPS_PROMPT- show tmux tips prompt:0to disable,1to force (default respects a persisted opt-out)CODEX_LOCK_TITLES- set to0to let tmux or shell rename windows automatically (default keeps Codex windows named after their directory)CODEX_WATCH_MODE-auto(default),tail, ormultitailto control codex-watch displayCODEX_AUTOSERVICE_CHOICE-yesornoto persist autoservice choiceCODEX_ANNOTATOR_AUTOSTART- set to0to skip starting the annotator
Annotator-specific:
CODEX_ANNOTATOR_ENABLED- set to0to disable the annotator loopCODEX_ANNOTATOR_RUNNING_REGEX- regex for pane commands considered RUNNINGCODEX_ANNOTATOR_SESSION_REGEX- regex for sessions to annotateCODEX_ANNOTATOR_INTERVAL- polling interval in secondsCODEX_ANNOTATOR_IGNORE_PREFIX- window/session name prefix to ignore (default:!)CODEX_ANNOTATOR_CAPTURE_LINES- number of lines to capture from panes (default:200)
Claude-specific:
- Use
CLAUDE_*versions of the common variables to override just the Claude wrappers.
Example:
CODEX_CMD="cursor" CODEX_ARGS="--wait" codex-add /my/projectFlags:
codex-add -d: start without attaching (useful in SSH automation)codex-restore -a: attach after restoring;-fto replace same-named windows
Create a separate "board" session for quick navigation:
# Create board session
codex-board create
# Link all Codex windows to board
codex-board link
# Switch to board session
codex-board switchNow you can use tmux switch-client -t board to scan through all Codex instances while the main codexfarm session continues running.
- Start or restore your farm, then safely detach:
codex-restore; tmux detach. - Reattach anytime:
codex-resume(ortmux attach -t ${CODEX_SESSION:-codexfarm}). - Prefer
codex-add -din automation to avoid stealing your current terminal. - For mobile networks and roaming devices, use mosh: install
moshon the server (and open UDP 60000-61000), then connect with a mosh-capable client and attach your tmux session. Desktop SSH keeps working the same.- Example client wrapper (tries mosh then ssh):
examples/connect.sh user@host
- Example client wrapper (tries mosh then ssh):
- If your terminal is very small (phones), use
codex-watch --simpleand zoom panes in tmux withPrefix + z. - Optional tmux tweak for mixed desktop/mobile:
tmux set -g aggressive-resize onto let windows resize to the current client.
-
Start many projects at once (non-attaching):
examples/batch-add.sh ~/proj/a ~/proj/b ~/proj/c tmux attach -t ${CODEX_SESSION:-codexfarm}
-
Auto-restore on login (add to shell rc):
# ~/.bashrc or ~/.zshrc source $(pwd)/examples/restore-on-login.sh
-
One-liners:
- Save then restore and attach:
codex-save && codex-restore -a - Start with a different command:
CODEX_CMD="cursor" CODEX_ARGS="--wait" codex-add -d /path - Watch logs with multitail if available:
codex-watch
- Save then restore and attach:
All logs are stored in ${XDG_STATE_HOME:-$HOME/.local/state}/codexfarm/logs/ with timestamps:
# View log status
codex-status logs
# Follow specific log
tail -f ~/.local/state/codexfarm/logs/myproject_20240315-143022.log
# Clean old logs (example: older than 7 days)
find ~/.local/state/codexfarm/logs -name "*.log" -mtime +7 -deleteRun the basic validation script (requires tmux):
./validate.shcodex-cli-farm/
├── setup.sh # Main setup script
├── bin/ # Helper scripts
│ ├── codex-add # Add new Codex instances
│ ├── codex-annotator # Bash wrapper for annotator
│ ├── codex-annotator.py # Annotate tmux window titles (python)
│ ├── codex-save # Save manifest of windows
│ ├── codex-restore # Restore windows from manifest
│ ├── codex-watch # Monitor logs
│ ├── codex-board # Navigation helper
│ ├── codex-resume # Resume into existing session(s)
│ ├── codex-status # Status information
│ └── claude-* # Claude wrappers for the same commands
├── examples/
│ ├── demo.sh # End-to-end demo of farm
│ └── mock-codex # Fake CLI used by the demo
├── validate.sh # Basic repo validation script
└── README.md # This file
- Linux or Unix-like system
- Bash shell
- One of: apt, dnf, yum, pacman, or zypper package managers
- Root access for package installation
- If you don't have sudo/root, install
tmuxandmultitailmanually and rerun./setup.shto place scripts in~/bin.
- If you don't have sudo/root, install
tmuxcannot mirror the same live pane in two windows (use linked windows or logs)pipe-panelogs only new output after activation- Manifest
cmd/argsare best-effort when saving from existing panes; windows created withcodex-addrestore reliably. Use envCODEX_CMD/CODEX_ARGSto override.
Licensed under the MIT License. See LICENSE for full text.
Unless noted otherwise, all files in this repository are covered by the MIT License.