feat(spawn): migrate to NewSessionWithCommand pattern

Migrate witness, boot, and deacon spawns to use NewSessionWithCommand
instead of NewSession+SendKeys to ensure BD_ACTOR is visible in the
process tree for orphan detection via ps.

Refs: gt-emi5b

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
dementus
2026-01-13 01:27:03 -08:00
committed by beads/crew/emma
parent e7b0af0295
commit 38bedc03e8
3 changed files with 36 additions and 58 deletions

View File

@@ -351,9 +351,17 @@ func startDeaconSession(t *tmux.Tmux, sessionName, agentOverride string) error {
style.PrintWarning("Could not create deacon settings: %v", err)
}
// Create session in deacon directory
// Build startup command first
// Export GT_ROLE and BD_ACTOR in the command since tmux SetEnvironment only affects new panes
startupCmd, err := config.BuildAgentStartupCommandWithAgentOverride("deacon", "deacon", "", "", agentOverride)
if err != nil {
return fmt.Errorf("building startup command: %w", err)
}
// Create session with command directly to avoid send-keys race condition.
// See: https://github.com/anthropics/gastown/issues/280
fmt.Println("Starting Deacon session...")
if err := t.NewSession(sessionName, deaconDir); err != nil {
if err := t.NewSessionWithCommand(sessionName, deaconDir, startupCmd); err != nil {
return fmt.Errorf("creating session: %w", err)
}
@@ -373,18 +381,6 @@ func startDeaconSession(t *tmux.Tmux, sessionName, agentOverride string) error {
theme := tmux.DeaconTheme()
_ = t.ConfigureGasTownSession(sessionName, theme, "", "Deacon", "health-check")
// Launch Claude directly (no shell respawn loop)
// Restarts are handled by daemon via ensureDeaconRunning on each heartbeat
// The startup hook handles context loading automatically
// Export GT_ROLE and BD_ACTOR in the command since tmux SetEnvironment only affects new panes
startupCmd, err := config.BuildAgentStartupCommandWithAgentOverride("deacon", "deacon", "", "", agentOverride)
if err != nil {
return fmt.Errorf("building startup command: %w", err)
}
if err := t.SendKeys(sessionName, startupCmd); err != nil {
return fmt.Errorf("sending command: %w", err)
}
// Wait for Claude to start (non-fatal)
if err := t.WaitForCommand(sessionName, constants.SupportedShells, constants.ClaudeStartTimeout); err != nil {
// Non-fatal