Manages tmux sessions from a YAML config file. The script and its default config live together — the script always looks for tmux-sessions.yaml in the same directory as itself.
Script: {baseDir}/scripts/tmux-manager.py Default config: {baseDir}/scripts/tmux-sessions.yaml Sample config: {baseDir}/scripts/tmux-sessions.yaml.sample
To deploy: copy tmux-manager.py to any directory, place a tmux-sessions.yaml next to it, and run it with uv run from anywhere.
text
uv run {baseDir}/scripts/tmux-manager.py (--all | -s SESSION [...] | --session-group GROUP [...] [--window-group GROUP [...]] | --window-group GROUP [...]) [--kill | --restart] [--dry-run] [--list] [--config FILE]
uv run {baseDir}/scripts/tmux-manager.py --send-keys -s SESSION[:WINDOW] COMMAND
uv run {baseDir}/scripts/tmux-manager.py --tail -s SESSION[:WINDOW]
uv run {baseDir}/scripts/tmux-manager.py --validate [--config FILE]
uv run {baseDir}/scripts/tmux-manager.py --list-groups [--config FILE]
FlagMeaning--allTarget every session in the config--session-group GROUPTarget sessions by session_group (repeatable, comma-separated) — all windows created--window-group GROUPFilter to only matching windows (repeatable, comma-separated) — can be combined with --session-group``-s SESSIONTarget a specific session by name (repeatable)
--all and -s are mutually exclusive with everything else. --session-group and --window-group can be used together to scope both sessions and windows.
FlagMeaning_(no action flag)_Create targeted sessions; skip ones already running--killKill targeted sessions--restartKill then recreate targeted sessions--listShow status table (running/stopped) — no changes made--dry-runPreview what would happen — no changes made
FlagMeaning--tail -s SESSION[:WINDOW]Stream live pane output (Ctrl+C to stop)
FlagMeaning--send-keys -s SESSION[:WINDOW] "cmd"Send a shell command to a running session or specific window
FlagMeaning--config FILEUse an alternative config file--validateCheck config for errors and warnings (no selector needed)--list-groupsList all session groups and window groups (no selector needed)
bash
uv run {baseDir}/scripts/tmux-manager.py --all # create all sessions
uv run {baseDir}/scripts/tmux-manager.py --all --kill # kill all sessions in config
uv run {baseDir}/scripts/tmux-manager.py --all --restart # restart all sessions
uv run {baseDir}/scripts/tmux-manager.py --all --dry-run # preview what would be created
uv run {baseDir}/scripts/tmux-manager.py --all --list # list status of all sessions
uv run {baseDir}/scripts/tmux-manager.py --session-group work # create sessions in session-group 'work'
uv run {baseDir}/scripts/tmux-manager.py --session-group work --restart # restart sessions in session-group 'work'
uv run {baseDir}/scripts/tmux-manager.py --session-group work --list # list status of sessions in session-group 'work'
uv run {baseDir}/scripts/tmux-manager.py --kill --session-group work # kill all sessions in session-group 'work'
uv run {baseDir}/scripts/tmux-manager.py --window-group dev # create sessions, only 'dev' windows
uv run {baseDir}/scripts/tmux-manager.py --window-group dev --restart # restart with only 'dev' windows
uv run {baseDir}/scripts/tmux-manager.py --window-group claude,gemini # multiple groups, comma-separated
uv run {baseDir}/scripts/tmux-manager.py --window-group claude --window-group gemini # equivalent
uv run {baseDir}/scripts/tmux-manager.py --session-group TargetTracer,N8N --window-group claude,gemini # combined
uv run {baseDir}/scripts/tmux-manager.py -s my-session # create only my-session
uv run {baseDir}/scripts/tmux-manager.py --kill -s my-session # kill only my-session
uv run {baseDir}/scripts/tmux-manager.py --restart -s my-session # restart only my-session
uv run {baseDir}/scripts/tmux-manager.py --send-keys -s my-session "cmd" # send to active window
uv run {baseDir}/scripts/tmux-manager.py --send-keys -s my-session:claude "cmd" # send to specific window
uv run {baseDir}/scripts/tmux-manager.py --tail -s my-session # stream live pane output
uv run {baseDir}/scripts/tmux-manager.py --validate # validate config file
uv run {baseDir}/scripts/tmux-manager.py --list-groups # list all groups
uv run {baseDir}/scripts/tmux-manager.py --all --config ~/my-sessions.yaml # use a specific config
--restart to force recreate.--kill requires a selector — use --all --kill to kill everything managed by this config.--tail / --send-keys accept only a single -s SESSION[:WINDOW] target.SESSION[:WINDOW] — append :windowname to target a specific window, e.g. my-session:claude. Without it, the active window is used.--validate does not require a selector — warns on unknown fields, catching typos like window_grou or sesion_group.--list-groups does not require a selector — reads config only.pre_hook / post_hook run on the host shell, not inside tmux.pre_hook_fail: abort — stops session creation if the pre_hook exits non-zero. Default is warn (prints warning, continues).--window-group — sessions already running are skipped unless --restart is used. On restart, only the matching windows are created.--session-group + --window-group combined — narrows to the specified sessions first, then opens only the matching windows within them.session_group are only reachable via --all or -s.These operations don't need a wrapper — use tmux directly:
OperationNative commandKill all tmux sessionstmux kill-serverSnapshot pane outputtmux capture-pane -p -t SESSION[:WINDOW]
tmux-sessions.yaml.sample)#yaml
sessions:
# ── Project session (no env vars) ─────────────────────────────────────────
- name: Project_1
session_group: Project_1
working_dir: ~/Projects/Project_1
# focus: claude # which window to select after creation (optional)
windows:
- name: claude
window_group: claude # targeted by: --window-group claude
command: "claude --dangerously-skip-permissions --continue"
- name: gemini
window_group: gemini # targeted by: --window-group gemini
command: "gemini -y --resume"
- name: shell # no window_group — only opened via --session-group or --all
# no command = opens a plain shell
# ── Project session (with env vars) ───────────────────────────────────────
- name: Project_2
session_group: Project_2
working_dir: ~/Projects/Project_2
env:
NODE_ENV: development
PORT: 3000
windows:
#- name: server # uncomment to add a dev server window
# command: "npm run dev"
- name: claude
window_group: claude
command: "claude --dangerously-skip-permissions --continue"
- name: gemini
window_group: gemini
command: "gemini -y --resume"
- name: shell
window_group: shell
# no command = opens a plain shell
# ── Single-window utility session ─────────────────────────────────────────
- name: monitoring
session_group: system
working_dir: ~
command: "htop"
FieldLevelDescriptionnamesessionRequired. Must be unique.session_groupsessionOptional. String or list. Used with --session-group — targets the whole session. A session can belong to multiple groups.working_dirsession / windowStarting directory. Window value overrides session.focussessionWindow name to select after creation.pre_hooksessionShell command run before session is created.pre_hook_failsessionwarn (default) or abort — whether a failed pre_hook stops session creation.post_hooksessionShell command run after session is created.envsession / windowMap of env vars. Window env sent as export statements.commandsession / windowProgram to run. On session level, creates a single-window session.windowssessionList of windows. Overrides session-level command.window_groupwindowOptional. String or list. Used with --window-group — only matching windows are created. A window can belong to multiple groups.paneswindowList of panes to split the window into. Each can have command and working_dir.layoutwindowPane layout: tiled, even-horizontal, even-vertical, main-horizontal, main-vertical.