From 69299e9a4398cc211dab733f25647b2d67e52f5b Mon Sep 17 00:00:00 2001 From: mayor Date: Fri, 9 Jan 2026 11:36:11 -0700 Subject: [PATCH] Fix gt shutdown to stop daemon (fixes #299) gt shutdown was not stopping the daemon, which caused it to restart agents (witnesses, refineries) after shutdown completed. The daemon heartbeats every 3 minutes and calls ensureWitnessesRunning() and ensureRefineriesRunning(), which would notice the sessions were dead and restart them. This adds daemon stop logic to both runGracefulShutdown (as Phase 6) and runImmediateShutdown (after polecat cleanup), matching the behavior that gt down already has. Co-Authored-By: Claude Opus 4.5 --- internal/cmd/start.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/internal/cmd/start.go b/internal/cmd/start.go index 9851ef0c..ee3cb16f 100644 --- a/internal/cmd/start.go +++ b/internal/cmd/start.go @@ -13,6 +13,7 @@ import ( "github.com/steveyegge/gastown/internal/config" "github.com/steveyegge/gastown/internal/constants" "github.com/steveyegge/gastown/internal/crew" + "github.com/steveyegge/gastown/internal/daemon" "github.com/steveyegge/gastown/internal/deacon" "github.com/steveyegge/gastown/internal/git" "github.com/steveyegge/gastown/internal/mayor" @@ -465,6 +466,12 @@ func runGracefulShutdown(t *tmux.Tmux, gtSessions []string, townRoot string) err cleanupPolecats(townRoot) } + // Phase 6: Stop the daemon + fmt.Printf("\nPhase 6: Stopping daemon...\n") + if townRoot != "" { + stopDaemonIfRunning(townRoot) + } + fmt.Println() fmt.Printf("%s Graceful shutdown complete (%d sessions stopped)\n", style.Bold.Render("✓"), stopped) return nil @@ -484,6 +491,13 @@ func runImmediateShutdown(t *tmux.Tmux, gtSessions []string, townRoot string) er cleanupPolecats(townRoot) } + // Stop the daemon + if townRoot != "" { + fmt.Println() + fmt.Println("Stopping daemon...") + stopDaemonIfRunning(townRoot) + } + fmt.Println() fmt.Printf("%s Gas Town shutdown complete (%d sessions stopped)\n", style.Bold.Render("✓"), stopped) @@ -633,6 +647,21 @@ func cleanupPolecats(townRoot string) { } } +// stopDaemonIfRunning stops the daemon if it is running. +// This prevents the daemon from restarting agents after shutdown. +func stopDaemonIfRunning(townRoot string) { + running, _, _ := daemon.IsRunning(townRoot) + if running { + if err := daemon.StopDaemon(townRoot); err != nil { + fmt.Printf(" %s Daemon: %s\n", style.Dim.Render("○"), err.Error()) + } else { + fmt.Printf(" %s Daemon stopped\n", style.Bold.Render("✓")) + } + } else { + fmt.Printf(" %s Daemon not running\n", style.Dim.Render("○")) + } +} + // runStartCrew starts a crew workspace, creating it if it doesn't exist. // This combines the functionality of 'gt crew add' and 'gt crew at --detached'. func runStartCrew(cmd *cobra.Command, args []string) error {