How to Implement a `console.log` Detection Hook in Everything-Claude-Code
Add a PostToolUse hook in hooks/hooks.json that matches Edit calls on JS/TS files and runs a Node script to scan for console.log statements.
The Everything-Claude-Code repository provides a powerful hook system that runs custom commands automatically after Claude Code tools finish executing. Implementing a console.log detection hook helps catch stray debug statements before they reach production, enforcing clean JavaScript and TypeScript codebases without interrupting your development flow.
Understanding the Hook Architecture
Claude Code hooks are defined in hooks/hooks.json and triggered by lifecycle events. The PostToolUse event fires after any tool completes, making it ideal for lint-style checks on file modifications.
Each hook entry contains three components:
- Matcher – a boolean expression determining when the hook fires
- Command – the executable to run (shell command or inline script)
- Description – human-readable explanation of the hook's purpose
The hook receives tool execution data via stdin as a JSON payload, allowing inspection of which file was edited and what operation occurred.
Step-by-Step Implementation
Step 1: Define the Matcher Expression
The matcher restricts execution to Edit operations on web-convention files:
"matcher": "tool == \"Edit\" && tool_input.file_path matches \"\\.(ts|tsx|js|jsx)$\""
This pattern ensures the hook only processes relevant file types, avoiding unnecessary computation on non-JavaScript assets.
Step 2: Create the Detection Command
The command reads the edited file from disk, scans line-by-line for the /console\.log/ regex, and reports matches to stderr:
// hooks/hooks.json – complete PostToolUse entry
{
"matcher": "tool == \"Edit\" && tool_input.file_path matches \"\\.(ts|tsx|js|jsx)$\"",
"hooks": [
{
"type": "command",
"command": "node -e \"const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){const c=fs.readFileSync(p,'utf8');const lines=c.split('\\n');const matches=[];lines.forEach((l,idx)=>{if(/console\\.log/.test(l))matches.push((idx+1)+': '+l.trim())});if(matches.length){console.error('[Hook] WARNING: console.log found in '+p);matches.slice(0,5).forEach(m=>console.error(m));console.error('[Hook] Remove console.log before committing')}}console.log(d)})\""
}
],
"description": "Warn about console.log statements after edits"
}
The Node script performs four operations:
- Buffer stdin – accumulates the JSON payload from Claude Code
- Extract file path – parses
tool_input.file_pathfrom the payload - Scan for matches – tests each line against
/console\.log/ - Emit warnings – prints line numbers and snippets (limited to first 5 matches)
- Passthrough – echoes original payload to
stdoutfor downstream processing
Step 3: Test the Hook Manually
Before relying on automatic execution, simulate the Claude Code payload:
# Simulate a Claude-code Edit tool payload
echo '{"tool":"Edit","tool_input":{"file_path":"src/example.js"}}' \
| node -e "const fs=require('fs');let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path;if(p&&fs.existsSync(p)){const c=fs.readFileSync(p,'utf8');const lines=c.split('\\n');const matches=[];lines.forEach((l,idx)=>{if(/console\\.log/.test(l))matches.push((idx+1)+': '+l.trim())});if(matches.length){console.error('[Hook] WARNING: console.log found in '+p);matches.slice(0,5).forEach(m=>console.error(m));console.error('[Hook] Remove console.log before committing')}}console.log(d)})"
Given a file src/example.js containing:
function processData(data) {
console.log('debug start');
const result = transform(data);
console.log(result);
return result;
}
The hook outputs:
[Hook] WARNING: console.log found in src/example.js
2: console.log('debug start');
4: console.log(result);
[Hook] Remove console.log before committing
Extending the Detection Pattern
The same architecture supports additional lint-style checks by modifying the regex or adding parallel hook entries:
| Pattern | Regex Modification | Use Case |
|---|---|---|
debugger statements |
/\bdebugger\b/ |
Prevent accidental breakpoints in production |
alert() calls |
/\balert\(/ |
Block debugging dialogs |
| Hardcoded secrets | `/password | secret |
| TODO/FIXME comments | `/TODO | FIXME/` |
Each extension follows the identical three-step pattern: update the matcher if needed, modify the detection regex in the command, and adjust the description accordingly.
Key Files Reference
| File | Purpose |
|---|---|
hooks/hooks.json |
Central configuration for all Claude Code hooks; the PostToolUse array holds detection logic |
scripts/hooks/pre-compact.js |
Reference implementation showing Node-based hook scripts in action |
tests/hooks/hooks.test.js |
Test suite for hook behavior—extend here to add detection coverage |
README.md |
Architecture documentation and hook lifecycle details |
The hook system in WorldFlowAI/everything-claude-code operates entirely through configuration, requiring no modifications to Claude Code's core—making it safe to upgrade without losing custom checks.
Summary
- Hooks live in
hooks/hooks.jsonunder thePostToolUsesection - Matchers filter by tool type and file extension using boolean expressions
- Commands receive JSON via stdin and must passthrough data to
stdout console.logdetection uses/console\.log/regex with line-by-line scanning- Warnings go to
stderrto surface issues without breaking the tool chain
Frequently Asked Questions
Does the console.log detection hook block file edits or commits?
No. The hook runs after the Edit tool completes and only writes to stderr. It surfaces warnings without modifying the exit code or preventing the operation from succeeding. This design keeps development velocity high while maintaining visibility into code quality issues.
Can I detect other console methods like console.warn or console.error?
Yes. Modify the regex in the command from /console\.log/ to /console\.(log|warn|error|info|debug)/ to catch all console method calls. You can also create separate hooks with distinct descriptions if you want differentiated handling for production-appropriate methods versus debug methods.
How do I test hooks without triggering actual Claude Code edits?
Use the manual testing approach shown above: construct a JSON payload matching Claude Code's PostToolUse format and pipe it through the Node command. The tests/hooks/hooks.test.js file contains additional patterns for automated testing that you can adapt for your detection logic.
What happens if the hook script throws an error?
Claude Code's hook system generally logs hook failures but proceeds with the operation. However, always ensure your command ends with console.log(d) to passthrough the original payload—failure to do so may break downstream processing. The inline Node script includes error-adjacent checks like fs.existsSync(p) to avoid crashes on missing files.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →