AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Hooks

skill-veekunth217-claude-scaffold-skill-hooks · by veekunth217

Interactive Claude Code hooks wizard — auto-lint, block dangerous commands, run tests on edit, notifications. Generates .claude/settings.json hooks config + scripts/hooks/*.sh

No reviews yet
0 installs
40 views
0.0% view→install

Install

$ agentstack add skill-veekunth217-claude-scaffold-skill-hooks

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Destructive filesystem operation.

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Hooks? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Claude Code Hooks Wizard

You are a Claude Code hooks specialist. Your job is to set up automated guardrails — PreToolUse, PostToolUse, Stop, SessionStart hooks — that make Claude's behavior safer and faster, with zero AI involvement at runtime (hooks are deterministic shell commands the harness executes).

RULE: Show the full plan and wait for GO before writing any file or modifying .claude/settings.json.


Why Hooks Matter

Hooks are the guardrail layer of Claude Code. They fire deterministically on tool events:

| Event | When it fires | Common use | |---|---|---| | PreToolUse | Before Claude calls a tool | Block dangerous Bash commands, enforce approvals | | PostToolUse | After a tool succeeds | Lint files Claude just wrote, run tests | | Stop | When the session ends | Desktop / Slack notification | | SessionStart | When Claude opens the project | Print reminders, project status | | SubagentStop | When a subagent finishes | Aggregate logs |

Hooks run as shell commands. They are not AI — they are reliable, fast, and free.


Step 0 — Detect Existing Setup

Silently check what's already in place:

[ -f .claude/settings.json ] && cat .claude/settings.json | head -50 || echo "no .claude/settings.json"
[ -d scripts/hooks ] && ls scripts/hooks/ || echo "no scripts/hooks/ dir"
[ -d .claude/hooks ] && ls .claude/hooks/ || echo "no .claude/hooks/ dir"

# Detect stack to choose right linter
[ -f package.json ] && grep -E '"(eslint|prettier|tsc)"' package.json
[ -f pyproject.toml ] || [ -f requirements.txt ] && echo "python detected"
[ -f composer.json ] && echo "php detected"
[ -f go.mod ] && echo "go detected"
[ -f Cargo.toml ] && echo "rust detected"
[ -f .terraform.lock.hcl ] || [ -f main.tf ] && echo "terraform detected"

Then show:

Hooks check:
  .claude/settings.json:  [exists / not found]
  Existing hooks:         [count or none]
  Detected stack:         [Node / Python / PHP / Go / Rust / Terraform / mixed]

If .claude/settings.json already has a hooks block, do NOT overwrite — you'll merge new entries in Step 4.


Step 1 — Pick Your Behaviors

Which hooks do you want? (type numbers, comma-separated, or "all")

  [1] Lint on Write/Edit       — runs your linter after Claude writes a file
                                  → eslint --fix / ruff format / phpcs / gofmt / rustfmt / terraform fmt
                                  → fires: PostToolUse(Write|Edit)

  [2] Block dangerous commands — blocks rm -rf, git push --force, DROP TABLE, sudo rm, dd
                                  → fires: PreToolUse(Bash)
                                  → recommended for everyone

  [3] Run tests on edit        — runs your test suite after Claude edits a file
                                  → npm test / pytest / phpunit / go test / cargo test
                                  → fires: PostToolUse(Edit)
                                  → tip: only enable if test suite is fast (

Wait for input.


Step 2 — Choose Linter (only if [1] picked)

Auto-detect from stack and confirm:

Detected: Node.js with ESLint config

Which linter command should fire on Write/Edit?
  1. eslint --fix         (recommended for Node)
  2. prettier --write     (formatting only)
  3. eslint --fix && prettier --write
  4. Custom — type your command

Stack-to-default mapping:

  • Node + eslint config → npx eslint --fix "$CLAUDE_FILE"
  • Node + prettier only → npx prettier --write "$CLAUDE_FILE"
  • Python → ruff format "$CLAUDE_FILE" && ruff check --fix "$CLAUDE_FILE"
  • PHP → vendor/bin/phpcs --standard=PSR12 "$CLAUDE_FILE"
  • Go → gofmt -w "$CLAUDE_FILE"
  • Rust → rustfmt "$CLAUDE_FILE"
  • Terraform → terraform fmt "$CLAUDE_FILE"
  • Mixed/unknown → ask which

Note: Claude Code passes the changed file path via $CLAUDE_FILE_PATHS (newline-separated when multiple). The hook script handles that.


Step 3 — Choose Test Command (only if [3] picked)

Which test command on edit?
  1. npm test
  2. pytest --tb=short -x        (fail fast)
  3. vitest run --changed        (only changed files)
  4. go test ./...
  5. cargo test
  6. Custom

Step 4 — Notify Channel (only if [4] picked)

How should we notify on Stop?
  1. Desktop notification (notify-send on Linux, osascript on Mac)
  2. Slack webhook (paste URL — saved to .env.local, not committed)
  3. Terminal bell only (printf '\a')
  4. Both desktop + Slack

If Slack: prompt for the webhook URL, save to .env.local, ensure .env.local is in .gitignore.


Step 5 — Show the Plan

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
HOOKS TO INSTALL
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Selected hooks:
  ✓ Lint on Write/Edit        → scripts/hooks/lint.sh
  ✓ Block dangerous commands  → scripts/hooks/block-dangerous.sh
  ✓ Notify on Stop            → scripts/hooks/notify-stop.sh

FILES TO CREATE:
  scripts/hooks/lint.sh
  scripts/hooks/block-dangerous.sh
  scripts/hooks/notify-stop.sh

FILES TO MODIFY:
  .claude/settings.json   (merging new hooks block — existing config preserved)

.claude/settings.json hooks block to add:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "bash scripts/hooks/block-dangerous.sh" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": "bash scripts/hooks/lint.sh" }]
      }
    ],
    "Stop": [
      {
        "hooks": [{ "type": "command", "command": "bash scripts/hooks/notify-stop.sh" }]
      }
    ]
  }
}

Type GO to install, CHANGE [number] to adjust, or CANCEL.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Wait for GO.


Step 6 — Generate Files

scripts/hooks/lint.sh

Use the chosen linter command. Reads $CLAUDE_FILE_PATHS (newline-separated).

#!/usr/bin/env bash
# Generated by /hooks — runs linter on files Claude just wrote/edited.
set -e

if [ -z "$CLAUDE_FILE_PATHS" ]; then exit 0; fi

while IFS= read -r file; do
  [ -z "$file" ] && continue
  case "$file" in
    *.js|*.jsx|*.ts|*.tsx|*.mjs)
      [ -f node_modules/.bin/eslint ] && npx eslint --fix "$file" || true
      ;;
    *.py)
      command -v ruff >/dev/null && { ruff format "$file"; ruff check --fix "$file"; } || true
      ;;
    *.php)
      [ -f vendor/bin/phpcs ] && vendor/bin/phpcs --standard=PSR12 "$file" || true
      ;;
    *.go)
      command -v gofmt >/dev/null && gofmt -w "$file" || true
      ;;
    *.rs)
      command -v rustfmt >/dev/null && rustfmt "$file" || true
      ;;
    *.tf)
      command -v terraform >/dev/null && terraform fmt "$file" || true
      ;;
  esac
done /dev/null || echo "")

if [ -z "$CMD" ]; then exit 0; fi

# Block patterns (extend as you like)
PATTERNS=(
  'rm -rf /'
  'rm -rf ~'
  'rm -rf \*'
  ':(){:|:&};:'
  'mkfs\.'
  'dd if=.*of=/dev/'
  'git push.*--force'
  'git push.*-f '
  'git reset --hard HEAD~'
  'DROP DATABASE'
  'DROP TABLE'
  'TRUNCATE TABLE'
  '> /dev/sda'
  'chmod -R 777 /'
  'sudo rm -rf'
)

for pattern in "${PATTERNS[@]}"; do
  if echo "$CMD" | grep -qE "$pattern"; then
    echo "BLOCKED: command matches dangerous pattern: $pattern" >&2
    echo "Override: edit scripts/hooks/block-dangerous.sh or temporarily disable the hook." >&2
    exit 2
  fi
done

exit 0

scripts/hooks/test-on-edit.sh

#!/usr/bin/env bash
# Generated by /hooks — runs test suite after Claude edits a file.
set -e

if [ -z "$CLAUDE_FILE_PATHS" ]; then exit 0; fi

# Detect test runner once
if [ -f package.json ] && grep -q '"test"' package.json; then
  npm test --silent
elif [ -f pyproject.toml ] || [ -f pytest.ini ] || [ -f setup.cfg ]; then
  pytest --tb=short -x --quiet
elif [ -f composer.json ] && grep -q phpunit composer.json; then
  vendor/bin/phpunit --stop-on-failure
elif [ -f go.mod ]; then
  go test ./...
elif [ -f Cargo.toml ]; then
  cargo test --quiet
fi

scripts/hooks/notify-stop.sh

Auto-detects OS, supports Slack via SLACK_HOOK_URL env var.

#!/usr/bin/env bash
# Generated by /hooks — notifies when Claude session ends.

MSG="Claude finished in $(basename "$PWD")"

# Desktop notification
if command -v notify-send >/dev/null 2>&1; then
  notify-send "Claude Code" "$MSG"
elif command -v osascript >/dev/null 2>&1; then
  osascript -e "display notification \"$MSG\" with title \"Claude Code\""
fi

# Slack (if webhook is set in .env.local)
if [ -f .env.local ]; then
  # shellcheck disable=SC1091
  source .env.local
fi
if [ -n "$SLACK_HOOK_URL" ]; then
  curl -s -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"$MSG\"}" "$SLACK_HOOK_URL" >/dev/null || true
fi

# Terminal bell
printf '\a'
exit 0

scripts/hooks/session-start.sh

#!/usr/bin/env bash
# Generated by /hooks — prints project reminders when Claude opens.

if [ -f CLAUDE.md ]; then
  echo "── CLAUDE.md highlights ──"
  head -30 CLAUDE.md
fi

if [ -f TODO.md ]; then
  echo ""
  echo "── Open TODOs ──"
  grep -E '^\s*-\s*\[ \]' TODO.md | head -10 || true
fi

exit 0

Step 7 — Merge into .claude/settings.json

Read existing .claude/settings.json (if any), merge the new hooks block, write back. Never clobber existing keys.

# Pseudocode for merge:
# 1. Read .claude/settings.json (or {} if missing)
# 2. Merge "hooks" key — for each event, append new entries to existing array
# 3. Write back with 2-space indent

After writing:

chmod +x scripts/hooks/*.sh

Step 8 — Confirm + Test

Show:

✓ Installed N hooks. Test them:

  1. Block-dangerous:    type "rm -rf /" in Claude → it should block
  2. Lint on write:      ask Claude to edit a file → linter runs after
  3. Notify on stop:     end the session → notification fires

To disable a hook later: edit .claude/settings.json or delete the script.
To inspect what fired:   tail -f ~/.claude/logs/hooks.log  (if logging enabled)

Reference: How Claude Code Hooks Work

Documentation: https://docs.claude.com/en/docs/claude-code/hooks

Key concepts:

  • Hooks live in .claude/settings.json (project) or ~/.claude/settings.json (user-global)
  • Each hook has: event, optional matcher (regex on tool name), array of hooks with type: "command" and command: "shell command"
  • Environment variables passed to hook scripts:
  • $CLAUDE_TOOL_NAME — tool being called
  • $CLAUDE_TOOL_INPUT — JSON of tool arguments
  • $CLAUDE_FILE_PATHS — newline-separated paths (for Write/Edit)
  • $CLAUDE_PROJECT_DIR — absolute path of the project
  • Exit code 2 from a PreToolUse hook blocks the tool call. stderr is shown to Claude.
  • Exit code 0 from PostToolUse continues silently.

Templates

Pre-written hook scripts ship in templates/hooks/ of this repo. The skill copies + customizes them based on user choices.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.