ClaudeSuperPower
P

PreToolUse (Bash)

Hook

Fail-closed bash safety guard: blocks prod-data-loss, credential-leak, and catastrophic rm before any Bash command runs. Non-bash tools are untouched.

Fires on

PreToolUsematchingBash

Immediately before a tool runs — this is where an action can be denied.

Where this sits in a session

  1. Session start
  2. Prompt submitted
  3. Prompt expansion
  4. Before tool use
  5. After tool use
  6. Notification
  7. Before compaction
  8. Subagent finished
  9. Turn finished
  10. Session end

Can blockThis hook is able to deny the action or send Claude back to work.

What it runs

Executed automatically when the event fires — no prompt, no confirmation.

command· timeout 15s
node --no-warnings --experimental-strip-types "${CLAUDE_PLUGIN_ROOT}/hooks/guard-hook.ts"

Install it yourself

Paste into .claude/settings.json to run this hook without installing the whole plugin. Adjust the paths to point at your own copy of the scripts.

settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node --no-warnings --experimental-strip-types \"${CLAUDE_PLUGIN_ROOT}/hooks/guard-hook.ts\"",
            "timeout": 15
          }
        ],
        "matcher": "Bash"
      }
    ]
  }
}

Source

Read this before installing — it runs on your machine with your permissions.

#!/usr/bin/env node
/**
 * PreToolUse guard hook for Claude Code (bash-safety-guard plugin).
 *
 * Wired to the `Bash` tool via hooks/hooks.json. Reuses the same
 * `classifyCommand` classifier as the pixtension pi orchestrator (vendored in
 * ./lib/guards.ts) so both enforce identical rules. PreToolUse hooks run
 * regardless of permission mode (including `--dangerously-skip-permissions`),
 * so the gate holds even in autonomous sessions.
 *
 * Contract: exit 0 = allow; exit 2 = block (stderr is fed back to the model).
 * We FAIL CLOSED (exit 2) on any prod-data-loss / credential-leak /
 * catastrophic-rm verdict AND on any parse/classifier error. Non-Bash tools are
 * auto-allowed (this hook is only matched to Bash, but we double-check).
 *
 * Requires Node >= 22 (uses --experimental-strip-types to run TS directly).
 */
import { classifyCommand } from "../lib/guards.ts";

function block(reason: string): never {
	process.stderr.write(`BLOCKED by bash-safety-guard (fail-closed): ${reason}\n`);
	process.exit(2);
}

let raw = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
	raw += chunk;
});
process.stdin.on("end", () => {
	let payload: {
		tool_name?: string;
		toolName?: string;
		tool_input?: { command?: string };
		toolInput?: { command?: string };
	};
	try {
		payload = JSON.parse(raw || "{}");
	} catch {
		block("could not parse PreToolUse payload");
	}

	const tool = payload.tool_name ?? payload.toolName ?? "";
	if (tool !== "Bash") process.exit(0);

	const command = payload.tool_input?.command ?? payload.toolInput?.command ?? "";
	let verdict: ReturnType<typeof classifyCommand>;
	try {
		verdict = classifyCommand(String(command));
	} catch (err) {
		block(`classifier error: ${(err as Error).message}`);
	}

	if (verdict.action === "allow") process.exit(0);
	block(`${verdict.category}: ${verdict.reason}\n\nCommand:\n${command}`);
});

Shipped by 1 plugin

Installing any of these installs this hook.

Reviews

Log in to leave a review.

No reviews yet — be the first.

Explore related

Other things in this space — across every part of the ecosystem, not just hooks.