From 0d665e6cd70161e3512869497016fc59b4ca0fca Mon Sep 17 00:00:00 2001 From: furiosa Date: Fri, 23 Jan 2026 16:15:51 -0800 Subject: [PATCH] fix(hooks): remove Stop hook that caused 30s timeouts (gt-quoj) The Stop hook with `gt costs record` was causing 30-second timeouts on every session stop due to beads socket connection issues. Since cost tracking is disabled anyway (Claude Code doesn't expose session costs), this hook provided no value. Changes: - Remove Stop hook from settings-autonomous.json and settings-interactive.json - Remove Stop hook validation from claude_settings_check.go - Update tests to not expect Stop hook The cost tracking infrastructure remains in costs.go for future use when Claude Code exposes session costs via API or environment variable. Co-Authored-By: Claude Opus 4.5 --- .../claude/config/settings-autonomous.json | 11 ---- .../claude/config/settings-interactive.json | 11 ---- internal/doctor/claude_settings_check.go | 11 ++-- internal/doctor/claude_settings_check_test.go | 57 +------------------ 4 files changed, 7 insertions(+), 83 deletions(-) diff --git a/internal/claude/config/settings-autonomous.json b/internal/claude/config/settings-autonomous.json index d858b685..1b0cea11 100644 --- a/internal/claude/config/settings-autonomous.json +++ b/internal/claude/config/settings-autonomous.json @@ -65,17 +65,6 @@ } ] } - ], - "Stop": [ - { - "matcher": "", - "hooks": [ - { - "type": "command", - "command": "export PATH=\"$HOME/go/bin:$HOME/bin:$PATH\" && gt costs record" - } - ] - } ] } } diff --git a/internal/claude/config/settings-interactive.json b/internal/claude/config/settings-interactive.json index 77a0b314..49130f23 100644 --- a/internal/claude/config/settings-interactive.json +++ b/internal/claude/config/settings-interactive.json @@ -65,17 +65,6 @@ } ] } - ], - "Stop": [ - { - "matcher": "", - "hooks": [ - { - "type": "command", - "command": "export PATH=\"$HOME/go/bin:$HOME/bin:$PATH\" && gt costs record" - } - ] - } ] } } diff --git a/internal/doctor/claude_settings_check.go b/internal/doctor/claude_settings_check.go index dda1b195..e548787a 100644 --- a/internal/doctor/claude_settings_check.go +++ b/internal/doctor/claude_settings_check.go @@ -335,8 +335,8 @@ func (c *ClaudeSettingsCheck) checkSettings(path, _ string) []string { // All templates should have: // 1. enabledPlugins // 2. PATH export in hooks - // 3. Stop hook with gt costs record (for autonomous) - // 4. gt nudge deacon session-started in SessionStart + // 3. gt nudge deacon session-started in SessionStart + // Note: Stop hook was removed (gt-quoj) - cost tracking is disabled // Check enabledPlugins if _, ok := actual["enabledPlugins"]; !ok { @@ -359,10 +359,9 @@ func (c *ClaudeSettingsCheck) checkSettings(path, _ string) []string { missing = append(missing, "deacon nudge") } - // Check Stop hook exists with gt costs record (for all roles) - if !c.hookHasPattern(hooks, "Stop", "gt costs record") { - missing = append(missing, "Stop hook") - } + // Note: Stop hook with gt costs record was removed in gt-quoj. + // Cost tracking is disabled - Claude Code doesn't expose session costs. + // The Stop hook was causing 30s timeouts on session stop with no benefit. return missing } diff --git a/internal/doctor/claude_settings_check_test.go b/internal/doctor/claude_settings_check_test.go index ca64ecd1..384e6af7 100644 --- a/internal/doctor/claude_settings_check_test.go +++ b/internal/doctor/claude_settings_check_test.go @@ -56,17 +56,6 @@ func createValidSettings(t *testing.T, path string) { }, }, }, - "Stop": []any{ - map[string]any{ - "matcher": "**", - "hooks": []any{ - map[string]any{ - "type": "command", - "command": "gt costs record --session $CLAUDE_SESSION_ID", - }, - }, - }, - }, }, } @@ -106,17 +95,6 @@ func createStaleSettings(t *testing.T, path string, missingElements ...string) { }, }, }, - "Stop": []any{ - map[string]any{ - "matcher": "**", - "hooks": []any{ - map[string]any{ - "type": "command", - "command": "gt costs record --session $CLAUDE_SESSION_ID", - }, - }, - }, - }, }, } @@ -156,9 +134,6 @@ func createStaleSettings(t *testing.T, path string, missingElements ...string) { } } hookObj["hooks"] = filtered - case "Stop": - hooks := settings["hooks"].(map[string]any) - delete(hooks, "Stop") } } @@ -374,33 +349,6 @@ func TestClaudeSettingsCheck_MissingDeaconNudge(t *testing.T) { } } -func TestClaudeSettingsCheck_MissingStopHook(t *testing.T) { - tmpDir := t.TempDir() - - // Create stale settings missing Stop hook (at correct location) - mayorSettings := filepath.Join(tmpDir, "mayor", ".claude", "settings.json") - createStaleSettings(t, mayorSettings, "Stop") - - check := NewClaudeSettingsCheck() - ctx := &CheckContext{TownRoot: tmpDir} - - result := check.Run(ctx) - - if result.Status != StatusError { - t.Errorf("expected StatusError for missing Stop hook, got %v", result.Status) - } - found := false - for _, d := range result.Details { - if strings.Contains(d, "Stop hook") { - found = true - break - } - } - if !found { - t.Errorf("expected details to mention Stop hook, got %v", result.Details) - } -} - func TestClaudeSettingsCheck_WrongLocationWitness(t *testing.T) { tmpDir := t.TempDir() rigName := "testrig" @@ -468,7 +416,7 @@ func TestClaudeSettingsCheck_MultipleStaleFiles(t *testing.T) { createStaleSettings(t, mayorSettings, "PATH") deaconSettings := filepath.Join(tmpDir, "deacon", ".claude", "settings.json") - createStaleSettings(t, deaconSettings, "Stop") + createStaleSettings(t, deaconSettings, "deacon-nudge") // Settings inside git repo (witness/rig/.claude/) are wrong location witnessWrong := filepath.Join(tmpDir, rigName, "witness", "rig", ".claude", "settings.json") @@ -1037,8 +985,7 @@ func TestClaudeSettingsCheck_TownRootSettingsWarnsInsteadOfKilling(t *testing.T) "env": {"PATH": "/usr/bin"}, "enabledPlugins": ["claude-code-expert"], "hooks": { - "SessionStart": [{"matcher": "", "hooks": [{"type": "command", "command": "gt prime"}]}], - "Stop": [{"matcher": "", "hooks": [{"type": "command", "command": "gt handoff"}]}] + "SessionStart": [{"matcher": "", "hooks": [{"type": "command", "command": "gt prime"}]}] } }` if err := os.WriteFile(staleTownRootSettings, []byte(settingsContent), 0644); err != nil {