diff --git a/internal/cmd/handoff.go b/internal/cmd/handoff.go index 2313c390..c51cdcbc 100644 --- a/internal/cmd/handoff.go +++ b/internal/cmd/handoff.go @@ -211,14 +211,17 @@ func runHandoff(cmd *cobra.Command, args []string) error { style.PrintWarning("could not set remain-on-exit: %v", err) } - // Kill all processes in the pane before respawning to prevent orphan leaks - // RespawnPane's -k flag only sends SIGHUP which Claude/Node may ignore - if err := t.KillPaneProcesses(pane); err != nil { - // Non-fatal but log the warning - style.PrintWarning("could not kill pane processes: %v", err) - } + // NOTE: For self-handoff, we do NOT call KillPaneProcesses here. + // That would kill the gt handoff process itself before it can call RespawnPane, + // leaving the pane dead with no respawn. RespawnPane's -k flag handles killing + // atomically - tmux kills the old process and spawns the new one together. + // See: https://github.com/steveyegge/gastown/issues/859 (pane is dead bug) + // + // For orphan prevention, we rely on respawn-pane -k which sends SIGHUP/SIGTERM. + // If orphans still occur, the solution is to adjust the restart command to + // kill orphans at startup, not to kill ourselves before respawning. - // Use exec to respawn the pane - this kills us and restarts + // Use respawn-pane -k to atomically kill current process and start new one // Note: respawn-pane automatically resets remain-on-exit to off return t.RespawnPane(pane, restartCmd) }