Architecture¶
Pipeline¶
stdin (JSON) → index.ts → parser.ts → evaluator.ts → stdout (JSON) / exit code 2
↑ ↑
unbash rules.ts + defaults.ts + targets.ts
Modules¶
index.ts - Entry point¶
Reads hook JSON from stdin, runs parse→evaluate pipeline, outputs decision. Handles YOLO mode activation/deactivation, stdin size limits (1MB), and --dangerously-skip-permissions detection.
parser.ts - Command parser¶
AST-based shell command parser using unbash. Walks the AST to:
- Extract commands from pipes, chains, control flow (while, if, for, case, functions)
- Extract env prefixes (
VAR=value) - Normalize command paths to basename
- Recursively parse
sh -c/bash -carguments - Extract script paths from
bash/sh/zsh script.shinvocations - Detect subshells (
$(), backticks), process substitutions, and heredocs - Track chain-scoped variable assignments (
VAR=value && $VAR) - Detect
$(cat <<MARKER)string interpolation idiom
evaluator.ts - Decision engine¶
Evaluation hierarchy (first match wins):
- Parse errors → ask
- Empty command → allow
- Subshell extraction and recursive evaluation
- Layer-scoped alwaysDeny/alwaysAllow (project > user > default)
- Target policies (path, database, endpoint)
- Chain-local variable resolution (auto-allow if no rules match)
- Local binary auto-allow (relative-path commands like
./build/foo) - Temp directory rm auto-allow (
rm -rfaftercd /tmpin chain) - Chain-local rm cleanup
- Remote command whitelisting (SSH, Docker, kubectl, Sprite, Fly)
- Package runner subcommand evaluation (npx, bunx, pnpx, uv run)
- Script safety scanning (Python, Node, Perl)
- Command rules with argPattern matching
- Default decision (
config.defaultDecision)
For pipelines/chains: any deny → deny, any ask → ask, all allow → allow.
defaults.ts - Built-in rules¶
Three tiers: always-allow (~60 commands), always-deny (~20 commands), conditional (~50 commands with argument-aware patterns).
rules.ts - Config loader¶
Loads and merges YAML/JSON config from project (.claude/warden.yaml) and user (~/.claude/warden.yaml) levels. Handles legacy config migration, validation, and layer merging.
targets.ts - Target policy evaluator¶
Three policy types: path (filesystem with traversal protection), database (connection string/URI parsing), endpoint (URL matching). Uses glob-to-regex conversion. Most restrictive policy wins.
glob.ts - Pattern matching¶
Two functions: globToRegex (general: *, ?, [...], {a,b,c}) and pathGlobToRegex (path-aware: * = single segment, ** = any depth).
suggest.ts - Feedback system¶
Generates YAML config snippets and help messages when commands are blocked/flagged. Shows /warden:allow and /warden:yolo hints.
notify.ts - OS notifications¶
macOS (terminal-notifier/osascript) and Linux (notify-send). Background, fire-and-forget.
audit.ts - Audit logging¶
JSONL output with 5MB rotation. Configurable path and verbosity.
yolo.ts - YOLO mode¶
Session-scoped auto-allow with time limits. State in /tmp files keyed by session ID.
script-scanner.ts - Script safety scanning¶
Language-specific pattern detection for Python, TypeScript/JavaScript, and Perl. Two levels: dangerous (shell exec, eval, rmtree) and cautious (file writes, network).
codex-export.ts - Codex rules export¶
Converts Warden config to Codex CLI .rules format (Starlark prefix_rule statements).
codex.ts - Codex rule evaluation bridge¶
Evaluates each candidate command (from alwaysAllow, alwaysDeny, and rules across all layers) through Warden's pipeline, producing decision records used by codex-export.ts to generate Starlark rules.
Plugin structure¶
.claude-plugin/plugin.json- Plugin metadatahooks/hooks.json- PreToolUse hook registration (Bash matcher)config/warden.default.yaml- Reference config for userscommands/*.md- Slash command definitions