Codex CLI Farm
May 11, 2026 · View on GitHub
A tmux session manager for running and restoring multiple Codex CLI instances, with Claude and Gemini wrappers, logging, and monitoring built in.
Features
- 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
- Tool wrappers:
claude-*andgemini-*commands use the same tmux workflow
Quick Start
1. One-time Setup
Run the setup script to install dependencies and create helper scripts (source it to auto-reload your shell):
source ./setup.sh
This will:
- Install missing
tmuxandmultitailpackages when needed - Create helper scripts in
$HOME/bin/ - Set up logging directories
- Add
$HOME/binto your PATH automatically (bash/zsh/fish) and the current session
If tmux and multitail are already on your PATH, the setup script skips package-manager work. If multitail is unavailable, codex-watch falls back to a simpler tail view.
2. Add Codex, Claude, or Gemini Instances
From any project directory:
codex-add
Or specify a path:
codex-add /path/to/project
Use a named farm without exporting CODEX_SESSION:
codex-add work /path/to/project
codex-add work # current directory in the "work" farm
Claude and Gemini use the same tmux workflow with wrappers:
claude-add /path/to/project
gemini-add /path/to/project
3. Watch All Instances
Monitor all Codex logs in real-time:
codex-watch
Notes:
- 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.
4. Save/Restore or Resume
Snapshot your current Codex windows:
codex-save # writes to ~/.config/codexfarm/manifest.tsv
Restore them later (e.g., after reboot or on SSH login):
codex-restore -a # recreates and attaches to the session
Use -f to force re-creation of existing-named windows.
Saved Codex, Claude, and Gemini windows restore with exact session IDs when codex-save can read the live session file from the pane's process tree. If the exact session is unavailable, restore falls back by tool: codex resume --last, claude --continue, or gemini --resume latest.
If tmux sessions are already running (no manifest needed):
codex-resume # joins the main Codex session if present
codex-resume work # joins the named "work" farm
codex-resume work --board
Flags:
--boardto prefer the board session first.--session NAMEto force a specific farm when a positional argument would be ambiguous.
5. (Optional) Enable Autosave/Autorestore
codex-add can install systemd user services to autosave hourly and restore on login.
You can trigger it directly:
codex-add --install-autoservice
The installed units pin the selected tmux farm via CODEX_SESSION, so codex-add --session work --install-autoservice autosaves and restores the work farm.
Set CODEX_AUTOSERVICE_CHOICE=yes to auto-accept the prompt, or no to suppress it.
Status Annotations (RUN/READY/ERR)
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)
Available Commands
Core Commands
codex-add [session] [directory]- Add a new Codex instance, optionally selecting a named farmcodex-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] [session]- Manage the default or a named board session for navigationcodex-resume [session] [--board]- Attach/switch to an existing Codex/tmux session or named farm boardcodex-save [manifest]- Snapshot current windows to a manifest (TSV)codex-restore [-a] [-f] [manifest]- Restore windows from a manifest
Claude and Gemini Wrappers
Claude and Gemini 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, gemini-add, gemini-annotator, gemini-board, gemini-restore, gemini-resume, gemini-save, gemini-status, gemini-watch.
Environment Variables
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)
Tool-specific:
claude-addandgemini-addhonorCLAUDE_*orGEMINI_*versions of the common launch variables. For save/restore/resume/status/watch/board commands, select the farm withCODEX_SESSIONor the command's positional/--sessionargument where supported.
Example:
CODEX_CMD="cursor" CODEX_ARGS="--wait" codex-add /my/project
Flags:
codex-add -d: start without attaching (useful in SSH automation)codex-restore -a: attach after restoring;-fto replace same-named windows
Advanced Usage
Board Session for Fast Navigation
Create a separate board session for quick navigation. The default farm uses the legacy board session name; named farms use <farm>-board:
# Create board session for the default farm
codex-board create
# Create and use a named board
codex-board create work
codex-board link work
codex-board switch work
# Link all Codex windows to the default board
codex-board link
# Switch to the default board session
codex-board switch
Now you can use tmux switch-client -t board to scan through all Codex instances while the main codexfarm session continues running.
For named farms, codex-resume work --board jumps directly to work-board.
Remote SSH Tips
- 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.
Examples
-
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 - Start in a named farm without env vars:
codex-add work /path - Watch logs with multitail if available:
codex-watch
- Save then restore and attach:
Log Management
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 -delete
Validation
Run the basic validation script (requires tmux):
./validate.sh
File Structure
codex-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-* / gemini-* # Tool 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
Requirements
- Linux or Unix-like system
- Bash shell
lsofis optional but recommended so autosaved Codex, Claude, and Gemini windows can record exact resume commands- One of: apt, dnf, yum, pacman, or zypper package managers
- Root access for package installation
- If you don't have sudo/root, install
tmuxmanually and rerun./setup.shto place scripts in~/bin. multitailis optional; without it,codex-watchuses simple mode automatically.
- If you don't have sudo/root, install
Limitations
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. Exact session IDs are captured from live processes whenlsofcan see the open session file: Codex under~/.codex/sessions, Claude under~/.claude/projects, and Gemini under a.gemini/.../chatsdirectory. Missing IDs fall back to each tool's latest/continue behavior. - A single positional argument to
codex-addis interpreted as a farm name when it does not look like a path. Use--session NAMEto force farm selection when needed.
License
Licensed under the MIT License. See LICENSE for full text.
Unless noted otherwise, all files in this repository are covered by the MIT License.