Metadata-Version: 2.4
Name: castor-kernel
Version: 0.5.1
Summary: A secure microkernel for LLM Agents
Project-URL: Homepage, https://github.com/substratum-labs/castor
Project-URL: Repository, https://github.com/substratum-labs/castor
Project-URL: Documentation, https://substratum-labs.github.io/castor/
Project-URL: Issues, https://github.com/substratum-labs/castor/issues
Author: Substratum Labs
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: agents,checkpoint,hitl,llm,microkernel,security
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: pydantic>=2.0
Requires-Dist: sqlalchemy>=2.0
Provides-Extra: autogen
Requires-Dist: autogen-agentchat>=0.4; extra == 'autogen'
Requires-Dist: autogen-core>=0.4; extra == 'autogen'
Provides-Extra: crewai
Requires-Dist: crewai>=0.80; extra == 'crewai'
Provides-Extra: demo
Requires-Dist: litellm>=1.0; extra == 'demo'
Requires-Dist: rich>=13.0; extra == 'demo'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs>=1.6; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.27; extra == 'docs'
Provides-Extra: google-adk
Requires-Dist: google-adk>=0.1; extra == 'google-adk'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.2; extra == 'langchain'
Requires-Dist: langgraph>=0.2; extra == 'langchain'
Provides-Extra: mcp
Requires-Dist: fastmcp>=3.1.0; extra == 'mcp'
Provides-Extra: observability
Requires-Dist: opentelemetry-api>=1.20; extra == 'observability'
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'observability'
Provides-Extra: openai-agents
Requires-Dist: openai-agents>=0.1; extra == 'openai-agents'
Provides-Extra: pydantic-ai
Requires-Dist: pydantic-ai>=0.1; extra == 'pydantic-ai'
Provides-Extra: smolagents
Requires-Dist: smolagents>=1.0; extra == 'smolagents'
Description-Content-Type: text/markdown

# Castor

[![CI](https://github.com/substratum-labs/castor/actions/workflows/ci.yml/badge.svg)](https://github.com/substratum-labs/castor/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/castor-kernel)](https://pypi.org/project/castor-kernel/)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)

<p align="center">
  <img src="assets/security_levels.png" alt="Castor: Same agent, three security levels" width="900">
</p>

**The secure execution layer for AI agents.** Three levels of protection — from human approval on every action, to full-speed speculative execution with post-hoc review, to time-travel rollback when things go wrong.

Your agent's code stays untouched. Castor wraps your existing tools, tracks every action, and enforces safety — without your agent knowing it's there.

---

## 🚀 Quick Start

```bash
pip install castor-kernel
```

```python
import asyncio
from castor import Castor, auto_approve
from castor.lib import tool

# Your existing tools — plain functions, no decorators needed
async def search(query: str) -> list[str]:
    return [f"Result for: {query}"]

async def delete_file(path: str) -> str:
    return f"Deleted {path}"

# Your agent — doesn't know about Castor
async def my_agent():
    results = await tool("search", query="old logs")
    await tool("delete_file", path="/tmp/old1")
    await tool("delete_file", path="/tmp/old2")
    return "Cleaned up"

async def main():
    kernel = Castor(
        tools=[search, delete_file],
        destructive=["delete_file"],       # mark dangerous tools
    )

    # Option A: auto-approve (for testing / trusted environments)
    cp = await kernel.run_until_complete(my_agent, on_hitl=auto_approve)
    print(cp.result)  # "Cleaned up"

    # Option B: speculative — full speed, review after
    cp = await kernel.run(my_agent, speculative=True)
    summary = kernel.scan(cp)
    print(f"{summary.total_steps} steps, {summary.flagged_count} need review")

asyncio.run(main())
```

`search` runs immediately (safe tool). `delete_file` is destructive — in default mode Castor suspends for human approval. In speculative mode it runs but flags the step for post-hoc review. **The agent doesn't know either way.**

## 🛡️ Three Levels of Protection

### Level 1: HITL — Human approves every dangerous action

```python
cp = await kernel.run(my_agent, budgets={"api": 10})
# → destructive tools pause for approval, safe tools run immediately
```

### Level 2: Speculative — Full speed, review after

```python
cp = await kernel.run(my_agent, speculative=True)
summary = kernel.scan(cp)
# → 23 steps, 21 auto-verified, 2 flagged for review
```

Agent runs without interruption. Every destructive operation is flagged with `needs_review` — the kernel decides at execution time, not after. You review the flagged steps, approve or reject.

### Level 3: Time-Travel — Rewind and fix mistakes

```python
# Agent finished but Step 5 was wrong
forked = cp.fork(at_step=5)
cp2 = await kernel.run(my_agent, checkpoint=forked)
# → Steps 1-4 replay from cache (free). Steps 5+ re-execute.
```

Don't re-run the whole thing. Rewind to the mistake, fix it, fork a new timeline. Cached steps cost nothing — no re-execution, no re-billing.

Run `uv run python examples/security_levels.py` to see all three levels on the same task.

## 💡 Philosophy

Agent frameworks give LLMs tools. They don't control how those tools are used. Guardrails are advisory — the agent still owns execution.

Castor inverts this. **The agent doesn't call tools. It requests them.** Every side effect is a syscall that passes through a kernel. The kernel validates, budgets, gates, and logs before anything executes.

| | OS Concept | Castor Analog |
|:---:|---|---|
| 🏗️ | User / Kernel space | Agent code / Castor kernel |
| 📞 | System calls | `tool()` / `proxy.syscall()` |
| 🎟️ | Capabilities | Depletable budget tokens |
| ⏯️ | Process checkpointing | Fork, replay, time-travel |
| 🧠 | Virtual memory | Context window MMU |

Like Linux, your program (agent) uses libc (`castor.lib`) and never touches the kernel directly. The operator configures security policy. Three roles, fully separated:

```
Tool developer:  writes plain functions (no Castor knowledge)
Agent developer: uses castor.lib.tool() (no kernel imports)
Operator:        Castor(tools=, destructive=, budgets=)
```

## 🔧 CLI

Run agents from the command line — like a shell for AI agents:

```bash
castor run agent.py:main \
    --tool tools.py:search \
    --tool tools.py:delete_file --destructive \
    --budget api=50 \
    --speculative
```

Agent and tool code have zero Castor knowledge. The operator configures everything via CLI flags.

```bash
castor ps                              # list agents
castor inspect <pid>                   # view checkpoint
castor approve <pid>                   # approve pending action
castor reject <pid> --reason "..."     # reject with feedback
```

## 🛡️ Guard Any Framework

Already using an agent framework? Pass your tools through Castor. Your framework runs the agent loop, Castor guards the tool calls.

```python
from castor import Castor
from castor.lib import tool

# ── Your existing tools (unchanged) ──

async def web_search(query: str) -> str:
    return f"Results for: {query}"          # your real search implementation

async def delete_file(path: str) -> str:
    os.remove(path)                         # your real file deletion
    return f"Deleted {path}"

# ── Your existing agent logic (unchanged) ──

async def my_agent():
    results = await tool("web_search", query="old temp files")
    for path in parse_paths(results):
        await tool("delete_file", path=path)
    return "Cleanup done"

# ── Operator adds Castor (one place, no changes to above) ──

kernel = Castor(
    tools=[web_search, delete_file],
    destructive=["delete_file"],
    budgets={"api": 20, "disk": 5},
)

cp = await kernel.run(my_agent, speculative=True)
summary = kernel.scan(cp)
print(f"{summary.total_steps} steps, {summary.flagged_count} need review")
```

This works with any framework — LangChain, CrewAI, smolagents, pydantic-ai, or your own code. The only requirement: tool calls go through `castor.lib.tool()`. The agent loop is yours.

## 🔒 Security Scope

Castor provides **application-layer control**: it gates what the agent *intends* to do (tool calls, budgets, approval). It does **not** sandbox the process (filesystem, network). For defense in depth, run Castor inside a container or use [Roche](https://github.com/substratum-labs/roche), a sandbox orchestrator designed for AI agents. Castor controls intent; your infrastructure controls capability.

## 📚 Documentation

- **[API Reference](https://substratum-labs.github.io/castor/)**: All modules and classes
- **[Architecture & Guides](https://substratum-labs.github.io/castor-docs/)**: Whitepaper, deep dives, getting started

## 🤝 Contributing

Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## 🛠️ Development

```bash
git clone https://github.com/substratum-labs/castor.git
cd castor && uv sync
uv run pytest
uv run ruff check src/
```

## 📄 License

Apache 2.0. See [LICENSE](LICENSE).
