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:

  1. Installing manifests — coreutils, git, cargo, npm, pip, dangerous-patterns, sanitize-env
  2. Locking the policy — compiles, signs, and installs the warrant
  3. Choosing your agents — select which to wrap (Codex, Claude Code, OpenCode)
  4. 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:

  1. Aliases set guard env vars: alias codex='WSH_GUARD=1 BASH_ENV="$HOME/.bashenv" codex'
  2. A hook in ~/.zshenv (and mirrored to ~/.zshrc) intercepts zsh -c commands:
    if [[ -n "$ZSH_EXECUTION_STRING" && "$WSH_GUARD" != "0" && ( -n "$WSH_GUARD" || "$CLAUDECODE" = "1" ) ]]; then
      wsh guard "$ZSH_EXECUTION_STRING" || exit 1
    fi
  3. A hook in ~/.bashenv intercepts bash -c commands:
    if [[ -n "$BASH_EXECUTION_STRING" && "$WSH_GUARD" != "0" && ( -n "$WSH_GUARD" || "$CLAUDECODE" = "1" ) ]]; then
      wsh guard "$BASH_EXECUTION_STRING" || exit 1
    fi
  4. Claude Code additionally gets a PreToolUse hook in ~/.claude/settings.json with matcher Bash, so wsh guard runs before Claude’s internal Bash tool executes.
  5. wsh guard evaluates 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

AgentMethodStatus
Codexwsh setup codexTested — shell startup guard hooks (.zshenv/.zshrc, .bashenv)
Claude Codewsh setup claudeTested — shell hooks + Claude PreToolUse Bash hook
OpenCodewsh setup codexGuard hook via shell startup files
Custom agentswsh 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