
Zero-trust sandbox for AI agents with kernel-level filesystem jail, transparent network proxy, and YAML-based policy engine to intercept and control shell commands, file operations, and network requests.
Zero-trust sandbox for autonomous AI agents.
AgentGuard wraps any AI agent (LangChain, CrewAI, AutoGen, custom scripts) with safety rails. One command change:
# Before (dangerous — agent has full system access)
python my_agent.py
# After (sandboxed)
agentguard run -- python my_agent.py
AgentGuard intercepts every shell command, file modification, and network request the agent makes. Safe actions are auto-allowed, dangerous actions are auto-blocked, and everything else prompts the human for approval.
AgentGuard has four defense layers that work together:
┌─────────────────────────────────────────────────────────────┐
│ Layer 0: Filesystem Jail (sandbox-exec on macOS) │
│ Kernel-level enforcement. Restricts file writes and │
│ network at the syscall level. Agent cannot bypass from │
│ userspace. Blocks Python's open(), requests.post(), etc. │
├─────────────────────────────────────────────────────────────┤
│ Layer 1: Network Proxy │
│ Transparent HTTP/HTTPS proxy. Every network call the │
│ agent makes is checked against the policy. Per-destination │
│ allow/deny with full visibility in the TUI. │
├─────────────────────────────────────────────────────────────┤
│ Layer 2: PATH Shims │
│ Shell script shims that intercept commands like git, │
│ pip, curl, rm. Each shim asks the daemon for permission │
│ before running the real binary. │
├─────────────────────────────────────────────────────────────┤
│ Layer 3: Policy Engine + Approval Daemon │
│ YAML-based rules evaluate every intercepted action. │
│ Auto-allow safe commands, auto-block dangerous ones, │
│ prompt the human for everything else. │
└─────────────────────────────────────────────────────────────┘
No single layer is the security boundary. They work together — defense in depth.
go build -o agentguard ./cmd/agentguard/
go build -o agentguard-check ./cmd/agentguard-check/
Both binaries must be in the same directory.
agentguard init
This creates .agentguard/policy.yaml in the current directory. Edit it to match your needs.
agentguard run -- python my_agent.py
The TUI takes over the terminal and shows:
For interactive tools like Claude Code that need the terminal:
agentguard run --headless -- claude
The agent gets the terminal directly. AgentGuard runs silently in the background. All events are logged to ~/.agentguard/logs/headless.log. Monitor in another terminal:
tail -f ~/.agentguard/logs/headless.log
agentguard run [flags] -- <command> [args...]
--policy <path> Use a specific policy file
--headless No TUI — agent gets the terminal
--default-allow Auto-allow PROMPT decisions in headless mode (default: auto-deny)
--no-sandbox Disable sandbox-exec (shims and proxy still active)
agentguard init Create a default policy file
agentguard version Print version
Policies are YAML files that define what the agent can and cannot do. AgentGuard checks three locations (in order):
./.agentguard/policy.yaml (project-local)~/.agentguard/policy.yaml (user global)version: 1
deny:
# Block dangerous commands
- command: "rm"
args: "-rf *"
reason: "Recursive forced deletion is too dangerous"
- command: "sudo"
args: "*"
reason: "Privilege escalation is not allowed"
- command: "chmod"
args: "777 *"
reason: "World-writable permissions are dangerous"
# Block reading sensitive files (enforced by sandbox-exec)
- file:
path: "*.env"
action: "read"
reason: "Don't let agent read .env files"
- file:
path: "*.pem"
action: "read"
reason: "Don't let agent read private keys"
allow:
# Safe read-only commands
- command: "ls"
- command: "cat"
- command: "pwd"
- command: "echo"
- command: "grep"
- command: "head"
- command: "tail"
- command: "wc"
# Read-only git
- command: "git"
args: "status"
- command: "git"
args: "log *"
- command: "git"
args: "diff *"
# Allow writes to workspace
- file:
path: "/tmp/workspace/**"
action: "write"
# Allow specific API endpoints
- network:
destination: "api.anthropic.com:443"
- network:
destination: "api.github.com:443"
deny network *) — checked third. Acts as a default deny.Command rules — match shell commands by name and argument pattern:
- command: "git"
args: "push *"
reason: "Pushing requires approval"
File rules — match file operations (enforced by sandbox-exec):
- file:
path: "*.env"
action: "read" # "read" or "write"
reason: "Protect secrets"
Network rules — match network destinations (enforced by proxy + sandbox-exec):
- network:
destination: "api.anthropic.com:443"
Use * as a wildcard in command args, file paths, and network destinations.
agentguard/
├── cmd/
│ ├── agentguard/ # Main CLI binary
│ └── agentguard-check/ # Shim helper binary
├── internal/
│ ├── policy/ # Policy engine (YAML parsing, rule evaluation)
│ ├── events/ # Event system (JSONL audit log, pub/sub)
│ ├── daemon/ # Central daemon (Unix socket, approval queue)
│ │ └── client/ # Client library for shims
│ ├── shim/ # Shim generator (PATH-based interception)
│ ├── proxy/ # Transparent network proxy
│ ├── spawner/ # Orchestration + macOS sandbox integration
│ └── ui/tui/ # Terminal UI (Bubble Tea)
├── configs/
│ └── default_policy.yaml # Reference policy file
├── .gitignore
├── go.mod
├── LICENSE
└── README.md
Every intercepted action is logged to ~/.agentguard/logs/YYYY-MM-DD.jsonl:
{"id":"a1b2c3","timestamp":"2026-03-22T14:30:00Z","session_id":"abc123","source":"shim","command":"git","args":["push","origin","main"],"decision":"deny","decided_by":"human","response_time_ms":3200}
{"id":"d4e5f6","timestamp":"2026-03-22T14:30:01Z","session_id":"abc123","source":"proxy","network_dst":"api.anthropic.com:443","decision":"allow","decided_by":"policy"}
Query with standard tools:
# All denied actions today
cat ~/.agentguard/logs/2026-03-22.jsonl | jq 'select(.decision == "deny")'
# All network requests
cat ~/.agentguard/logs/2026-03-22.jsonl | jq 'select(.source == "proxy")'
# Commands that required human approval
cat ~/.agentguard/logs/2026-03-22.jsonl | jq 'select(.decided_by == "human")'
Threat model: The agent is untrusted. It may try to:
rm -rf /, sudo).env, private keys)What AgentGuard prevents:
.env, .pem, etc.)filepath.CleanWhat AgentGuard does NOT prevent (known limitations):
ctypes/cffi (sandbox-exec blocks these too on macOS)api.anthropic.com, the agent can send data there)go test ./... -race
The project has 140+ tests covering:
jail_darwin.go — macOS sandbox-exec (compiled only on macOS)jail_noop.go — fallback shim-only mode (compiled on Linux/Windows)sandbox_monitor_darwin.go — macOS system log tailing for sandbox violationssandbox_monitor_noop.go — no-op on non-macOS platformsSee LICENSE.
| Key | Action | When |
|---|
Y | Allow the pending request | Approval prompt visible |
N | Deny the pending request | Approval prompt visible |
A | Allow + remember for this session ("Always Allow") | Approval prompt visible |
B | Deny + remember for this session ("Block Forever") | Approval prompt visible |
Tab | Toggle agent stdout/stderr panel | Always |
Up/Down | Scroll activity stream | Always |
Q | Quit (kills the agent) | Always |
| Agent action | Shims | Proxy | sandbox-exec |
|---|
subprocess.run(["rm", "-rf", "/"]) | Yes | - | - |
subprocess.run(["git", "push"]) | Yes | - | - |
requests.post("https://evil.com") | - | Yes | Yes |
urllib.request.urlopen("https://api.com") | - | Yes | Yes |
open(".env", "r") | - | - | Yes |
open("/etc/shadow", "w") | - | - | Yes |
/usr/bin/curl https://evil.com (absolute path) | - | Yes | Yes |
| Component | Package | Purpose |
|---|
| Policy Engine | internal/policy | Parses YAML rules, evaluates requests → ALLOW / DENY / PROMPT |
| Event System | internal/events | Append-only JSONL audit log + real-time pub/sub for TUI |
| Daemon | internal/daemon | Unix socket server, approval queue with timeouts, session management |
| TUI | internal/ui/tui | Bubble Tea terminal UI with activity stream and approval modal |
| Shim Generator | internal/shim | Generates shell script shims, resolves real binary paths |
| Network Proxy | internal/proxy | Transparent HTTP/HTTPS proxy enforcing per-destination policy |
| Spawner | internal/spawner | Orchestrates everything: policy → daemon → shims → proxy → sandbox → agent → TUI |
| macOS Sandbox | internal/spawner/jail_darwin.go | sandbox-exec with Seatbelt profiles for kernel-level enforcement |
| Platform | Shims | Proxy | sandbox-exec | File read deny |
|---|
| macOS (Apple Silicon) | Yes | Yes | Yes | Yes |
| macOS (Intel) | Yes | Yes | Yes | Yes |
| Linux | Yes | Yes | No (future: namespaces + seccomp) | No |
| Windows | Yes | Yes | No (future: Job Objects) | No |