fix(hooks): remove Stop hook that caused 30s timeouts (gt-quoj)
Some checks failed
CI / Check for .beads changes (push) Has been skipped
CI / Check embedded formulas (push) Failing after 18s
CI / Test (push) Failing after 1m33s
CI / Lint (push) Failing after 22s
CI / Integration Tests (push) Successful in 1m22s
CI / Coverage Report (push) Has been skipped
Windows CI / Windows Build and Unit Tests (push) Has been cancelled

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 <noreply@anthropic.com>
This commit is contained in:
furiosa
2026-01-23 16:15:51 -08:00
committed by John Ogle
parent 0eb2da6031
commit 089cf64c0b
4 changed files with 7 additions and 83 deletions

View File

@@ -64,17 +64,6 @@
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "export PATH=\"$HOME/go/bin:$HOME/bin:$PATH\" && gt costs record"
}
]
}
]
}
}

View File

@@ -64,17 +64,6 @@
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "export PATH=\"$HOME/go/bin:$HOME/bin:$PATH\" && gt costs record"
}
]
}
]
}
}

View File

@@ -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
}

View File

@@ -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 {