Claude Code, Cursor, Copilot, and Aider all rely on application-level permission systems (ignore files, allow/deny lists) that can be bypassed. aigate moves that boundary into the OS kernel: POSIX ACLs, Linux namespaces, and egress allowlists physically block what the agent can read, execute, and reach on the network, regardless of what the model decides to try.
The most-starred tool in the AxeForge portfolio. See it on GitHub.
Every file read, command, and network call the agent makes is checked against your rules before it runs.
Four enforcement layers, each backed by an OS primitive the sandboxed process cannot negotiate with.
Persistent POSIX ACLs (setfacl) on Linux, extended ACLs (chmod +a) on macOS, deny read access at rest. At run time, mount namespaces overmount denied directories with empty tmpfs and files with /dev/null: two layers of defense-in-depth.
allowed_paths hides everything in $HOME except the working directory and paths you allow. Non-scoped files are invisible: reads fail, listings don't leak names, writes land in a discarded overlay.
Bubblewrap's --unshare-net plus slirp4netns and iptables/ip6tables restrict egress to your allow_net allowlist on Linux; Seatbelt network-outbound rules do the same on macOS.
User and PID namespaces (--unshare-user --unshare-pid) mean the sandboxed process can't see or signal anything on the host, and needs no real root to set up mounts and networking.
aigate prefers bwrap when it's installed and falls back cleanly when it isn't; run aigate doctor to see which mode is active.
| Layer | Linux (bwrap) | Linux (unshare fallback) | macOS |
|---|---|---|---|
| File | Declarative bind-mount overrides | Shell-script mount overrides | Seatbelt file-read* deny rules |
| Network | --unshare-net + slirp4netns + iptables | Nested unshare + slirp4netns + iptables | sandbox-exec network-outbound rules |
| Process | --unshare-user --unshare-pid, sandboxed PID 1 | unshare --user --map-root-user | Enforced by Sandbox.kext |
| Command exec | mount --bind deny stubs + arg-checking wrappers | Same bind-mount stubs | (deny process-exec) rules |
Each identity has its own Claude Code login, GitHub CLI login, git author and ssh key. A session only gets its own; the kernel hides the rest.
aigate identity add work asks for folders, git author and ssh key, then logs in to Claude and gh inside that identity's sandbox. Your first identity can adopt your current ~/.claude without moving anything.
aigate identity use work binds a folder. Every run says which identity is active and why; aigate whoami answers it without running anything.
Other identities' folders are hidden, host tokens like GH_TOKEN are removed, and git over ssh uses only the identity's key, never an agent. A cloned repo's .aigate.yaml can't pick an identity.
| What a session can reach | Linux | macOS |
|---|---|---|
Other identities' files, gh login, ssh keys | Hidden (bwrap) | Hidden (Seatbelt) |
| Git author / committer | Per identity | Per identity |
| Other identities' Claude login | Hidden | Separate Keychain item, not access-isolated (aigate doctor explains) |
$ aigate identity add work
$ cd ~/work && aigate identity use work
$ aigate run -- claude
[aigate] identity: work (folder ~/work)
setupOne-time, needs sudo. Creates the ai-agents OS group and ai-runner user that ACL rules attach to.
initWrites ~/.aigate/config.yaml with sensible defaults: .env, secrets/, ~/.ssh/, and friends, denied out of the box.
deny / allowAdd or remove file, exec, and network rules, globally or per-project, via .aigate.yaml, which extends the global config.
runLaunches any AI tool inside the sandbox and prints exactly which restrictions are active to stderr before it starts.
doctorChecks bwrap/slirp4netns/namespaces and prints a READY/DEGRADED/BLOCKED verdict, and exits non-zero so CI can gate on it.
GDPR/ISO/security teams need a trust boundary that isn't "the model chose not to read the file." ACLs and namespaces don't have that failure mode.
sudo aigate setup && aigate init
Deny read on .env, secrets/, and SSH keys, then mask API keys and tokens (Anthropic, OpenAI, GitHub, Cloudflare, Stripe, Slack and more) that still make it into stdout.
aigate deny read .env secrets/ *.pem
An agent that can only resolve the hosts you named can't phone home to anywhere else, curl an attacker's server, or exfiltrate over DNS.
aigate deny net --except api.anthropic.com
doctor exits non-zero when full isolation isn't available, so a pipeline can refuse to run an agent unsandboxed.
aigate doctor || exit 1
Install the binary
curl -L https://github.com/AxeForging/aigate/releases/latest/download/aigate-linux-amd64.tar.gz | tar xz
sudo mv aigate-linux-amd64 /usr/local/bin/aigate
One-time system setup: sudo aigate setup && aigate init
Run any AI tool sandboxed: aigate run -- claude