Runtime Safety for Python AI Agents
Enforce kernel-level isolation, network filtering, and atomic rollbacks from Python with nono-py.
pip install nono-pySecure execution model
nono-py provides Python bindings to nono's core Rust library via PyO3. The SDK exposes four key systems: kernel-level process sandboxing, a network proxy with credential injection, filesystem snapshots with rollback, and a policy engine for composable security profiles.
Two sandboxing modes are available. nono.apply(caps) applies kernel-level restrictions to the current process — irrevocable, inherited by all child processes. nono.sandboxed_exec() runs a command in a sandboxed child process, leaving the parent unsandboxed. Use the first for self-sandboxing agents; use the second for orchestrators that need to spawn isolated workloads.
Full type stubs are included ( py.typed) — mypy, pyright, and IDE autocompletion work out of the box.
Kernel-Level Sandbox
Apply irrevocable filesystem restrictions via Landlock (Linux and Windows) or Seatbelt (macOS). Define per-path access modes — read, write, read-write. Everything not explicitly allowed is denied at the kernel level.
Network Proxy & Credential Injection
Domain-filtered outbound access with per-route credential injection. Supports header, URL path, query parameter, and basic auth injection modes. Real API keys stay outside the sandbox — only phantom tokens enter the process.
Filesystem Snapshots
Content-addressable snapshots with Merkle roots. Create baselines before agent execution, compute diffs after, and roll back to any previous state. Respects .gitignore patterns and custom exclusions.
Sandboxed Child Processes
Run untrusted code in a sandboxed child process via sandboxed_exec(). The parent stays unsandboxed. Set working directory, timeout, and environment variables. Captures stdout and stderr as bytes.
import nono_py as nono# Define capabilities — deny by defaultcaps = nono.CapabilitySet()caps.allow_path("/project", nono.AccessMode.READ_WRITE)caps.allow_file("/home/user/.gitconfig", nono.AccessMode.READ)caps.block_network()# Apply sandbox (irrevocable — kernel-enforced)nono.apply(caps)# Your agent runs sandboxed from hereagent.run()
import nono_py as nono# Run a command in a sandboxed child process# Parent stays unsandboxedcaps = nono.CapabilitySet()caps.allow_path("/project", nono.AccessMode.READ_WRITE)result = nono.sandboxed_exec(caps,["python", "untrusted_script.py"],cwd="/project",timeout_secs=30,env=[("API_KEY", "phantom-token-here")])print(result.exit_code)print(result.stdout.decode())
import nono_py as nono# Network proxy with credential injectionroute = nono.RouteConfig(prefix="/v1",upstream="https://api.openai.com",credential_key="openai_api_key",inject_mode=nono.InjectMode.HEADER,inject_header="Authorization",credential_format="Bearer {credential}")proxy = nono.ProxyConfig(allowed_hosts=["api.openai.com"],routes=[route])handle = nono.start_proxy(proxy)print(f"Proxy on port {handle.port}")print(handle.env_vars()) # {"HTTP_PROXY": "..."}print(handle.credential_env_vars()) # phantom tokens# Drain audit events after the sessionevents = handle.drain_audit_events()handle.shutdown()
import nono_py as nono# Snapshot the working directory before agent executionexclusions = nono.ExclusionConfig(use_gitignore=True,exclude_patterns=["node_modules", ".next", "__pycache__"])mgr = nono.SnapshotManager("/project", exclusions)mgr.create_baseline()# ... agent runs and modifies files ...mgr.create_incremental()diff = mgr.compute_restore_diff()for change in diff:print(f"{change.change_type}: {change.path}")# Roll back everything the agent changedmgr.restore_to(snapshot_number=0)
Core API
CapabilitySet
Builder for filesystem and network rules. allow_path(), allow_file(), block_network(), platform_rule(). Irrevocable after apply().
QueryContext
Dry-run permission checks. query_path() and query_network() test whether access would be allowed before applying the sandbox.
Policy
Load and resolve JSON security profiles. Built-in groups (python_runtime, node_runtime) expand to platform-specific paths. Composable and version-controlled.
ProxyConfig
Network proxy with domain allowlists, per-route credential injection (header, URL, query param, basic auth), and audit event streaming.
SnapshotManager
Content-addressable filesystem snapshots. Baseline, incremental, compute diffs, restore to any point. Merkle root verification.
sandboxed_exec()
Run a command in a sandboxed child process. Set cwd, timeout, env vars. Parent process remains unsandboxed for orchestration.
import nono_py as nono# Dry-run permission checks before applyingcaps = nono.CapabilitySet()caps.allow_path("/project", nono.AccessMode.READ_WRITE)ctx = nono.QueryContext(caps)result = ctx.query_path("/etc/passwd", nono.AccessMode.READ)print(result["status"]) # "denied"print(result["reason"]) # explains whynet = ctx.query_network("api.openai.com", 443)print(net["status"]) # "denied" (block_network not set, default)