Block Dangerous Commands
Reject rm -rf, curl | sh, writes to .env, and similar at the PreToolUse step.
ts
#!/usr/bin/env bun
// .hooks/guard.ts
import { defineHook, run } from "@pivanov/agent-hooks-bridge";
const DANGEROUS_BASH = [
/\brm\s+(-[a-zA-Z]*r|--recursive)/, // rm -rf, rm -Rfv, rm --recursive
/curl[^|]*\|\s*(sh|bash|zsh)/, // curl ... | sh
/\bsudo\b/, // anything sudo
/\bDROP\s+(TABLE|DATABASE)/i, // SQL DROP
];
const PROTECTED_PATHS = [
/^\.env(\.|$)/,
/^secrets?\//,
/\.pem$/,
/\.key$/,
];
const hooks = defineHook({
PreToolUse: (event) => {
if (event.tool === "Bash") {
const command = String(event.tool_input.command ?? "");
for (const pattern of DANGEROUS_BASH) {
if (pattern.test(command)) {
return {
decision: "deny",
reason: `command matches policy block: /${pattern.source}/`,
user_message: `Blocked: dangerous bash command (${pattern.source})`,
};
}
}
}
if (event.tool === "Write" || event.tool === "Edit") {
const file = event.tool_input.file_path;
if (typeof file === "string") {
for (const pattern of PROTECTED_PATHS) {
if (pattern.test(file)) {
return {
decision: "deny",
reason: `writes to ${file} are policy-blocked`,
user_message: `Blocked: cannot write to ${file}`,
};
}
}
}
}
return { decision: "allow" };
},
});
await run(hooks);Install:
bash
chmod +x .hooks/guard.ts
bunx @pivanov/agent-hooks-bridge install ./.hooks/guard.ts --events PreToolUsePer-host behavior
| Host | decision: "deny" surface |
|---|---|
| Claude | hookSpecificOutput.permissionDecision = "deny", exit 2. reason shown to model. |
| Cursor | permission: "deny", exit 2. reason → agent_message (model). user_message → human UI. |
| Codex | hookSpecificOutput.permissionDecision = "deny", exit 2. reason shown to model. user_message dropped + warn. |
The user_message field is honored only on Cursor's permission events. Claude and Codex have no human-facing channel. If you set both reason and user_message, set them to similar content; the bridge drops user_message on the hosts that can't show it.
Pairing with format-on-edit
You can run both hooks in one script. Either:
- Single script, multiple events: one
defineHookmap handlingPreToolUse(guard) andPostToolUse(format). - Two scripts: wire each separately:
bash
bunx @pivanov/agent-hooks-bridge install ./.hooks/guard.ts --events PreToolUse
bunx @pivanov/agent-hooks-bridge install ./.hooks/format.ts --events PostToolUseBoth work. The single-script form is simpler; the two-script form lets you toggle policies independently.