Catalog PyPI
PACKAGE EXPLORERView in registry

agentbox-runtime

PyPI

Policy-sandboxed runtime for AI agent processes: enforce a policy file, capture a tamper-evident trace, deterministically replay any run.

agentsllmpolicyreplaysafetysandboxtrace
Versions collected1
Direct dependencies0From release 0.3.0
Last observed20 Oct, 21:34 UTC

README

Version 0.3.0 documentation

agentbox

A sandbox runtime for AI agent processes. One policy file says what the agent may touch; agentbox wraps the process, enforces the policy at the interpreter level, captures a tamper-evident trace of every side effect, and can deterministically replay any recorded run.

allow: read ./src, net: api.github.com

Zero dependencies. Pure Python stdlib. Python 3.11+.

Why

Agents run with your whole user account: your SSH keys, your ~/.aws, your network. Reviewing what an agent did after the fact means scrolling logs that the agent itself could have written. agentbox gives you three properties that compose:

  1. Policy — default-deny capability file for filesystem, network, subprocesses, and environment variables.
  2. Trace — every allowed effect and every denial is appended to a hash-chained JSONL log. Edit, delete, or reorder one line and agentbox verify catches it.
  3. Replay — re-run the same command against the trace: recorded effects are served back (network never touched, clock and RNG frozen, writes skipped), and any behavioral divergence — including an input file whose content changed — fails the replay with the exact step that differed.

Quickstart

pip install agentbox-runtime

agentbox init                                   # writes a starter agentbox.policy
agentbox run    -p agentbox.policy -- python agent.py    # record
agentbox show                                   # inspect the trace
agentbox verify                                 # check the hash chain
agentbox replay -p agentbox.policy -- python agent.py    # deterministic re-run

A run looks like this:

$ agentbox run -p agentbox.policy -- python demo_agent.py
wrote out/summary.txt at 1786243519.9181929
blocked as expected: agentbox: policy denies read /etc/passwd
agentbox: recorded 4 effects, 1 observations, 1 denials -> trace.jsonl

$ agentbox replay -p agentbox.policy -- python demo_agent.py
wrote out/summary.txt at 1786243519.9181929        # same clock value, replayed
agentbox: replay ok — 5/5 recorded steps matched

Policy file

One rule per line, # comments, everything not allowed is denied:

read:  ./data              # file reads under this root
write: ./out               # writes (implies read) under this root
net:   api.github.com      # DNS + connect to this host
net:   *.githubusercontent.com
net:   127.0.0.1:8080      # optional port pin
net:   unix:/tmp/app.sock  # unix sockets
exec:  git status          # argv prefix match
exec:  echo                # bare program name: any args
env:   HOME                # env vars passed into the sandbox
env:   AWS_*               # globs work everywhere

allow: read ./src is an alias for read: ./src, and rules can share a line: allow: read ./src, net: api.github.com.

How enforcement works

agentbox run spawns your command with a scrubbed environment (only env:-allowed variables survive) and injects a sitecustomize shim via PYTHONPATH. Before any user code runs, the shim installs a sys.addaudithook guard — CPython audit hooks cannot be removed once installed, so the agent's own code can't disarm it. The guard:

  • blocks open() outside the policy roots (stdlib and sys.path imports are exempt), and records allowed reads with a content sha256;
  • blocks DNS resolution and socket connects to non-allowed hosts;
  • blocks subprocess/os.system/os.exec* spawns that don't match an exec: rule, plus deletes/renames outside write roots;
  • blocks ctypes dlopen/dlsym — the classic audit-hook bypass;
  • fails closed: if the sandbox can't arm, the process refuses to start.

For replayable effects, agents use the SDK (anything outside it is still guarded and observed):

import agentbox.client as box

text = box.read_text("data/notes.txt")
resp = box.get("https://api.github.com/repos/x/y")   # {"status", "body", "sha256"}
out  = box.run(["git", "status"])                    # {"code", "stdout", "stderr"}
t    = box.now()      # frozen on replay
r    = box.random()   # frozen on replay
box.write_text("out/report.md", text.upper())

Undo what the agent did

Policy says what the agent may touch — but allowed ≠ wanted. With snapback installed, --checkpoint snapshots the working tree right before the agent's first mutating effect, so every recorded run is one command away from never having happened:

pip install snapback-cli

$ agentbox run --checkpoint -p agentbox.policy -- python agent.py
agent done: rewrote data/notes.txt, wrote out/report.md
agentbox: recorded 4 effects, 0 observations, 0 denials -> trace.jsonl
agentbox: checkpoint 20260809-143103 taken before first mutation — `snapback undo` reverts this run

$ snapback diff              # what did it actually change?
A out/report.md
M data/notes.txt

$ snapback undo              # put it all back
snapback: restored 20260809-143103

Properties worth knowing:

  • Lazy — the snapshot is taken on the first write_text/run, not at startup. Runs that only read cost nothing.
  • In the chain — the checkpoint is recorded as a hook.checkpoint effect in the same hash-chained trace, so "what can I roll back to" is part of the same tamper-evident record as "what did it do" (agentbox show shows it).
  • Fails closed — if the snapshot can't be taken, the mutation is blocked with CheckpointError rather than proceeding un-undoable.
  • Replay-transparent — agentbox replay neither re-snapshots nor diverges on the hook entry.
  • Drop a snapback.toml with ignore = ["trace.jsonl"] next to your agent so rolling back the agent's writes never truncates the audit trail (see examples/).

Full demo: examples/checkpoint_agent.py.

Node agents

The same runner sandboxes Node processes — no extra install:

agentbox run    -p agentbox.policy -- node agent.js
agentbox replay -p agentbox.policy -- node agent.js

A CommonJS shim is injected via NODE_OPTIONS --require; it enforces the same policy file (fs, net, child_process, env scrub), appends to the same hash chain the runner starts, and exposes the SDK as globalThis.agentbox:

const box = globalThis.agentbox;
const text  = box.readText("data/notes.txt");
const resp  = await box.get("https://api.github.com/repos/x/y");
const out   = box.run(["git", "status"]);
const t     = box.now();      // integer ms, frozen on replay
const r     = box.random();   // integer in [0, 2^48), frozen on replay
box.writeText("out/report.md", text.toUpperCase());

Caveat: the Node guard monkeypatches fs/net/child_process — it contains well-behaved agents and prompt-injected tool calls, but unlike CPython's irremovable audit hooks it is not a boundary against code that deliberately unpatches it. Hardening it (Node permission model flags) is a welcome PR.

Threat model, honestly

agentbox is an interpreter-level sandbox for Python processes, not a kernel one. What that means in practice:

StopsDoesn't stop
An agent (or its prompt-injected tool call) reading ~/.ssh, posting to an unapproved host, spawning rm -rfA malicious C extension making raw syscalls
Secret env vars leaking into the process at allBugs in CPython itself
Post-hoc log tampering (hash chain)A hostile human with local root
Silent behavioral drift between runs (replay divergence)Non-Python child processes (their spawn is policy-checked; their own IO is not yet guarded)

Kernel backends (Landlock on Linux, Seatbelt on macOS) are on the roadmap as defense-in-depth; the policy file and trace format won't change.

Replay semantics

  • SDK effects are matched in order by (op, args) and served from the trace.
  • Guard-observed direct IO is verified: a read whose file content changed since recording is a divergence, with the sha256 diff in the report.
  • Live network and subprocess spawns are blocked during replay — replayable effects must go through the SDK.
  • Replay from the same working directory; relative paths are part of the match.

Roadmap — contributions are deliberately bite-sized

Each of these is a single focused PR:

  • One policy rule per PR — net: cidr/…, rate limits (net: api.x.com @10/min), read-once:, size caps on write:.
  • One language runtime per PR — Node (--require shim), Deno (permissions bridge), Bun; the policy/trace/replay core is runtime-agnostic.
  • One trace exporter per PR — OTLP spans, SQLite, agentbox show --html timeline.
  • Kernel backends: Landlock, Seatbelt, seccomp-bpf.
  • Adapters: LangGraph / OpenAI Agents / Claude Agent SDK tool-call wrappers.

See CONTRIBUTING.md.

Development

python -m pytest        # 59 tests, all stdlib + pytest (Node tests auto-skip without node)

MIT © Sophie Nguyen Thu Thuy

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.3.09 Aug 20260

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
sophie-nguyenthuthuy/agentbox

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:34 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:15645529599edb145f5e76883cbeb2ac811dd32cf161a53d7efcb48fd2db0ca5