Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions internal/cmd/deacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,14 @@ func startDeaconSession(t *tmux.Tmux, sessionName, agentOverride string) error {
return fmt.Errorf("creating deacon directory: %w", err)
}

// Resolve CLAUDE_CONFIG_DIR from accounts.json so deacon sessions
// use the correct account. Mirrors the daemon restart path (lifecycle.go).
accountsPath := constants.MayorAccountsPath(townRoot)
runtimeConfigDir, _, _ := config.ResolveAccountConfigDir(accountsPath, "")
if runtimeConfigDir == "" {
runtimeConfigDir = os.Getenv("CLAUDE_CONFIG_DIR")
}

// Ensure runtime settings exist (autonomous role needs mail in SessionStart)
runtimeConfig := config.ResolveRoleAgentConfig("deacon", townRoot, deaconDir)
if err := runtime.EnsureSettingsForRole(deaconDir, deaconDir, "deacon", runtimeConfig); err != nil {
Expand All @@ -520,11 +528,12 @@ func startDeaconSession(t *tmux.Tmux, sessionName, agentOverride string) error {
Topic: "patrol",
}, "I am Deacon. First run `gt deacon heartbeat`. Then check gt hook, if empty create mol-deacon-patrol wisp and execute it.")
startupCmd, err := config.BuildStartupCommandFromConfig(config.AgentEnvConfig{
Role: "deacon",
TownRoot: townRoot,
Prompt: initialPrompt,
Topic: "patrol",
SessionName: sessionName,
Role: "deacon",
TownRoot: townRoot,
RuntimeConfigDir: runtimeConfigDir,
Prompt: initialPrompt,
Topic: "patrol",
SessionName: sessionName,
}, "", initialPrompt, agentOverride)
if err != nil {
return fmt.Errorf("building startup command: %w", err)
Expand All @@ -540,9 +549,10 @@ func startDeaconSession(t *tmux.Tmux, sessionName, agentOverride string) error {
// Set environment (non-fatal: session works without these)
// Use centralized AgentEnv for consistency across all role startup paths
envVars := config.AgentEnv(config.AgentEnvConfig{
Role: "deacon",
TownRoot: townRoot,
Agent: agentOverride,
Role: "deacon",
TownRoot: townRoot,
RuntimeConfigDir: runtimeConfigDir,
Agent: agentOverride,
})
for k, v := range envVars {
_ = t.SetEnvironment(sessionName, k, v)
Expand Down
33 changes: 22 additions & 11 deletions internal/refinery/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,15 @@ func (m *Manager) Start(foreground bool, agentOverride string) error {
// Ensure runtime settings exist in the shared refinery parent directory.
// Settings are passed to Claude Code via --settings flag.
townRoot := filepath.Dir(m.rig.Path)

// Resolve CLAUDE_CONFIG_DIR from accounts.json so refinery sessions
// use the correct account. Mirrors the daemon restart path (lifecycle.go).
accountsPath := constants.MayorAccountsPath(townRoot)
runtimeConfigDir, _, _ := config.ResolveAccountConfigDir(accountsPath, "")
if runtimeConfigDir == "" {
runtimeConfigDir = os.Getenv("CLAUDE_CONFIG_DIR")
}

runtimeConfig := config.ResolveRoleAgentConfig("refinery", townRoot, m.rig.Path)
refinerySettingsDir := config.RoleSettingsDir("refinery", m.rig.Path)
if err := runtime.EnsureSettingsForRole(refinerySettingsDir, refineryRigDir, "refinery", runtimeConfig); err != nil {
Expand All @@ -185,12 +194,13 @@ func (m *Manager) Start(foreground bool, agentOverride string) error {
}, "Run `gt prime --hook` and begin patrol.")

command, err := config.BuildStartupCommandFromConfig(config.AgentEnvConfig{
Role: "refinery",
Rig: m.rig.Name,
TownRoot: townRoot,
Prompt: initialPrompt,
Topic: "patrol",
SessionName: sessionID,
Role: "refinery",
Rig: m.rig.Name,
TownRoot: townRoot,
RuntimeConfigDir: runtimeConfigDir,
Prompt: initialPrompt,
Topic: "patrol",
SessionName: sessionID,
}, m.rig.Path, initialPrompt, agentOverride)
if err != nil {
return fmt.Errorf("building startup command: %w", err)
Expand All @@ -208,11 +218,12 @@ func (m *Manager) Start(foreground bool, agentOverride string) error {
// Set environment variables (non-fatal: session works without these)
// Use centralized AgentEnv for consistency across all role startup paths
envVars := config.AgentEnv(config.AgentEnvConfig{
Role: "refinery",
Rig: m.rig.Name,
TownRoot: townRoot,
Agent: agentOverride,
SessionName: sessionID,
Role: "refinery",
Rig: m.rig.Name,
TownRoot: townRoot,
RuntimeConfigDir: runtimeConfigDir,
Agent: agentOverride,
SessionName: sessionID,
})
envVars = session.MergeRuntimeLivenessEnv(envVars, runtimeConfig)

Expand Down
37 changes: 24 additions & 13 deletions internal/witness/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ func (m *Manager) Start(foreground bool, agentOverride string, envOverrides []st
// package config) to prevent concurrent rig starts from corrupting the
// global agent registry.
townRoot := m.townRoot()

// Resolve CLAUDE_CONFIG_DIR from accounts.json so witness sessions
// use the correct account. Mirrors the daemon restart path (lifecycle.go).
accountsPath := constants.MayorAccountsPath(townRoot)
runtimeConfigDir, _, _ := config.ResolveAccountConfigDir(accountsPath, "")
if runtimeConfigDir == "" {
runtimeConfigDir = os.Getenv("CLAUDE_CONFIG_DIR")
}

runtimeConfig := config.ResolveRoleAgentConfig("witness", townRoot, m.rig.Path)
witnessSettingsDir := config.RoleSettingsDir("witness", m.rig.Path)
if err := runtime.EnsureSettingsForRole(witnessSettingsDir, witnessDir, "witness", runtimeConfig); err != nil {
Expand All @@ -180,7 +189,7 @@ func (m *Manager) Start(foreground bool, agentOverride string, envOverrides []st
// NOTE: No gt prime injection needed - SessionStart hook handles it automatically
// Export GT_ROLE and BD_ACTOR in the command since tmux SetEnvironment only affects new panes
// Pass m.rig.Path so rig agent settings are honored (not town-level defaults)
command, err := buildWitnessStartCommand(m.rig.Path, m.rig.Name, townRoot, sessionID, agentOverride, roleConfig)
command, err := buildWitnessStartCommand(m.rig.Path, m.rig.Name, townRoot, sessionID, agentOverride, roleConfig, runtimeConfigDir)
if err != nil {
return err
}
Expand All @@ -197,11 +206,12 @@ func (m *Manager) Start(foreground bool, agentOverride string, envOverrides []st
// Set environment variables (non-fatal: session works without these)
// Use centralized AgentEnv for consistency across all role startup paths
envVars := config.AgentEnv(config.AgentEnvConfig{
Role: "witness",
Rig: m.rig.Name,
TownRoot: townRoot,
Agent: agentOverride,
SessionName: sessionID,
Role: "witness",
Rig: m.rig.Name,
TownRoot: townRoot,
RuntimeConfigDir: runtimeConfigDir,
Agent: agentOverride,
SessionName: sessionID,
})
envVars = session.MergeRuntimeLivenessEnv(envVars, runtimeConfig)
for k, v := range envVars {
Expand Down Expand Up @@ -311,7 +321,7 @@ func roleConfigEnvVars(roleConfig *beads.RoleConfig, townRoot, rigName string) m
return expanded
}

func buildWitnessStartCommand(rigPath, rigName, townRoot, sessionName, agentOverride string, roleConfig *beads.RoleConfig) (string, error) {
func buildWitnessStartCommand(rigPath, rigName, townRoot, sessionName, agentOverride string, roleConfig *beads.RoleConfig, runtimeConfigDir string) (string, error) {
if agentOverride != "" {
roleConfig = nil
}
Expand Down Expand Up @@ -343,12 +353,13 @@ func buildWitnessStartCommand(rigPath, rigName, townRoot, sessionName, agentOver
Topic: "patrol",
}, "Run `gt prime --hook` and begin patrol.")
command, err := config.BuildStartupCommandFromConfig(config.AgentEnvConfig{
Role: "witness",
Rig: rigName,
TownRoot: townRoot,
Prompt: initialPrompt,
Topic: "patrol",
SessionName: sessionName,
Role: "witness",
Rig: rigName,
TownRoot: townRoot,
RuntimeConfigDir: runtimeConfigDir,
Prompt: initialPrompt,
Topic: "patrol",
SessionName: sessionName,
}, rigPath, initialPrompt, agentOverride)
if err != nil {
return "", fmt.Errorf("building startup command: %w", err)
Expand Down
18 changes: 15 additions & 3 deletions internal/witness/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func TestBuildWitnessStartCommand_UsesRoleConfig(t *testing.T) {
StartCommand: "exec run --town {town} --rig {rig} --role {role}",
}

got, err := buildWitnessStartCommand("/town/rig", "gastown", "/town", "", "", roleCfg)
got, err := buildWitnessStartCommand("/town/rig", "gastown", "/town", "", "", roleCfg, "")
if err != nil {
t.Fatalf("buildWitnessStartCommand: %v", err)
}
Expand All @@ -26,7 +26,7 @@ func TestBuildWitnessStartCommand_UsesRoleConfig(t *testing.T) {

func TestBuildWitnessStartCommand_DefaultsToRuntime(t *testing.T) {
t.Parallel()
got, err := buildWitnessStartCommand("/town/rig", "gastown", "/town", "", "", nil)
got, err := buildWitnessStartCommand("/town/rig", "gastown", "/town", "", "", nil, "")
if err != nil {
t.Fatalf("buildWitnessStartCommand: %v", err)
}
Expand Down Expand Up @@ -68,13 +68,25 @@ func TestRoleConfigEnvVars_NilConfig(t *testing.T) {
}
}

func TestBuildWitnessStartCommand_IncludesConfigDir(t *testing.T) {
t.Parallel()
got, err := buildWitnessStartCommand("/town/rig", "gastown", "/town", "", "", nil, "/home/user/.claude-accounts/work")
if err != nil {
t.Fatalf("buildWitnessStartCommand: %v", err)
}

if !strings.Contains(got, "CLAUDE_CONFIG_DIR=/home/user/.claude-accounts/work") {
t.Errorf("expected CLAUDE_CONFIG_DIR in command, got %q", got)
}
}

func TestBuildWitnessStartCommand_AgentOverrideWins(t *testing.T) {
t.Parallel()
roleCfg := &beads.RoleConfig{
StartCommand: "exec run --role {role}",
}

got, err := buildWitnessStartCommand("/town/rig", "gastown", "/town", "", "codex", roleCfg)
got, err := buildWitnessStartCommand("/town/rig", "gastown", "/town", "", "codex", roleCfg, "")
if err != nil {
t.Fatalf("buildWitnessStartCommand: %v", err)
}
Expand Down
Loading