14 KiB
Codebase Concerns
Analysis Date: 2026-03-27
Silent Error Handling (Critical)
Widespread use of empty catch blocks:
- Files:
/.claude/hooks/gsd-prompt-guard.js,/.claude/hooks/gsd-context-monitor.js,/.claude/hooks/gsd-workflow-guard.js,/.claude/hooks/gsd-statusline.js,/.claude/hooks/gsd-check-update.js - Issue: 14+ catch blocks across hooks swallow errors silently with
catch (e) {}orcatch (e) { // comment }without logging - Impact: Failures in hook execution go undetected, making debugging difficult. When files are corrupted, config fails to parse, or file system errors occur, no indication is provided to users or developers
- Current mitigation: Comments explain intent (e.g., "Silent fail -- bridge is best-effort", "don't break statusline on parse errors"), but no logging mechanism exists
- Recommendation: Implement optional debug logging to stderr (only when hooks are invoked in debug mode) without breaking normal operation. Use environment variable like
GSD_HOOK_DEBUG=1to enable error logging
Fragile Hook Timeout Architecture
Context-Monitor Hook (.claude/hooks/gsd-context-monitor.js):
- Issue: 10-second stdin timeout (line 35) is tight for slow systems. On Windows/Git Bash, pipe delays can exceed this
- Files:
/.claude/hooks/gsd-context-monitor.js(line 35:setTimeout(() => process.exit(0), 10000)) - Current mitigation: Comments reference issues #775, #1162 indicating this was a known problem
- Risk: On systems with slow I/O, the hook exits prematurely without reading input, potentially leaving metrics unprocessed
- Safe modification: Consider detecting platform and adjusting timeout accordingly, or make timeout configurable via environment variable
Hardcoded Buffer Percentage
Status Line Hook Context Normalization:
- Issue: 16.5% buffer hardcoded for Claude Code autocompact (line 29)
- Files:
/.claude/hooks/gsd-statusline.js(line 29:const AUTO_COMPACT_BUFFER_PCT = 16.5) - Impact: If Claude Code changes autocompact behavior or other models have different buffers, context calculations become inaccurate
- Recommendation: Make this configurable via
.planning/config.jsonwith sensible defaults per model (Claude, Gemini, OpenCode)
Stale Hook Version Tracking
Hook Version Header Validation:
- Issue: Version detection depends on comment headers in JavaScript files (line 78 in
gsd-check-update.js) - Files:
/.claude/hooks/gsd-check-update.js(lines 73-92) - Risk: If hook files are minified, reformatted, or copied incorrectly, version headers can be lost, making stale hook detection fail silently
- Current state: Detects "unknown" version if header is missing, but this doesn't prevent the hook from running with wrong version
- Recommendation: Add a checksum or content hash validation in addition to version headers to detect unintended hook modifications
Process Detachment on Windows
Check-Update Hook Background Process:
- Issue: Uses
spawn()withdetached: true(line 111 ingsd-check-update.js) - Files:
/.claude/hooks/gsd-check-update.js(lines 108-114) - Impact: Background npm process can hang on Windows if not properly detached. Blocks are prevented by
unref()(line 114), but edge cases remain if process fails - Current state:
windowsHide: trueflag added,stdio: 'ignore'set - Recommendation: Add timeout to background spawn, return immediately after unref, and consider writing to log file instead of silently ignoring errors
Config File Parsing Without Validation
Multiple Hooks Read .planning/config.json:
- Issue: Config files are parsed with
JSON.parse()but no schema validation exists - Files:
/.claude/hooks/gsd-context-monitor.js(line 53),/.claude/hooks/gsd-workflow-guard.js(line 65) - Risk: Malformed JSON or missing expected fields cause silent failures. If config structure changes, old configs won't error but silently ignore new fields
- Recommendation: Implement a simple schema validation utility (even lightweight: check for required keys and types) and log warnings when config doesn't match expected shape
Race Conditions in Metrics Bridge
Context Metrics Between Statusline and Monitor Hooks:
- Issue: Two separate hooks read/write to
/tmp/claude-ctx-{sessionId}.jsonwithout file locking - Files:
/.claude/hooks/gsd-statusline.js(line 40-47 writes),/.claude/hooks/gsd-context-monitor.js(line 63-70 reads) - Risk: On high-frequency tool use, write and read can race, causing monitor hook to read stale metrics or corrupted JSON
- Current mitigation: Both have try-catch around JSON.parse(), stale metrics are detected by timestamp (line 74)
- Recommendation: Use atomic writes (write-to-temp-then-rename pattern) for metrics file, or switch to a simpler shared state mechanism
Missing Logging Infrastructure
No Structured Logging:
- Issue: Hooks only log to stdout via process.stdout.write() for hook outputs. No persistent logs for troubleshooting
- Files: All hook files (
/.claude/hooks/*.js) - Impact: When hooks fail silently, no audit trail exists to debug issues. Users cannot see what hooks detected or why they exited
- Recommendation: Create optional debug logs in
.planning/hooks-debug.log(only when env varGSD_DEBUG=1), append structured JSON records with timestamp, hook name, and outcome
Unbounded Memory in Warning State File
Context Monitor Warning Debounce:
- Issue: Warning state tracked in
/tmp/claude-ctx-{sessionId}-warned.jsonaccumulates indefinitely - Files:
/.claude/hooks/gsd-context-monitor.js(lines 87-117) - Risk: Temporary directory might not clean this up, causing stale state from previous sessions to affect new sessions
- Current mitigation: State is per-session (uses sessionId), so scope is limited
- Recommendation: Add timestamp to warning state and treat state older than 1 hour as stale (auto-reset)
Regex Pattern Complexity in Prompt Guard
Prompt Injection Detection Patterns:
- Issue: 12 regex patterns for injection detection (lines 18-32 in
gsd-prompt-guard.js) are not anchored and may be fragile - Files:
/.claude/hooks/gsd-prompt-guard.js(lines 18-32) - Risk: Some patterns (e.g.,
/you\s+are\s+now\s+/i) could match benign documentation text about "You are now ready to..." and trigger false warnings - Impact: While warnings are advisory-only, frequent false positives degrade user experience
- Recommendation: Review patterns for false positive risk, consider context (e.g., only in code blocks, not in comments), or add allowlist for common false positives
Inconsistent Hook Version Across Environments
Multi-Environment Hook Duplication:
- Issue: Identical hooks duplicated across
.claude/,.agent/,.gemini/,.opencode/directories - Files: 4x each of
gsd-prompt-guard.js,gsd-context-monitor.js,gsd-workflow-guard.js,gsd-statusline.js,gsd-check-update.js - Risk: If one environment's hooks are updated, others can drift out of sync. Version check in
gsd-check-update.jsdetects this (line 81-82) but doesn't auto-fix - Impact: Users with multiple agent environments may see inconsistent behavior
- Recommendation: Consolidate hooks to a shared location or implement auto-sync mechanism in installer
Resource Leaks in Timeouts
Stdin Timeout Cleanup:
- Issue:
setTimeout()created for stdin timeout in all hooks, relies onclearTimeout()to clean up - Files:
/.claude/hooks/gsd-prompt-guard.js,/.claude/hooks/gsd-context-monitor.js,/.claude/hooks/gsd-workflow-guard.js,/.claude/hooks/gsd-statusline.js - Risk: If process exits before reaching
process.stdin.on('end'), timeout continues running until expiry (3-10 seconds) - Current state: Process exits on timeout with code 0, but spawned processes inherit this timeout
- Recommendation: Add
unref()call on timeout timers so they don't keep process alive
Platform-Specific Path Separator
Windows Path Handling in Guards:
- Issue: Guards check for both
/and\\in file paths (e.g., line 52 ingsd-prompt-guard.js) - Files:
/.claude/hooks/gsd-prompt-guard.js(line 52),/.claude/hooks/gsd-workflow-guard.js(line 43) - Risk: Mixing separators when checking
.planning/paths may not catch all variations on Windows (e.g., mixed slashes) - Recommendation: Normalize paths using
path.normalize()before comparison, or usepath.sepfor platform detection
Missing Config Directory Override Documentation
CLAUDE_CONFIG_DIR Environment Variable:
- Issue: Support for
CLAUDE_CONFIG_DIRenvironment variable is implemented (line 18 ingsd-check-update.js, line 73 ingsd-statusline.js) but not documented - Files:
/.claude/hooks/gsd-check-update.js(line 18),/.claude/hooks/gsd-statusline.js(line 73) - Impact: Users with custom config directories won't know this variable exists, potentially breaking hook functionality
- Recommendation: Document in copilot-instructions.md or add reference in hook comments
Temporary File Cleanup Strategy
Metric Files Never Cleaned:
- Issue:
/tmp/claude-ctx-{sessionId}.jsonand/tmp/claude-ctx-{sessionId}-warned.jsonare never deleted - Files:
/.claude/hooks/gsd-statusline.js(writes),/.claude/hooks/gsd-context-monitor.js(reads) - Risk: On long-running systems, /tmp fills up with stale session files
- Recommendation: Implement cleanup logic to delete temp files older than 7 days, or hook into session cleanup to delete files on logout
Package.json Missing Dependencies
Minimal Configuration:
- Issue:
.claude/package.jsononly contains{"type":"commonjs"}, no dependencies listed - Files:
/.claude/package.json - Risk: Hooks use built-in Node modules (fs, path, os, child_process), so this is correct, but appears incomplete
- Current state: This is intentional (all hooks use only Node builtins), but unclear to maintainers
- Recommendation: Add comment in package.json explaining that hooks intentionally use no external dependencies for portability
Potential Memory Bloat in Large Outputs
No Stream Processing in Hooks:
- Issue: All hooks read entire stdin into memory before processing (
let input = ''; process.stdin.on('data', chunk => input += chunk)) - Files: All hook files
- Risk: If a tool call writes gigabytes of content (e.g., massive file read), the hook process could run out of memory
- Current mitigation: Only tool writes/edits are inspected, and these are typically small
- Recommendation: For hooks processing large content (especially prompt injection guard), implement streaming regex matching or line-by-line processing
Test Coverage Gaps
No Unit Tests for Hooks:
- What's not tested: None of the 5 hook files have automated tests
- Files:
/.claude/hooks/*.js(all of them) - Risk: Changes to hook logic have no regression protection. Timeout tweaks, path logic, or regex patterns could break without detection
- Impact: Hook failures are silent (by design), so broken hooks go unnoticed until users report issues
- Priority: High — hooks are critical path for agent context management
Missing Error Recovery in Executor
Deviation Rule Priority Conflicts:
- Issue: Executor auto-applies Rules 1-3 without clear priority when multiple rules could apply
- Files:
/.github/agents/gsd-executor.agent.md(line 150 mentions "RULE PRIORITY:") - Risk: When a task has multiple issues (e.g., bug AND missing critical functionality), executor might fix bug first, missing that missing-function blocking task completion
- Recommendation: Clarify priority order: blocking issues (Rule 3) > missing critical functionality (Rule 2) > bugs (Rule 1)
Subprocess Error Propagation in Background Checks
npm view Command Failure Silent:
- Issue:
execSync('npm view get-shit-done-cc version')wrapped in try-catch, timeout 10s (line 96 ingsd-check-update.js) - Files:
/.claude/hooks/gsd-check-update.js(lines 95-97) - Risk: If npm is not installed, offline, or slow, fails silently. Users won't know update check failed
- Impact: Latest version is set to "unknown", update check becomes unreliable
- Recommendation: Log to file when update check fails (optional debug log), or retry with exponential backoff
Missing Instrumentation for Decision Points
No Audit Trail for Hook Decisions:
- Issue: When context monitor injects critical warning or workflow guard injects advisory, no record of decision
- Files:
/.claude/hooks/gsd-context-monitor.js(lines 125-142),/.claude/hooks/gsd-workflow-guard.js(lines 78-87) - Risk: If user behavior doesn't match warning, no way to audit what warning was shown or when
- Recommendation: Write decision logs to
.planning/hooks-audit.logwith timestamp, hook name, decision, and reason (only in GSD active mode)
Scalability of Hook Frequency
Hooks Run on Every Tool Use:
- Issue: Context monitor (PostToolUse) runs after EVERY tool call, reads file, parses JSON, checks thresholds
- Files:
/.claude/hooks/gsd-context-monitor.js - Risk: On high-frequency tool sessions (100+ tools), accumulated overhead could impact performance
- Current mitigation: Debounce warnings (line 108), stale metric detection (line 74)
- Recommendation: Profile hook execution time under load, consider batching metrics or reducing check frequency
Unclear Behavior on Missing Files
Graceful Degradation Assumptions:
- Issue: When
.planning/STATE.md,.planning/config.json, or todo files don't exist, hooks silently skip functionality - Files: All hooks that check for optional files
- Risk: Unclear to users whether missing files are "normal" or indicate misconfiguration
- Example: Statusline shows "no task" if todos not found, but user might think todos are lost
- Recommendation: Distinguish between "feature not enabled" (e.g., no .planning/ = not a GSD project) vs. "feature broken" (e.g., config.json exists but unparseable)
Concerns audit: 2026-03-27