Get the FREE Ultimate OpenClaw Setup Guide →

debug-hooks

npx machina-cli add skill parcadei/Continuous-Claude-v3/debug-hooks --openclaw
Files (1)
SKILL.md
3.4 KB

Debug Hooks

Systematic workflow for debugging Claude Code hooks.

When to Use

  • "Hook isn't firing"
  • "Hook produces wrong output"
  • "SessionEnd not working"
  • "PostToolUse hook not triggering"
  • "Why didn't my hook run?"

Workflow

1. Check Outputs First (Observe Before Editing)

# Check project cache
ls -la $CLAUDE_PROJECT_DIR/.claude/cache/

# Check specific outputs
ls -la $CLAUDE_PROJECT_DIR/.claude/cache/learnings/

# Check for debug logs
tail $CLAUDE_PROJECT_DIR/.claude/cache/*.log 2>/dev/null

# Also check global (common mistake: wrong path)
ls -la ~/.claude/cache/ 2>/dev/null

2. Verify Hook Registration

# Project settings
cat $CLAUDE_PROJECT_DIR/.claude/settings.json | grep -A 20 '"SessionEnd"\|"PostToolUse"\|"UserPromptSubmit"'

# Global settings (hooks merge from both)
cat ~/.claude/settings.json | grep -A 20 '"SessionEnd"\|"PostToolUse"\|"UserPromptSubmit"'

3. Check Hook Files Exist

# Shell wrappers
ls -la $CLAUDE_PROJECT_DIR/.claude/hooks/*.sh

# Compiled bundles (if using TypeScript)
ls -la $CLAUDE_PROJECT_DIR/.claude/hooks/dist/*.mjs

4. Test Hook Manually

# SessionEnd hook
echo '{"session_id": "test-123", "reason": "clear", "transcript_path": "/tmp/test"}' | \
  $CLAUDE_PROJECT_DIR/.claude/hooks/session-end-cleanup.sh

# PostToolUse hook (Write tool example)
echo '{"tool_name": "Write", "tool_input": {"file_path": "test.md"}, "session_id": "test-123"}' | \
  $CLAUDE_PROJECT_DIR/.claude/hooks/handoff-index.sh

5. Check for Silent Failures

If using detached spawn with stdio: 'ignore':

// This pattern hides errors!
spawn(cmd, args, { detached: true, stdio: 'ignore' })

Fix: Add temporary logging:

const logFile = fs.openSync('.claude/cache/debug.log', 'a');
spawn(cmd, args, {
  detached: true,
  stdio: ['ignore', logFile, logFile]  // capture stdout/stderr
});

6. Rebuild After Edits

If you edited TypeScript source, you MUST rebuild:

cd $CLAUDE_PROJECT_DIR/.claude/hooks
npx esbuild src/session-end-cleanup.ts \
  --bundle --platform=node --format=esm \
  --outfile=dist/session-end-cleanup.mjs

Source edits alone don't take effect - the shell wrapper runs the bundled .mjs.

Common Issues

SymptomLikely CauseFix
Hook never runsNot registered in settings.jsonAdd to correct event in settings
Hook runs but no outputDetached spawn hiding errorsAdd logging, check manually
Wrong session IDUsing "most recent" queryPass ID explicitly
Works locally, not in CIMissing dependenciesCheck npx/node availability
Runs twiceRegistered in both global + projectRemove duplicate

Debug Checklist

  • Outputs exist? (ls -la .claude/cache/)
  • Registered? (grep -A10 '"hooks"' .claude/settings.json)
  • Files exist? (ls .claude/hooks/*.sh)
  • Bundle current? (ls -la .claude/hooks/dist/)
  • Manual test works? (echo '{}' | ./hook.sh)
  • No silent failures? (check for stdio: 'ignore')

Source Sessions

Derived from 10 sessions (83% of all learnings):

  • a541f08a, 1c21e6c8, 6a9f2d7a, a8bd5cea, 2ca1a178, 657ce0b2, 3998f3a2, 2a829f12, 0b46cfd7, 862f6e2c

Source

git clone https://github.com/parcadei/Continuous-Claude-v3/blob/main/.claude/skills/debug-hooks/SKILL.mdView on GitHub

Overview

Debug-hooks provides a structured, step-by-step workflow to diagnose Claude Code hooks that don’t fire, produce incorrect outputs, or behave unexpectedly. It guides you from initial observation through registration checks, file verification, manual testing, and finally rebuilding after edits to ensure hooks run reliably.

How This Skill Works

The workflow uses command-line checks to inspect cache, settings, and hook scripts, then performs manual tests by piping JSON into hook executables to validate behavior. It also addresses silent failures (e.g., detached spawn with stdio: 'ignore') by adding temporary logging and rebuilding TypeScript sources into dist bundles so changes take effect.

When to Use It

  • Hook isn't firing
  • Hook produces wrong output
  • SessionEnd not working
  • PostToolUse hook not triggering
  • Why didn't my hook run?

Quick Start

  1. Step 1: Observe outputs and verify registrations (check .claude/cache, settings.json, and grep for hooks).
  2. Step 2: Ensure hook files exist (shell wrappers and dist/*.mjs if using TS) and run a manual test pass.
  3. Step 3: If issues persist, enable logging, fix code as needed, and rebuild the TS sources into dist bundles.

Best Practices

  • Verify registration in both project and global settings.json to ensure hooks are bound to the correct events.
  • Observe outputs and inspect cache/logs before editing to avoid guesswork.
  • Confirm hook shell wrappers exist and compiled bundles (dist/*.mjs) are up to date.
  • Test hooks manually by echoing JSON payloads into the hook scripts to validate behavior.
  • If you see silent failures, enable temporary logging and rebuild TS sources into dist to surface errors.

Example Use Cases

  • Hook not firing: fix by ensuring 'SessionEnd' is registered in project settings and reloading configuration.
  • Hook output incorrect: verify cache outputs and correct the tool input or session ID used by the hook.
  • CI environment failure: identify missing dependencies or environment differences and install them.
  • PostToolUse not triggering: reproduce with a manual test and confirm the hook script path and permissions.
  • Detached spawn hides errors: add logging to capture stdout/stderr and rebuild after edits.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers