Back to list
oakoss

warn-console-log

by oakoss

Open-source SaaS starter kit with React, TanStack, and Better Auth

0🍴 0📅 Jan 26, 2026

SKILL.md


name: meta:hook-creator description: Create event hooks for Claude Code that trigger on specific events. Generate hooks with proper JSON configuration for automating workflows. Use when creating hooks, setting up event triggers, automating on file saves or tool calls.

Hook Creator

Quick Start

Add a hook to .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'File written!'"
          }
        ]
      }
    ]
  }
}

Use /hooks command to manage hooks interactively.

Choosing an Approach

ApproachBest ForSetup
Hookify (/hookify)Pattern-based warn/blockMarkdown files, no code
Python hooksComplex logic, external toolsPython scripts + settings.json
Inline bashSimple one-linerssettings.json only

Decision Tree

Need to detect a pattern and warn/block?
  └─ Yes → Use hookify (/hookify "Don't use console.log")
  └─ No, need complex logic?
       └─ Yes → Use Python hook script
       └─ No, just a simple command?
            └─ Yes → Inline in settings.json

When to Use Hookify

  • Block/warn based on regex pattern matching
  • Quick setup without writing code
  • Personal rules (.local.md files aren't committed)
# .claude/hookify.warn-console-log.local.md

---

name: warn-console-log
enabled: true
event: file
pattern: console\.log\(
action: warn

---

Remove console.log before committing.

When to Use Python Hooks

  • Check file existence or conditions
  • Run external validators
  • Parse and analyze content
  • Call APIs or external tools
#!/usr/bin/env -S uv run --quiet --script
# .claude/hooks/schema-change.py
import json, sys

input_data = json.loads(sys.stdin.read())
file_path = input_data.get("tool_input", {}).get("file_path", "")

if "src/modules/db/schema" in file_path:
    print("📦 Schema modified. Run: pnpm db:generate")

Hook Locations

LocationScopeCommitted
.claude/settings.jsonProjectYes
.claude/settings.local.jsonProject (personal)No
~/.claude/settings.jsonUser (all projects)N/A
Managed policyEnterpriseN/A

Event Types

EventTriggerMatcherUse Case
PreToolUseBefore tool executesTool nameBlock/validate
PostToolUseAfter tool completesTool nameFormat/cleanup
PermissionRequestPermission dialog shownTool nameAuto-approve/deny
UserPromptSubmitUser sends messageN/ATransform input
NotificationClaude sends notificationTypeCustom alerts
StopMain agent finishesN/AContinue/cleanup
SubagentStopSubagent completesN/AProcess results
SessionStartSession beginsSourceInitialization
SessionEndSession endsN/AFinal cleanup
PreCompactBefore compactionTriggerPre-compact logic

Notification Matchers

MatcherTrigger
permission_promptPermission request
idle_promptWaiting for input (60s+)
auth_successAuthentication success
elicitation_dialogMCP tool elicitation

SessionStart Matchers

MatcherTrigger
startupNew session
resume--resume, --continue, /resume
clear/clear command
compactAuto or manual compact

Exit Codes

CodeMeaningEffect
0SuccessContinue normally
1ErrorShow error to user
2BlockBlock action (PreToolUse, PermissionRequest only)

Hook Types

Command Hook

Executes a shell command:

{
  "type": "command",
  "command": "your-shell-command",
  "timeout": 30
}

Prompt Hook (LLM-based)

Uses an LLM to evaluate (Stop/SubagentStop only):

{
  "type": "prompt",
  "prompt": "Evaluate if Claude should stop: $ARGUMENTS",
  "timeout": 30
}

Environment Variables

VariableAvailable InPurpose
CLAUDE_PROJECT_DIRAll hooksProject root path
CLAUDE_ENV_FILESessionStart onlyPersist env variables
CLAUDE_PLUGIN_ROOTPlugin hooksPlugin directory
CLAUDE_CODE_REMOTEAll hooks"true" if remote session

Persist Environment (SessionStart)

#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
fi

Matcher Patterns

PatternMatches
"Write"Specific tool
"Edit|Write"Multiple tools (OR)
"Bash.*"Regex pattern
"*"All tools
""Events without tools
"mcp__github__.*"MCP server tools

Hook Configuration

{
  "hooks": {
    "<EventType>": [
      {
        "matcher": "<pattern>",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/script.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Hooks in Components

Skills, agents, and commands can define hooks in frontmatter:

---
name: secure-operations
hooks:
  PreToolUse:
    - matcher: 'Bash'
      hooks:
        - type: command
          command: './scripts/security-check.sh'
          once: true
---

Supported events: PreToolUse, PostToolUse, Stop

The once: true option runs the hook only once per session (skills/commands only).

Common Templates

Block Dangerous Commands

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'input=$(cat); if echo \"$input\" | jq -e \".tool_input.command | test(\\\"rm -rf|--force\\\"; \\\"i\\\")\" >/dev/null 2>&1; then echo \"Blocked: Dangerous command\" >&2; exit 2; fi'"
          }
        ]
      }
    ]
  }
}

Protect Files

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'input=$(cat); path=$(echo \"$input\" | jq -r \".tool_input.file_path // empty\"); if [[ \"$path\" == *.env* ]]; then echo \"Blocked: Protected file\" >&2; exit 2; fi'"
          }
        ]
      }
    ]
  }
}

Auto-Format TypeScript

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'input=$(cat); file=$(echo \"$input\" | jq -r \".tool_input.file_path // empty\"); if [[ \"$file\" == *.ts ]]; then npx prettier --write \"$file\" 2>/dev/null; fi'",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

Desktop Notification

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude needs permission\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Script-Based Hooks

For complex logic, use Python scripts with uv instead of inline bash. See reference.md for templates and examples.

Common Mistakes

MistakeImpactCorrect Pattern
Using settings.json for patternsOverly complexUse hookify for pattern matching
Exit 1 in PreToolUseShows error, doesn't blockUse exit 2 to block
Complex inline bashHard to maintainUse Python script with uv
No timeoutHangs on slow commandsSet reasonable timeout
Missing $CLAUDE_PROJECT_DIRPath errorsQuote: "$CLAUDE_PROJECT_DIR"/...
Not testing stdin parsingRuntime failuresTest: echo '{}' | script.py

Validation

Run validation after every hook change:

uv run .claude/skills/meta-hook-creator/scripts/validate-hook.py .claude/settings.json

Checklist

  • Hook defined in settings.json
  • Event type is valid
  • Matcher pattern correct for event
  • Command handles stdin JSON properly
  • Exit codes match intended behavior
  • Timeout set appropriately
  • External scripts are executable

Delegation

  • After creating/modifying hooks: Run uv run .claude/skills/meta-hook-creator/scripts/validate-hook.py .claude/settings.json
  • Pattern discovery: For existing hook patterns, use Explore agent

Additional Resources

References

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon