The kernel does not care what you named the tool AgentGuard, an Apache-2.0 Linux eBPF LSM supervisor for coding agents, launched at version 0.1.2 as an early prototype that enforces security policy at the kernel level rather than inside the agent. The tool loads YAML policy from policies/default.yaml to block access to credentials such as .env and id_rsa, destructive argv like rm and dd, and non-allowlisted egress on port 443, returning EPERM on denial. AgentGuard is tested primarily with Claude Code and wired the same way for Codex, but native Darwin claude is not supervised because macOS has no BPF LSM. Back to blogs /blogs September 8, 2026 The kernel does not care what you named the tool AgentGuard: eBPF LSM for coding agents. YAML in the repo. Deny is EPERM . Linux prototype · Apache-2.0 · github.com/AgentGuard-hq/AgentGuard https://github.com/AgentGuard-hq/AgentGuard You asked the agent to fix a failing test. The GitHub issue looked normal. Buried in a fixture, or in an MCP response, or in a README the model helpfully fetched, was an instruction to read .env and post it somewhere. The model may even agree that secrets are off-limits. That is not a security boundary. The boundary is whether openat succeeds. Coding agents are not chatbots with a nicer prompt. They open , exec , and connect . The failure that matters is the next syscall , not the next token. Conscience is not a TCB Most guardrails live inside the agent: - a system prompt - CLAUDE.md / AGENTS.md - PreToolUse hooks - an allowlist of “Bash” strings Those are a conscience. Consciences are bypassed the moment execution leaves the tool schema. Deny .env in a hook, then read it with python -c , perl , node , a loader, mmap , anything that is not Read or Bash as the CLI defines them. Deny rm as a command string, then hit the same inode another way. The hook never ran. The kernel still would — if you asked it to . Vendor sandboxes Seatbelt, bubblewrap, Claude’s sandbox-runtime , devcontainers are the right product default for most people. This post is a narrower claim: Policy that remains true when the agent’s own conscience is false. That layer is the LSM. Deny is EPERM . The OS does not care what the tool was named. What AgentGuard is AgentGuard is a Linux eBPF LSM supervisor for coding agents. One binary loads policy into the kernel and starts the agent as the invoking user, not root. Policy is YAML in the project policies/default.yaml . Starter rules: - Credentials — block .env , id rsa , the usual secret paths - Destructive argv — rm , dd , the obvious ones - Egress — allowlisted hosts on 443, via a local proxy; everything else denied A deny is a kernel error, not a chat message. Optionally, Claude Code / Codex hooks inject a feedback: string so the model can adapt instead of spinning on a raw permission error. If the hooks are missing, the kernel still blocks . The model just is not told why. That split is the whole design: | Layer | Job | |---|---| | LSM | Enforcement. Fail closed. | | YAML in git | Policy you can review in the PR. | | Hooks | Explanation. Courtesy. Not the TCB. | policies/default.yaml │ ▼ eBPF LSM loaded as root │ ▼ agent as SUDO USER │ ├── openat ".env" → EPERM ├── execve "rm", … → EPERM └── connect not :443 allowlist → EPERM │ └── optional: "SYSTEM FEEDBACK: …" into the TUI Status: v0.1.2 , early. Tested primarily with Claude Code. Codex is wired the same way. Native Darwin claude is not supervised — macOS has no BPF LSM. A Colima/Docker Linux VM is a different machine, not a magic halo around the host binary. Why EPERM and not another hook Hooks inspect intent as the product serialized it . LSM inspects what the process did . If you only wrap Bash , you have not wrapped python . If you only wrap the CLI’s Read tool, you have not wrapped openat from a compiler, a test runner, or a postinstall script the agent just spawned. Child processes inherit the LSM. They do not inherit your settings.json . That is also why AgentGuard is not “prompt injection detection.” Injection is how you get to a bad syscall. The interesting part is whether the syscall is allowed. Catching every encoding of “ignore previous instructions” is a language problem. Catching openat on .ssh/id rsa is a kernel problem. I would rather have both. I will not pretend the first replaces the second. Privilege, said plainly Loading BPF is a loaded privilege. Typically root at load, CAP BPF in play. Two rules I treat as non-negotiable: 1. LSM only. The supervisor must not attach tracing probes on the agent’s TLS stack or rewrite userspace buffers. If you need to mutate what the model “saw” in order to “help,” you are no longer a reference monitor. 2. Pin the object. Drop caps on the child. doctor should fail on a hash mismatch. The agent must not keep CAP BPF . A second tracing program on the box is a peer of the supervisor, not a child you can YAML away — unless you also gate bpf / program types. “We used eBPF” is not the same sentence as “you can trust us.” The first is a mechanism. The second is a TCB story: hashed program, allowlisted types, no extra helpers, agent running as a boring user. install.sh cannot invent lsm=bpf . That is a boot-time fact. If doctor says BPF is missing from the LSM list, that is the kernel cmdline, not a missing mount. Securityfs being readable is not the same as enforcement. Non-goals on purpose AgentGuard is not : - a replacement for Anthropic’s Seatbelt / bubblewrap sandbox, MDM, or Claude Code on the web - a Mac-native enforcer - a hosted microVM product that is E2B/Daytona/Modal - a complete jail — the default YAML is a starter, completeness is a policy problem - unprivileged install on a random laptop kernel If the threat model is “untrusted repo, don’t toast the laptop,” start with the first-party sandbox or a VM. Use something like this when you need agent-agnostic, auditable syscall policy on a Linux box you already control. There are many other GitHub repos named AgentGuard. This one is the kernel one. The name collision is annoying and irrelevant to the claim. What “working” looks like The demo I care about is not a cartoon jailbreak. 1. Hooks and CLAUDE.md say: never read .env , never rm -rf . 2. The prompt is ordinary: debug the test / summarize the issue. 3. The bypass does not go through the tool the hook subscribed to. 4. Hooks-only: the secret is in context, or the file is gone. 5. LSM: EPERM . Process still alive. Optional feedback: so the model retries cleanly. If I cannot show a hook path that loses and an LSM path that holds , I do not have a product. I have a policy compiler with extra steps. Why this exists I wanted to know whether coding-agent safety could live at the same layer as every other process on Linux: LSM, fail closed, policy in git. The prototype says yes , with the usual kernel tax — BTF, lsm=bpf , sudo to load, no Darwin miracles. The industry is shipping consciences at industrial scale. Some of them are good consciences. I still want the door to lock when the conscience is tired, confused, or prompt-injected. Hooks are the agent’s conscience. The kernel is the door. AgentGuard is Apache-2.0, v0.1.2, Linux. Code and a longer engineering note: github.com/AgentGuard-hq/AgentGuard https://github.com/AgentGuard-hq/AgentGuard .