Integrating with AI Agents
wsh enforces capability policies on AI coding agents transparently. The agent runs normal commands — wsh intercepts and checks them before execution. The agent never needs to know wsh exists.
Quick setup (recommended)
One command sets up everything:
wsh setup codex This walks you through:
- Installing manifests — coreutils, git, cargo, npm, pip, dangerous-patterns, sanitize-env
- Locking the policy — compiles, signs, and installs the warrant
- Choosing your agents — select which to wrap (Codex, Claude Code, OpenCode)
- Installing the guard hook — a shell hook that checks every command against policy
After setup, use your agent normally:
codex # every command is policy-enforced and audited
claude # same — transparent to the agent How it works
AI agents like Codex and Claude Code execute commands by spawning a shell — typically /bin/zsh -lc 'command'. They ignore the $SHELL environment variable, which means traditional shell-wrapper approaches don’t work.
wsh solves this with shell hooks, and for Claude specifically, a tool hook:
- Aliases set guard env vars:
alias codex='WSH_GUARD=1 BASH_ENV="$HOME/.bashenv" codex' - A hook in
~/.zshenv(and mirrored to~/.zshrc) intercepts zsh-ccommands:if [[ -n "$ZSH_EXECUTION_STRING" && "$WSH_GUARD" != "0" && ( -n "$WSH_GUARD" || "$CLAUDECODE" = "1" ) ]]; then wsh guard "$ZSH_EXECUTION_STRING" || exit 1 fi - A hook in
~/.bashenvintercepts bash-ccommands:if [[ -n "$BASH_EXECUTION_STRING" && "$WSH_GUARD" != "0" && ( -n "$WSH_GUARD" || "$CLAUDECODE" = "1" ) ]]; then wsh guard "$BASH_EXECUTION_STRING" || exit 1 fi - Claude Code additionally gets a
PreToolUsehook in~/.claude/settings.jsonwith matcherBash, sowsh guardruns before Claude’s internal Bash tool executes. wsh guardevaluates the command against the warrant policy. Shell builtins are allowed through. External commands are checked against manifest rules. If denied, the shell exits before the command runs.
Codex/OpenCode are covered by shell startup hooks. Claude needs the extra PreToolUse hook because some command paths run through its internal Bash tool.
What the agent sees
When a command is denied, the agent receives a clean error:
exec /bin/zsh -lc 'curl https://example.com' exited 1 in 51ms:
denied by warrant policy: curl https://example.com Well-behaved agents understand the denial and adapt — they’ll try an approved alternative or ask the user for guidance.
Supported agents
| Agent | Method | Status |
|---|---|---|
| Codex | wsh setup codex | Tested — shell startup guard hooks (.zshenv/.zshrc, .bashenv) |
| Claude Code | wsh setup claude | Tested — shell hooks + Claude PreToolUse Bash hook |
| OpenCode | wsh setup codex | Guard hook via shell startup files |
| Custom agents | wsh exec -- <cmd> | Direct enforcement |
Other setup bundles
wsh setup offers three bundles:
- codex — Git, NPM, pip, Codex manifest, dangerous-patterns, sanitize-env
- claude — Git, NPM, pip, Claude manifest, dangerous-patterns, sanitize-env
- minimal — Coreutils and dangerous-pattern blocking only
Direct enforcement
For scripts, CI, or custom integrations, use wsh exec directly:
wsh exec -- cargo build # runs if allowed, denied otherwise
wsh check -- curl https://evil.com # dry-run: prints allow/deny Bash integration
For bash-based agents, add a DEBUG trap to .bashrc:
preexec_wsh() {
case "$BASH_COMMAND" in
wsh\ *|cd\ *|export\ *|source\ *|"."\ *) return ;;
esac
if ! wsh check $BASH_COMMAND 2>/dev/null; then
echo "denied by warrant policy: $BASH_COMMAND" >&2
return 1
fi
}
trap 'preexec_wsh' DEBUG Security model
The guard hook is a guardrail, not a sandbox. It catches normal agent commands reliably but can be bypassed by adversarial techniques (command substitution, scripts calling banned tools). wsh includes evasion detection for common tricks, but for hard containment, use warrant-box.
- Warrant Guardrails (wsh + guard hook): catches honest mistakes and obvious misuse
- Warrant Box (coming soon): OS-level enforcement via execve interception