debug-hooks — Claude Code skill: what it does, how to install
Systematic debugging guide for Claude Code hooks when events fail to fire, run twice, or swallow runtime errors.
npx skills add parcadei/Continuous-Claude-v3 --skill debug-hooks -a claude-codeWhat debug-hooks does
The skill provides an inspection sequence for SessionEnd and PostToolUse hooks. It directs the agent to check outputs before modifying any code. Claude Code inspects the .claude/cache/ directory, checks debug logs, and inspects settings.json to find missing registrations or duplicate hooks.
To pinpoint failure points, the workflow pipes mock JSON payloads into shell wrappers. Silent failures often occur in detached spawns configured with stdio: 'ignore'. When that happens, the skill routes stdout and stderr into a temporary log file.
TypeScript source edits will not alter behavior immediately. The shell wrapper executes the bundled .mjs file in dist/. You must run an esbuild command after code modifications. The skill requires Bash, Read, and Grep tools.
What it helps with
- identify why SessionEnd or PostToolUse hooks fail to trigger
- test hook scripts manually with mock JSON payloads
- capture silent failures hidden by detached spawn calls
- fix duplicate hook runs caused by conflicting settings
Example prompts for the agent
- My PostToolUse hook isn't firing, help me debug it
- Check why the SessionEnd cleanup script produces no logs
- Verify my hook registration in .claude/settings.json
How to install debug-hooks
1Skills CLI (Vercel)
npx skills add parcadei/Continuous-Claude-v3 --skill debug-hooks -a claude-code2Manually: put the files in place
~/.claude/skills/debug-hooks/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/debug-hooks/
1Skills CLI (Vercel)
npx skills add parcadei/Continuous-Claude-v3 --skill debug-hooks -a codex2Manually: put the files in place
.agents/skills/debug-hooks/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add parcadei/Continuous-Claude-v3 --skill debug-hooks -a cursor2Manually: put the files in place
.cursor/skills/debug-hooks/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install parcadei/Continuous-Claude-v3 debug-hooks2Manually: put the files in place
.github/skills/debug-hooks/SKILL.md1Skills CLI (Vercel)
npx skills add parcadei/Continuous-Claude-v3 --skill debug-hooks -a gemini-cli2Platform CLI
gemini skills install https://github.com/parcadei/Continuous-Claude-v3 --path .claude/skills/debug-hooksManually: put the files in place
.devin/skills/debug-hooks/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add parcadei/Continuous-Claude-v3 --skill debug-hooks -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about debug-hooks
How to install debug-hooks in Claude Code?
Run npx skills add parcadei/Continuous-Claude-v3 --skill debug-hooks -a claude-code. You can also place the skill file directly at ~/.claude/skills/debug-hooks/SKILL.md.
What does debug-hooks do?
It runs a six-step diagnostic sequence for hook scripts. It verifies registration in settings.json, tests shell execution with mock JSON, and checks build outputs.
Why do TypeScript hook edits fail to take effect?
The hook executes a compiled bundle from .claude/hooks/dist/*.mjs. You must rebuild the source with esbuild before changes become active.
Source text
SKILL.md · MIT
---
name: debug-hooks
description: Systematic hook debugging workflow. Use when hooks aren't firing, producing wrong output, or behaving unexpectedly.
allowed-tools: [Bash, Read, Grep]
---
# 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)
```bash
# 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
```bash
# 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
```bash
# 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
```bash
# 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'`:
```typescript
// This pattern hides errors!
spawn(cmd, args, { detached: true, stdio: 'ignore' })
```
**Fix:** Add temporary logging:
```typescript
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:
```bash
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
| Symptom | Likely Cause | Fix |
|---------|--------------|-----|
| Hook never runs | Not registered in settings.json | Add to correct event in settings |
| Hook runs but no output | Detached spawn hiding errors | Add logging, check manually |
| Wrong session ID | Using "most recent" query | Pass ID explicitly |
| Works locally, not in CI | Missing dependencies | Check npx/node availability |
| Runs twice | Registered in both global + project | Remove 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
© parcadei · MIT · parcadei/Continuous-Claude-v3