A security boundary for LLM agents — policy, audit, and rollback for every tool call
Project description
Agent OS Kernel
A security boundary for LLM agents. Every tool call an agent makes is authorized by policy, logged immutably, and optionally reversible — enforced at the architecture level, not by convention.
Why
When you give an LLM access to tools, nothing enforces what it can actually do. The agent may misread instructions, be manipulated by prompt injection, or simply make a mistake — and there is no layer between it and the real world.
Agent OS Kernel is that layer:
User Prompt
↓
AgentLoop ←──── LiteLLM (100+ LLM providers)
↓
tool_calls[]
↓
kernel.submit(request) ← sole execution path
├── Policy: allow / deny
├── Provider: execute action
└── Log: append audit record
↓
tool results → LLM → loop
One API. Three invariants.
| Invariant | Meaning |
|---|---|
| All access through Gate | kernel.submit() is the only code path that executes tools — enforced structurally, not by convention |
| Default deny | Actions not explicitly allowed in YAML policy are blocked |
| No silent actions | Every decision — allowed or denied — produces exactly one log record |
The key difference from wrapper-based approaches: ToolDef contains zero execution logic. There is no decorator to forget, no opt-in to skip, no bypass path in the code.
Features
- Structural Gate enforcement —
kernel.submit()is the sole tool execution path;ToolDefis pure metadata with no execution logic - Policy-based authorization — YAML allow-list with glob resource matching and constraint support
- Append-only audit log — tamper-evident JSONL; every
submit()is recorded with status, duration, and error - Reversible Action Layer — snapshot-and-rollback for write operations; safety net between "permitted" and "intended"
- 4 built-in providers — filesystem, process, HTTP, MCP (Model Context Protocol)
- 100+ LLM providers — LiteLLM-powered: OpenAI, Anthropic, Ollama, Azure, and more
- CLI —
submit,log,validate-policy,version - High throughput — 77,000+ ops/s, p99 < 0.1 ms
- Minimal core — ~1,600 lines of kernel source code; small enough to audit, complete enough to enforce
Quick Start
pip install py-agent-kernel
Or install from source:
git clone https://github.com/JiahaoZhang-Public/agent-kernel.git
cd agent-kernel
pip install -e .
Direct Kernel Usage
from agent_os_kernel import Kernel, ActionRequest
from agent_os_kernel.providers.filesystem import FilesystemProvider
with Kernel(policy="policy.yaml", providers=[FilesystemProvider()], log_path="kernel.log") as kernel:
result = kernel.submit(ActionRequest(action="fs.read", target="/workspace/data.csv"))
print(result.status) # OK
denied = kernel.submit(ActionRequest(action="fs.read", target="/etc/passwd"))
print(denied.status) # DENIED
Agent Loop (LLM-driven)
import asyncio
from agent_os_kernel import Kernel, AgentLoop, ToolDef
from agent_os_kernel.providers.filesystem import FilesystemProvider
# 1. Tools are pure metadata — no execution logic
read_file = ToolDef(
name="read_file",
description="Read a file",
parameters={
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
action="fs.read",
target_from="path",
)
write_file = ToolDef(
name="write_file",
description="Write content to a file",
parameters={
"type": "object",
"properties": {
"path": {"type": "string"},
"content": {"type": "string"},
},
"required": ["path", "content"],
},
action="fs.write",
target_from="path",
)
# 2. AgentLoop routes every tool call through kernel.submit()
with Kernel(policy="policy.yaml", providers=[FilesystemProvider()], log_path="kernel.log") as kernel:
loop = AgentLoop(
kernel=kernel,
model="gpt-4o", # or "anthropic/claude-sonnet-4-20250514", "ollama/llama3"
instructions="You are a data analyst.",
tools=[read_file, write_file],
)
result = asyncio.run(loop.run("Read /workspace/sales.csv and write a summary"))
print(result)
Every tool call the LLM generates is converted to an ActionRequest and submitted through the kernel Gate. Denied actions return an error string to the LLM — the agent continues running, but the action is blocked and logged.
More Examples
See examples/ for 30 runnable examples organized by category:
| Category | Description | LLM Required |
|---|---|---|
01_basic_kernel/ |
Direct kernel.submit(), status codes, audit log |
No |
02_policy/ |
Inline, YAML, glob matching, constraints | No |
03_agent_loop/ |
LLM-driven agents, multi-tool, denial handling | Yes |
04_reversible/ |
Snapshot, rollback, TTL expiry | No |
05_providers/ |
Filesystem, process, HTTP GET/POST | No |
06_multi_provider/ |
Provider chaining, agent with all providers | Mixed |
07_custom_provider/ |
Build your own provider | No |
08_advanced/ |
Callable target_from, agent+reversible, log analysis | Mixed |
# Run any example
uv run python examples/01_basic_kernel/hello_kernel.py
# LLM examples need an API key
OPENAI_API_KEY=sk-... uv run python examples/03_agent_loop/file_analyst.py
Reversible Actions
The Reversible Action Layer wraps the kernel without modifying it. Rollback requests go through the Gate like any other action — authorized and logged.
from agent_os_kernel.reversible import ReversibleActionLayer, SnapshotStore, FsWriteSnapshotStrategy
layer = ReversibleActionLayer(
kernel=kernel,
strategies=[FsWriteSnapshotStrategy()],
store=SnapshotStore("/tmp/.snapshots"),
)
# Write through the layer — snapshot captured automatically
result = layer.submit(ActionRequest(
action="fs.write",
target="/workspace/output/report.txt",
params={"content": "oops, wrong content"},
))
# Roll it back
rollback = layer.rollback(result.record_id)
print(rollback.status) # OK — file restored
Policy bounds the scope of damage. Rollback bounds the duration.
Providers
| Provider | Actions | Description |
|---|---|---|
FilesystemProvider |
fs.read, fs.write, fs.delete |
Local filesystem operations |
ProcessProvider |
proc.exec |
Shell command execution with timeout |
HttpProvider |
net.http |
GET/POST/PUT/DELETE via urllib |
McpProvider |
mcp.call |
Any MCP server over stdio (JSON-RPC 2.0) |
MCP Integration
from agent_os_kernel.providers.mcp import McpProvider
provider = McpProvider(servers={
"my_server": {"command": ["python", "my_mcp_server.py"]},
})
result = kernel.submit(ActionRequest(
action="mcp.call",
target="my_server/some_tool",
params={"arguments": {"key": "value"}},
))
Policy
# policy.yaml
capabilities:
- action: fs.read
resource: /workspace/**
- action: fs.write
resource: /workspace/output/**
- action: net.http
resource: https://api.example.com/**
constraint:
method: GET
- action: mcp.call
resource: my_server/**
python -m agent_os_kernel validate-policy --policy policy.yaml
CLI
# Submit a single action
python -m agent_os_kernel submit --action fs.read --target /workspace/data.csv --policy policy.yaml
# Inspect the audit log
python -m agent_os_kernel log --log-path kernel.log --status DENIED
# Print version
python -m agent_os_kernel version
Performance
Measured on GPU server with RTX 4090 (Python 3.10):
| Benchmark | Throughput | p99 Latency |
|---|---|---|
| Sequential (deny-only, 2000 ops) | 77,048 ops/s | 0.02 ms |
| Sequential with fs.read (500 ops) | 29,526 ops/s | 0.04 ms |
| Concurrent (10 threads x 100 ops) | 7,092 ops/s | 3.68 ms |
| Mixed allow/deny stress (1000 ops) | 40,566 ops/s | 0.04 ms |
| Write throughput (200 files) | 14,136 ops/s | 0.11 ms |
| Log integrity (8 threads x 50 ops) | 400/400 entries | - |
Development
# Install
uv sync --all-extras && uv run pre-commit install
# Test
uv run pytest # 207+ tests, 96%+ coverage
uv run pytest --cov=src/agent_os_kernel # with coverage report
# Lint
uv run ruff check src/ && uv run ruff format src/
# E2E demo (requires API key)
OPENAI_API_KEY=sk-... OPENAI_MODEL=gpt-5.4-mini \
python scripts/e2e_agent_demo.py
# Performance benchmarks
python scripts/perf_test.py
Project Structure
src/agent_os_kernel/
├── kernel.py # Gate — single submit() entry point
├── policy.py # Policy engine — YAML + glob matching
├── log.py # Append-only JSONL audit log
├── models.py # ActionRequest, ActionResult, Record
├── agent_loop.py # AgentLoop + ToolDef (kernel-native, LiteLLM)
├── reversible.py # Reversible Action Layer (v2.1)
├── config.py # Config loader
├── __main__.py # CLI entry point
└── providers/
├── filesystem.py # fs.read / fs.write / fs.delete
├── process.py # proc.exec
├── http.py # net.http
└── mcp.py # mcp.call (JSON-RPC 2.0 over stdio)
tests/ # 207+ tests, 96%+ coverage
examples/ # 30 runnable examples (8 categories)
scripts/ # perf_test.py, e2e_agent_demo.py, demo_kernel.py
configs/ # example, restrictive, permissive policies
docs/
├── user/ # Public documentation (MkDocs)
└── research/ # Design specs (v0 → v2.1) and plans
Roadmap
- v0.1 — Core kernel: Gate, Policy, Log, Providers, Reversible Layer
- v0.2 — MCP provider, CLI, 96% test coverage
- v0.3 — Live E2E tests, real MCP integration, performance benchmarks
- v0.4 — Kernel-native agent loop (all access through Gate enforced structurally)
- v0.5 — Budget / rate limiting layer
- v0.6 — Human-in-the-loop approval gate
- v1.0 — Stable API, full documentation, production hardening
Design
The kernel design is versioned and documented in docs/research/design/:
- v0 — initial concept
- v1 — provider model
- v2 — Gate + Policy + Log invariants
- v2.1 — Reversible Action Layer
- v2.2 — Kernel-Native Agent Loop (current)
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
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 py_agent_kernel-0.4.3.tar.gz.
File metadata
- Download URL: py_agent_kernel-0.4.3.tar.gz
- Upload date:
- Size: 24.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5ec06459f662a67c55f21aab28479a577acaa6234510d4eb3b2ab66c88b3946
|
|
| MD5 |
6f8407bb2778b8f7e17a6839b9724155
|
|
| BLAKE2b-256 |
7f4d0a3b517dcf187fbcb967f3a922476927f58e7d9cb201fdcaaf9dbdcf9d5f
|
Provenance
The following attestation bundles were made for py_agent_kernel-0.4.3.tar.gz:
Publisher:
publish.yml on JiahaoZhang-Public/agent-kernel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_agent_kernel-0.4.3.tar.gz -
Subject digest:
c5ec06459f662a67c55f21aab28479a577acaa6234510d4eb3b2ab66c88b3946 - Sigstore transparency entry: 1192603591
- Sigstore integration time:
-
Permalink:
JiahaoZhang-Public/agent-kernel@0c63aafbc361e94cfc035dcf3a15012fdc103520 -
Branch / Tag:
refs/tags/v0.4.3 - Owner: https://github.com/JiahaoZhang-Public
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0c63aafbc361e94cfc035dcf3a15012fdc103520 -
Trigger Event:
release
-
Statement type:
File details
Details for the file py_agent_kernel-0.4.3-py3-none-any.whl.
File metadata
- Download URL: py_agent_kernel-0.4.3-py3-none-any.whl
- Upload date:
- Size: 27.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0ee911584a46288f2c61ef0e7f4aa713ca05568480b3faff67b65e4babf0d00
|
|
| MD5 |
4b51cc213cef8c68efbb5fa906f056a8
|
|
| BLAKE2b-256 |
1d2b7471b24ebaf45f3342dc751df2edec651e6ee82a81f4e660c37810ec3b8a
|
Provenance
The following attestation bundles were made for py_agent_kernel-0.4.3-py3-none-any.whl:
Publisher:
publish.yml on JiahaoZhang-Public/agent-kernel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_agent_kernel-0.4.3-py3-none-any.whl -
Subject digest:
f0ee911584a46288f2c61ef0e7f4aa713ca05568480b3faff67b65e4babf0d00 - Sigstore transparency entry: 1192603638
- Sigstore integration time:
-
Permalink:
JiahaoZhang-Public/agent-kernel@0c63aafbc361e94cfc035dcf3a15012fdc103520 -
Branch / Tag:
refs/tags/v0.4.3 - Owner: https://github.com/JiahaoZhang-Public
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0c63aafbc361e94cfc035dcf3a15012fdc103520 -
Trigger Event:
release
-
Statement type: