From 63d5502b4bbc7e2e249a414e4106d3ab0103cf76 Mon Sep 17 00:00:00 2001 From: valkyrie Date: Fri, 2 Jan 2026 18:52:56 -0800 Subject: [PATCH] fix(status): Reconcile tmux session state with bead state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gt status command now properly reconciles the tmux session existence with the agent bead state to surface mismatches: - If session exists AND bead says running/idle → "running" - If session exists BUT bead says stopped/dead → "running [bead: ]" - If session gone BUT bead says running/idle → "running [dead]" - If session gone AND bead says stopped → "stopped" This surfaces the key mismatch case where a tmux session is actually running but the bead state incorrectly says "stopped" or "dead". Fixes: gt-doih4 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/cmd/status.go | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/internal/cmd/status.go b/internal/cmd/status.go index 0e94e4f8..2a207fc6 100644 --- a/internal/cmd/status.go +++ b/internal/cmd/status.go @@ -471,14 +471,40 @@ func outputStatusText(status TownStatus) error { // renderAgentDetails renders full agent bead details func renderAgentDetails(agent AgentRuntime, indent string, hooks []AgentHookInfo, townRoot string) { // Line 1: Agent bead ID + status - statusStr := style.Success.Render("running") - if !agent.Running { + // Reconcile bead state with tmux session state to surface mismatches + // States: "running" (active), "idle" (waiting), "stopped", "dead", etc. + beadState := agent.State + sessionExists := agent.Running + + // "idle" is a normal operational state (running but waiting for work) + // Treat it the same as "running" for reconciliation purposes + beadSaysRunning := beadState == "running" || beadState == "idle" || beadState == "" + + var statusStr string + var stateInfo string + + switch { + case beadSaysRunning && sessionExists: + // Normal running state - session exists and bead agrees + statusStr = style.Success.Render("running") + case beadSaysRunning && !sessionExists: + // Bead thinks running but session is gone - stale bead state + statusStr = style.Error.Render("running") + stateInfo = style.Warning.Render(" [dead]") + case !beadSaysRunning && sessionExists: + // Session exists but bead says stopped/dead - mismatch! + // This is the key case: tmux says alive, bead says dead/stopped + statusStr = style.Success.Render("running") + stateInfo = style.Warning.Render(" [bead: " + beadState + "]") + default: + // Both agree: stopped statusStr = style.Error.Render("stopped") } - stateInfo := "" - if agent.State != "" && agent.State != "idle" && agent.State != "running" { - stateInfo = style.Dim.Render(fmt.Sprintf(" [%s]", agent.State)) + // Add agent state info if not already shown and state is interesting + // Skip "idle" and "running" as they're normal operational states + if stateInfo == "" && beadState != "" && beadState != "idle" && beadState != "running" { + stateInfo = style.Dim.Render(fmt.Sprintf(" [%s]", beadState)) } // Build agent bead ID using canonical naming: prefix-rig-role-name