Bug Description
When dmux creates a new tmux session, it immediately sends the startup command via tmux send-keys without waiting for the shell in the pane to finish initializing. If the user has a heavy shell init (e.g., antigen, mise, starship, zoxide, atuin, direnv), the send-keys command fires before the shell is ready, causing the PATH='...' '/path/to/dmux' command to be echoed as raw text into the terminal instead of being executed.
The result is that dmux appears to silently fail — the user just sees the PATH string dumped to the terminal with no dmux TUI.
Steps to Reproduce
- Have a shell with heavy initialization (e.g., zsh with antigen, mise, starship, zoxide, atuin, direnv)
- Run dmux — it creates a new tmux session and immediately sends keys
- Observe that the
PATH='...' command string is printed as raw text rather than executed
Relevant Code Path
In dist/index.js:
- Line 232:
execSync('tmux new-session -d -s ${sessionName}', { stdio: 'inherit' }) — creates the session
- Line 248:
sendTmuxShellCommand(this.sessionName, dmuxCommand, 'inherit') — fires immediately after with no wait for shell readiness
sendTmuxShellCommand simply calls spawnSync('tmux', ['send-keys', '-t', target, command, 'Enter'], { stdio }).
The command sent is built by buildDmuxCommand in dist/utils/dmuxCommand.js and looks like PATH='...' '/path/to/dmux'.
There is no mechanism between session creation and send-keys to verify the shell has finished initializing and is ready to accept input.
Suggested Fix
A few possible approaches:
- Poll for shell readiness — after
tmux new-session, poll the pane (e.g., check for a prompt character via tmux capture-pane) before sending keys
- Use
tmux wait-for — have the shell signal readiness via tmux wait-for -S at the end of init, and wait on it before sending keys
- Use
tmux respawn-pane -k — instead of send-keys, use respawn-pane with the command directly, which replaces the shell process entirely and avoids the race
- Use tmux
set-option remain-on-exit + respawn-pane — start the pane with the dmux command directly rather than starting a shell and then injecting a command into it
Option 3 (respawn-pane) is likely the simplest and most robust, as it sidesteps the race entirely by not relying on shell readiness at all.
Bug Description
When dmux creates a new tmux session, it immediately sends the startup command via
tmux send-keyswithout waiting for the shell in the pane to finish initializing. If the user has a heavy shell init (e.g., antigen, mise, starship, zoxide, atuin, direnv), thesend-keyscommand fires before the shell is ready, causing thePATH='...' '/path/to/dmux'command to be echoed as raw text into the terminal instead of being executed.The result is that dmux appears to silently fail — the user just sees the PATH string dumped to the terminal with no dmux TUI.
Steps to Reproduce
PATH='...'command string is printed as raw text rather than executedRelevant Code Path
In
dist/index.js:execSync('tmux new-session -d -s ${sessionName}', { stdio: 'inherit' })— creates the sessionsendTmuxShellCommand(this.sessionName, dmuxCommand, 'inherit')— fires immediately after with no wait for shell readinesssendTmuxShellCommandsimply callsspawnSync('tmux', ['send-keys', '-t', target, command, 'Enter'], { stdio }).The command sent is built by
buildDmuxCommandindist/utils/dmuxCommand.jsand looks likePATH='...' '/path/to/dmux'.There is no mechanism between session creation and
send-keysto verify the shell has finished initializing and is ready to accept input.Suggested Fix
A few possible approaches:
tmux new-session, poll the pane (e.g., check for a prompt character viatmux capture-pane) before sending keystmux wait-for— have the shell signal readiness viatmux wait-for -Sat the end of init, and wait on it before sending keystmux respawn-pane -k— instead ofsend-keys, userespawn-panewith the command directly, which replaces the shell process entirely and avoids the raceset-option remain-on-exit+respawn-pane— start the pane with the dmux command directly rather than starting a shell and then injecting a command into itOption 3 (
respawn-pane) is likely the simplest and most robust, as it sidesteps the race entirely by not relying on shell readiness at all.