Skip to content

perf: launch sessions as initial tmux process to skip pane-ready poll#389

Open
naps62 wants to merge 1 commit intoasheshgoplani:mainfrom
naps62:fix/fast-session-launch
Open

perf: launch sessions as initial tmux process to skip pane-ready poll#389
naps62 wants to merge 1 commit intoasheshgoplani:mainfrom
naps62:fix/fast-session-launch

Conversation

@naps62
Copy link
Contributor

@naps62 naps62 commented Mar 19, 2026

Summary

  • For non-shell tools (claude, gemini, codex, opencode, custom), pass the command directly to tmux new-session as the initial process instead of starting a bare shell, polling for a prompt (up to 2s via waitForPaneReady), then sending keys
  • Eliminates ~1-2s of latency on every session launch
  • Shell sessions keep the legacy shell+send-keys flow for status detection compatibility
  • Commands with bash-specific syntax are wrapped in bash -c for fish shell compatibility

Test plan

  • Verified build passes
  • Verified existing tests pass (2 pre-existing failures unrelated to this change)
  • Manual test: launch a new Claude session from the TUI — should start noticeably faster
  • Manual test: launch a new shell session — should behave the same as before
  • Manual test: verify session status detection still works after launch

🤖 Generated with Claude Code

For non-shell tools (claude, gemini, codex, opencode, custom), pass the
command directly to `tmux new-session` instead of starting a shell,
polling for a prompt (up to 2s), and sending keys via send-keys.

This eliminates ~1-2s of latency on every session launch. Shell sessions
keep the legacy flow since they need a wrapping shell for status detection.

Commands with bash-specific syntax are wrapped in `bash -c` for fish
shell compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 19, 2026 18:28
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces session launch latency by starting non-shell tool commands directly as the initial tmux pane process (skipping the waitForPaneReady prompt poll + send-keys path), while keeping shell sessions on the legacy flow for status-detection compatibility.

Changes:

  • Launch commands via tmux new-session ... <command> when RunCommandAsInitialProcess is enabled, with conditional bash -c wrapping.
  • Keep a fallback path using send-keys when not launching as the initial process.
  • Enable RunCommandAsInitialProcess for all non-shell tools (and sandboxed sessions) in instance startup/restart flows.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
internal/tmux/tmux.go Adds initial-process launch path for faster session start; keeps send-keys fallback.
internal/session/instance.go Expands when RunCommandAsInitialProcess is enabled (non-shell tools + sandbox).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// Sandbox sessions also get remain-on-exit for dead-pane detection.
i.tmuxSession.OptionOverrides = i.buildTmuxOptionOverrides()
i.tmuxSession.RunCommandAsInitialProcess = i.IsSandboxed()
i.tmuxSession.RunCommandAsInitialProcess = i.IsSandboxed() || i.Tool != "shell"
Comment on lines +1191 to +1194
if strings.Contains(command, "$(") || strings.Contains(command, "session_id=") {
escapedCmd := strings.ReplaceAll(command, "'", "'\"'\"'")
cmdToStart = fmt.Sprintf("bash -c '%s'", escapedCmd)
}
Comment on lines +1190 to +1195
cmdToStart := command
if strings.Contains(command, "$(") || strings.Contains(command, "session_id=") {
escapedCmd := strings.ReplaceAll(command, "'", "'\"'\"'")
cmdToStart = fmt.Sprintf("bash -c '%s'", escapedCmd)
}
args = append(args, cmdToStart)
Comment on lines +1184 to +1195
// Create new tmux session in detached mode with the command as the initial
// process. This avoids the slow shell-wait-sendkeys path (~2s pane ready poll).
// Commands containing bash-specific syntax are wrapped for fish compatibility.
startWithInitialProcess := command != "" && s.RunCommandAsInitialProcess
args := []string{"new-session", "-d", "-s", s.Name, "-c", workDir}
if startWithInitialProcess {
args = append(args, command)
cmdToStart := command
if strings.Contains(command, "$(") || strings.Contains(command, "session_id=") {
escapedCmd := strings.ReplaceAll(command, "'", "'\"'\"'")
cmdToStart = fmt.Sprintf("bash -c '%s'", escapedCmd)
}
args = append(args, cmdToStart)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants