diff --git a/internal/config/loader.go b/internal/config/loader.go index b0d93dae..62a062e7 100644 --- a/internal/config/loader.go +++ b/internal/config/loader.go @@ -1235,55 +1235,23 @@ func BuildAgentStartupCommandWithAgentOverride(role, bdActor, rigPath, prompt, a // BuildPolecatStartupCommand builds the startup command for a polecat. // Sets GT_ROLE, GT_RIG, GT_POLECAT, BD_ACTOR, and GIT_AUTHOR_NAME. func BuildPolecatStartupCommand(rigName, polecatName, rigPath, prompt string) string { - bdActor := fmt.Sprintf("%s/polecats/%s", rigName, polecatName) - envVars := map[string]string{ - "GT_ROLE": "polecat", - "GT_RIG": rigName, - "GT_POLECAT": polecatName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": polecatName, - } - return BuildStartupCommand(envVars, rigPath, prompt) + return BuildStartupCommand(RoleEnvVars("polecat", rigName, polecatName), rigPath, prompt) } // BuildPolecatStartupCommandWithAgentOverride is like BuildPolecatStartupCommand, but uses agentOverride if non-empty. func BuildPolecatStartupCommandWithAgentOverride(rigName, polecatName, rigPath, prompt, agentOverride string) (string, error) { - bdActor := fmt.Sprintf("%s/polecats/%s", rigName, polecatName) - envVars := map[string]string{ - "GT_ROLE": "polecat", - "GT_RIG": rigName, - "GT_POLECAT": polecatName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": polecatName, - } - return BuildStartupCommandWithAgentOverride(envVars, rigPath, prompt, agentOverride) + return BuildStartupCommandWithAgentOverride(RoleEnvVars("polecat", rigName, polecatName), rigPath, prompt, agentOverride) } // BuildCrewStartupCommand builds the startup command for a crew member. // Sets GT_ROLE, GT_RIG, GT_CREW, BD_ACTOR, and GIT_AUTHOR_NAME. func BuildCrewStartupCommand(rigName, crewName, rigPath, prompt string) string { - bdActor := fmt.Sprintf("%s/crew/%s", rigName, crewName) - envVars := map[string]string{ - "GT_ROLE": "crew", - "GT_RIG": rigName, - "GT_CREW": crewName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": crewName, - } - return BuildStartupCommand(envVars, rigPath, prompt) + return BuildStartupCommand(RoleEnvVars("crew", rigName, crewName), rigPath, prompt) } // BuildCrewStartupCommandWithAgentOverride is like BuildCrewStartupCommand, but uses agentOverride if non-empty. func BuildCrewStartupCommandWithAgentOverride(rigName, crewName, rigPath, prompt, agentOverride string) (string, error) { - bdActor := fmt.Sprintf("%s/crew/%s", rigName, crewName) - envVars := map[string]string{ - "GT_ROLE": "crew", - "GT_RIG": rigName, - "GT_CREW": crewName, - "BD_ACTOR": bdActor, - "GIT_AUTHOR_NAME": crewName, - } - return BuildStartupCommandWithAgentOverride(envVars, rigPath, prompt, agentOverride) + return BuildStartupCommandWithAgentOverride(RoleEnvVars("crew", rigName, crewName), rigPath, prompt, agentOverride) } // ExpectedPaneCommands returns tmux pane command names that indicate the runtime is running. diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index 0a9186a2..c4498241 100755 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -847,17 +847,19 @@ func (d *Daemon) restartPolecatSession(rigName, polecatName, sessionName string) } // Set environment variables - _ = d.tmux.SetEnvironment(sessionName, "GT_ROLE", "polecat") - _ = d.tmux.SetEnvironment(sessionName, "GT_RIG", rigName) - _ = d.tmux.SetEnvironment(sessionName, "GT_POLECAT", polecatName) - - bdActor := fmt.Sprintf("%s/polecats/%s", rigName, polecatName) - _ = d.tmux.SetEnvironment(sessionName, "BD_ACTOR", bdActor) + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("polecat", rigName, polecatName) + // Add polecat-specific beads configuration beadsDir := filepath.Join(d.config.TownRoot, rigName, ".beads") - _ = d.tmux.SetEnvironment(sessionName, "BEADS_DIR", beadsDir) - _ = d.tmux.SetEnvironment(sessionName, "BEADS_NO_DAEMON", "1") - _ = d.tmux.SetEnvironment(sessionName, "BEADS_AGENT_NAME", fmt.Sprintf("%s/%s", rigName, polecatName)) + envVars["BEADS_DIR"] = beadsDir + envVars["BEADS_NO_DAEMON"] = "1" + envVars["BEADS_AGENT_NAME"] = fmt.Sprintf("%s/%s", rigName, polecatName) + + // Set all env vars in tmux session (for debugging) and they'll also be exported to Claude + for k, v := range envVars { + _ = d.tmux.SetEnvironment(sessionName, k, v) + } // Apply theme theme := tmux.AssignTheme(rigName) @@ -870,7 +872,7 @@ func (d *Daemon) restartPolecatSession(rigName, polecatName, sessionName string) // Launch Claude with environment exported inline // Pass rigPath so rig agent settings are honored (not town-level defaults) rigPath := filepath.Join(d.config.TownRoot, rigName) - startCmd := config.BuildPolecatStartupCommand(rigName, polecatName, rigPath, "") + startCmd := config.BuildStartupCommand(envVars, rigPath, "") if err := d.tmux.SendKeys(sessionName, startCmd); err != nil { return fmt.Errorf("sending startup command: %w", err) } diff --git a/internal/mayor/manager.go b/internal/mayor/manager.go index 6510a219..a2ec31fa 100644 --- a/internal/mayor/manager.go +++ b/internal/mayor/manager.go @@ -94,8 +94,11 @@ func (m *Manager) Start(agentOverride string) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_ROLE", "mayor") - _ = t.SetEnvironment(sessionID, "BD_ACTOR", "mayor") + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("mayor", "", "") + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) + } // Apply Mayor theming (non-fatal: theming failure doesn't affect operation) theme := tmux.MayorTheme() diff --git a/internal/refinery/manager.go b/internal/refinery/manager.go index 5eee6619..1fbe16b2 100644 --- a/internal/refinery/manager.go +++ b/internal/refinery/manager.go @@ -186,17 +186,23 @@ func (m *Manager) Start(foreground bool) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name) - _ = t.SetEnvironment(sessionID, "GT_REFINERY", "1") - _ = t.SetEnvironment(sessionID, "GT_ROLE", "refinery") - _ = t.SetEnvironment(sessionID, "BD_ACTOR", bdActor) + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("refinery", m.rig.Name, "") - // Set beads environment - refinery uses rig-level beads (non-fatal) + // Add refinery-specific flag + envVars["GT_REFINERY"] = "1" + + // Add beads environment - refinery uses rig-level beads // Use ResolveBeadsDir to handle both tracked (mayor/rig) and local beads beadsDir := beads.ResolveBeadsDir(m.rig.Path) - _ = t.SetEnvironment(sessionID, "BEADS_DIR", beadsDir) - _ = t.SetEnvironment(sessionID, "BEADS_NO_DAEMON", "1") - _ = t.SetEnvironment(sessionID, "BEADS_AGENT_NAME", fmt.Sprintf("%s/refinery", m.rig.Name)) + envVars["BEADS_DIR"] = beadsDir + envVars["BEADS_NO_DAEMON"] = "1" + envVars["BEADS_AGENT_NAME"] = envVars["BD_ACTOR"] + + // Set all env vars in tmux session (for debugging) and they'll also be exported to Claude + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) + } // Apply theme (non-fatal: theming failure doesn't affect operation) theme := tmux.AssignTheme(m.rig.Name) diff --git a/internal/witness/manager.go b/internal/witness/manager.go index 950fc782..c2181de9 100644 --- a/internal/witness/manager.go +++ b/internal/witness/manager.go @@ -164,9 +164,11 @@ func (m *Manager) Start(foreground bool) error { } // Set environment variables (non-fatal: session works without these) - _ = t.SetEnvironment(sessionID, "GT_ROLE", "witness") - _ = t.SetEnvironment(sessionID, "GT_RIG", m.rig.Name) - _ = t.SetEnvironment(sessionID, "BD_ACTOR", bdActor) + // Use shared RoleEnvVars for consistency across all role startup paths + envVars := config.RoleEnvVars("witness", m.rig.Name, "") + for k, v := range envVars { + _ = t.SetEnvironment(sessionID, k, v) + } // Apply Gas Town theming (non-fatal: theming failure doesn't affect operation) theme := tmux.AssignTheme(m.rig.Name)