@seanmozeik/tripwire
v0.5.1
Published
Opinionated hooks dispatcher for AI coding agents with configurable safety rules
Readme
@seanmozeik/tripwire
Opinionated hooks dispatcher for AI coding agents (Claude Code, Codex, Devin, etc.) with configurable safety rules. Blocks or rewrites dangerous commands with actionable error messages.
Installation
bun install @seanmozeik/tripwireCLI
tripwire test '<command>' # Test a command
tripwire test --tool=Read --path=.env # Test Read tool
tripwire test --post --tool=Bash --stdout='ghp_TOKEN' # Test PostToolUse
tripwire install claude # Install hooks for Claude Code
tripwire install codex # Install hooks for Codex
tripwire install pi # Install hooks for pi-guardrails
tripwire install all # Install hooks for all agentsHook Configuration
Configure your AI agent to call tripwire-hook for hook events. You can do this manually, or use the tripwire install command to automatically configure hooks for supported agents:
Claude Code
~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "/path/to/tripwire-hook" }] }],
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "/path/to/tripwire-hook" }] }],
},
}Codex
Same as Claude Code — Codex uses the same hook format.
Devin
Configure in your Devin settings to call tripwire-hook for tool events.
Configuration
Create ~/.config/tripwire/config.json to customize behavior:
{
"rtk": { "enabled": true, "path": "/opt/homebrew/bin/rtk" },
"git": {
"protectedBranches": ["main", "master", "develop", "production", "release"],
"enforceConventionalCommits": true
},
"safePaths": {
"relative": ["dist", "build", ".next", "node_modules"],
"absolute": ["/tmp", "/var/tmp"]
},
"blockedCommands": [
{ "pattern": "dangerous-tool", "message": "Use safer-alternative instead", "action": "deny" }
],
"allowedCommands": [
{ "pattern": "my-custom-tool", "message": "Allowing my-custom-tool per your configuration" }
]
}Configuration Options
rtk
enabled(boolean, default:false) — Enable rtk token-saver integrationpath(string, optional) — Path to rtk binary. If not specified, searches common locations.
git
protectedBranches(string[], default:["main", "master", "develop", "production", "release"]) — Branches that require PR for pushenforceConventionalCommits(boolean, default:true) — Enforce Conventional Commits format for commit messages
safePaths
relative(string[], optional) — Additional relative paths considered safe for destructive operationsabsolute(string[], optional) — Additional absolute paths considered safe for destructive operations
Default safe paths include: dist, build, .next, node_modules, /tmp, /var/tmp, and other common build/cache directories.
blockedCommands
Array of custom command blocks:
pattern(string) — Command pattern to block (uses shell parsing for matching)message(string) — Error message shown when blockedaction("deny"|"ask", default:"deny") — Whether to deny or ask for confirmationrequiresFlags(string[], optional) — Match only when every listed flag is present, including--flag=valueformforbidsFlagValues(array, optional) — Match only when each listed flag is present with one of the listed values
allowedCommands
Array of custom command allows (overrides blocks):
pattern(string) — Command pattern to allowmessage(string) — Message shown when allowedrequiresFlags(string[], optional) — Same matching condition asblockedCommandsforbidsFlagValues(array, optional) — Same matching condition asblockedCommands
Shell-Based Command Matching
Command patterns in blockedCommands and allowedCommands use the same shell parsing as the rest of tripwire. This means:
rmmatches anyrmcommandgit pushmatchesgit pushwith any argumentsgog calendar creatematches that head + subcommand path, not everygogcommandrequiresFlags: ["--attendees"]matches--attendees Xand--attendees=XforbidsFlagValues: [{ "flag": "--send-updates", "values": ["all"] }]matches--send-updates alland--send-updates=all- Patterns are parsed using shell-quote for accurate matching
- More sophisticated than simple regex
Example:
{
"blockedCommands": [
{
"pattern": "brew install",
"message": "Use brew install with explicit version pinning",
"action": "ask"
},
{
"pattern": "gog calendar create",
"requiresFlags": ["--attendees"],
"message": "Calendar invite sends email; draft it in chat first.",
"action": "deny"
},
{
"pattern": "gog calendar delete",
"forbidsFlagValues": [{ "flag": "--send-updates", "values": ["all", "externalOnly"] }],
"message": "Cancellation sends email; use --send-updates none or ask first."
}
]
}Default Behavior
Tripwire comes with opinionated but reasonable defaults:
Bash Safety
- Blocks catastrophic commands:
rm -rf /, fork bombs,ddto disks - Blocks macOS system mutations:
defaults write,launchctl,diskutil erase - Blocks cloud destructive operations:
gh repo delete,flyctl destroy - Scopes
rmandfind -deleteto safe paths (build outputs, cache directories) - Blocks network install scripts:
curl | bash,wget | sh - Enforces package manager policy: Bun-only, no npm/pnpm/yarn/pip
Git Policy
- Read-only operations allowed:
status,log,diff,fetch, etc. - Blocks working-tree destruction:
reset --hard,clean -fd,checkout . - Blocks history rewriting:
rebase -i,filter-branch,commit --amend - Blocks force push and protected branch pushes
- Enforces Conventional Commits format (configurable)
- Requires
-m "message"for commits (no editor mode) - Asks for confirmation on merge/rebase/cherry-pick
File Protection
- Blocks reads/writes to
.env,.ssh/,*.pem,id_rsa*, etc. - Warns on TODO/FIXME/placeholder in code (configurable)
- Scrubs secrets from tool output
Bypass
Add # tripwire-allow: <reason> to bypass any rule:
rm -rf /tmp/test # tripwire-allow: cleaning test directory
git reset --hard HEAD~1 # tripwire-allow: undoing mistaken commitLibrary Usage
import { allow, deny, ask, warn } from '@seanmozeik/tripwire';
import type { Decision, Config } from '@seanmozeik/tripwire';Development
bun install
bun run build # Build dist/tripwire.js and dist/tripwire-cli.js
bun run check # Format + lint + typecheck
bun test # Run testsLicense
MIT
