X Tutup
Skip to content

tmuxinator/teamocil feature parity #1016

@tony

Description

@tony

Summary

Tracking issue for reaching feature parity with tmuxinator (3.3.7) and teamocil (1.4.2). Based on a comprehensive source-level analysis of both projects, their importers, and the tmuxp builder/loader/CLI.

Tracking issue for libtmux-side API additions: tmux-python/libtmux#635


Phase 1: Import Fixes (No Builder/libtmux Changes)

These fix existing bugs and add missing translations without touching the builder.

I1. tmuxinator pre / pre_window Mapping Bugs

Two bugs in importers.py:59-70:

Bug A — Solo pre maps to wrong key: When only pre exists (no pre_window), it maps to shell_command_before — a per-pane key. But tmuxinator's pre runs once before any windows are created. Correct target: before_script.

Bug B — Combo pre + pre_window loses pre: When both exist, pre maps to shell_command (invalid session key, silently ignored). The isinstance check on line 62 tests the wrong variable (pre instead of pre_window).

Correct mapping: pre -> before_script, pre_window -> shell_command_before

Note: before_script uses Popen without shell=True (util.py:27-32), so pipes/&&/redirects won't work. Forward path is on_project_start (T6).

I2. tmuxinator cli_args / tmux_options Fragile Parsing

str.replace("-f", "").strip() at importers.py:41,48 does global string replacement, not flag-aware parsing. Ignores -L (socket name) and -S (socket path) flags entirely.

Fix: Use shlex.split() + iterate to find -f flag and its value.

I3. teamocil Redundant Filter Loops

for _b in w["filters"]["before"]: loops at importers.py:145-149 iterate N times but set the same value each time.

Fix: Replace with direct assignment.

I4. teamocil v1.x Format Not Supported

Importer assumes v0.x format. String panes (v1.x format) are not handled — when p is a string, if "cmd" in p performs substring containment instead of dict key lookup, and p.pop("cmd") would raise AttributeError. commands key (v1.x) not mapped.

v0.x pane width is silently dropped (importers.py:161-163). height is not even popped — it passes through as a dead key. libtmux's Pane.resize() exists, so both could be preserved.

Fix: Add format detection. Handle string panes, commands key, focus, and options.

I5. tmuxinator Missing Keys

Not imported but translatable:

  • rvm -> shell_command_before: ["rvm use {value}"]
  • pre_tab -> shell_command_before (deprecated predecessor to pre_window)
  • startup_window -> find matching window, set focus: true
  • startup_pane -> find matching pane, set focus: true
  • on_project_first_start -> before_script
  • post -> deprecated predecessor to on_project_exit (needs T6)
  • socket_path -> warn user to use CLI -S flag
  • attach: false -> warn user to use CLI -d flag

I6. teamocil Missing Keys

v1.x keys (same key names in tmuxp):

  • commands -> shell_command
  • focus (window/pane) -> focus (pass-through)
  • options (window) -> options (pass-through)
  • String pane shorthand -> shell_command: [command]

v0.x keys:

  • with_env_var -> environment: { TEAMOCIL: "1" }
  • height (pane) -> should be popped like width

I7. Importer TODOs Need Triage

importers.py:121,123 lists with_env_var and cmd_separator as TODOs. Both are verified v0.x features (not stale):

  • with_env_var: Implement — map to environment: { TEAMOCIL: "1" }
  • clear: Preserved in config at line 141 (window_dict["clear"] = w["clear"]) but builder ignores it. libtmux has Pane.clear().
  • cmd_separator: Remove TODO — irrelevant since tmuxp sends commands individually.

Phase 2: Builder Additions (tmuxp Only)

T1. No synchronize Config Key

WorkspaceBuilder does not check for synchronize on window configs. Silently ignored.

Blocks: tmuxinator synchronize: true/before/after.

Implementation: window.set_option("synchronize-panes", "on") — before pane commands for before/true, in config_after_window() for after.

T3. No shell_command_after Config Key

Teamocil importer produces shell_command_after (from filters.after), but builder never reads it.

Blocks: teamocil v0.x filters.after.

Implementation: Read window_config.get("shell_command_after", []) in config_after_window() and send to panes.

T4. No Session Rename Mode / --here CLI Flag

tmuxp load has no --here flag. Always creates new windows.

Blocks: teamocil --here (reuse current window for first window) and session rename mode.

Implementation: Add --here to cli/load.py. For first window: rename_window() + send_keys("cd <root>") instead of new_window(). Also rename_session() when --here is used.


Phase 3: libtmux Additions

Tracked in tmux-python/libtmux#635

T2. No Pane Title Config Key

Depends on: libtmux Pane.set_title() (L1)

Implementation: Session-level enable_pane_titles, pane_title_position, pane_title_format via session.set_option(). Per-pane title via pane.set_title().


Phase 4: New CLI Commands

T5. No stop / kill CLI Command

tmuxp has no stop command.

Blocks: tmuxinator stop / stop-all.

Implementation: tmuxp stop <session> — find session, call session.kill(). Run on_project_stop hook before kill.

T10. Missing Config Management Commands

tmuxp only has edit. Missing: new, copy, delete.

Blocks: tmuxinator new, copy, delete, implode.


Phase 5: Larger Features (Nice-to-Have)

T6. No Lifecycle Hook Config Keys

tmuxp's plugin system has 5 Python hooks, but no config-driven shell command hooks.

Blocks: tmuxinator on_project_start, on_project_first_start, on_project_restart, on_project_exit, on_project_stop.

Mapping:

  • on_project_start -> run at start of build(), before before_script
  • on_project_first_start -> partially covered by before_script
  • on_project_restart -> run on reattach
  • on_project_exit -> session.set_hook("client-detached", cmd)
  • on_project_stop -> run in tmuxp stop (T5)

T7. --no-shell-command-before CLI Flag

Skip shell_command_before for debugging. Equivalent to tmuxinator --no-pre-window.

T8. Config Templating

tmuxp has no user-defined variable interpolation (env vars work, custom key=value does not).

Blocks: tmuxinator ERB templating.

T9. --debug / Dry-Run CLI Flag

Depends on: libtmux L3 (pre-execution logging)

L2. Custom tmux Binary

Depends on: libtmux L2

Blocks: tmuxinator tmux_command: wemux


Dead Config Keys

Keys produced by importers but silently ignored by the builder:

Key Producer Issue
shell_command (session-level) tmuxinator Bug I1-B: pre commands lost
config tmuxinator Dead data — extracted -f path unused
socket_name tmuxinator Dead data — CLI uses -L flag
clear teamocil Builder doesn't read it (libtmux has Pane.clear())
height (pane) teamocil width is popped but height passes through
target (pane) teamocil Accidentally preserved (libtmux has Pane.split(target=...))
shell_command_after teamocil Builder has no after-command support

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      X Tutup