Privacy-first local AI agent runtime — sandboxed execution, automatic sensitivity routing, and hybrid local/cloud model switching.
A Python runtime that lets AI agents run primarily on your local hardware. A privacy router automatically classifies each task for sensitive content (PII, credentials, proprietary code) and routes it to the right model:
- Sensitive tasks → Ollama (local model, data never leaves your machine)
- Non-sensitive tasks → Claude (cloud model, better capability)
- Always local mode → force everything through Ollama
Inspired by NVIDIA NemoClaw — the idea that always-on agents with privacy-aware routing will be the default architecture for enterprise AI deployments.
# 1. Install Ollama and pull a local model
brew install ollama
ollama pull llama3.2
# 2. Install dependencies
pip install -e .
export ANTHROPIC_API_KEY=your_key # only needed for cloud routing
# 3. Run examples
python examples/hybrid_research.py # see routing in action
python examples/summarize_local_docs.py # always-local modeUser Task
│
▼
Privacy Router ──── classifies sensitivity
│ │
│ LOW/MEDIUM/HIGH │
│ │
▼ HIGH ▼ LOW
Local Model Cloud Model
(Ollama/Llama) (Claude/GPT)
│ │
└────────┬───────────┘
▼
Response + Audit Log
The router scans task text for sensitive patterns:
| Pattern | Sensitivity | Example |
|---|---|---|
| Email addresses | HIGH | user@company.com |
| API keys / passwords | HIGH | api_key = "sk-..." |
| Private keys | HIGH | -----BEGIN RSA PRIVATE KEY----- |
| AWS credentials | HIGH | AKIAIOSFODNN7EXAMPLE |
| Internal hostnames | MEDIUM | db.internal.corp.com |
| Private IP ranges | MEDIUM | 192.168.1.100 |
| Public queries | LOW | routes to cloud |
from src.privacy_router import classify_task
decision = classify_task("Connect to db.internal.company.com", context="")
print(decision.sensitivity) # Sensitivity.MEDIUM
print(decision.use_local) # True
print(decision.reasons) # ["Detected internal host"]# config/default.yaml
local_model: "llama3.2"
cloud_model: "claude-opus-4-6"
force_local: false
allowed_read_paths:
- "~/Documents"
- "/tmp"
allowed_write_paths:
- "/tmp"
allowed_commands:
- "ls"
- "cat"
- "grep"from src.runtime import Runtime, RuntimeConfig
# Default: hybrid routing
runtime = Runtime()
response = await runtime.run("What is connection pooling?")
print(response.model_used) # "cloud:claude-opus-4-6"
print(response.routed_locally) # False
# Force local: data never leaves machine
config = RuntimeConfig(force_local=True)
runtime = Runtime(config)
response = await runtime.run(
"Summarize this document",
context=open("private_doc.txt").read()
)
print(response.model_used) # "local:llama3.2"All file operations and shell commands go through a sandbox with explicit allowlists:
from src.sandbox import Sandbox, SandboxConfig
config = SandboxConfig(
allowed_read_paths=["/home/user/projects"],
allowed_write_paths=["/tmp"],
allowed_commands=["ls", "cat", "grep"],
)
sandbox = Sandbox(config)
# Read file (allowed)
result = sandbox.read_file("/home/user/projects/config.yaml")
# Read outside allowlist (blocked, logged)
result = sandbox.read_file("/etc/passwd") # allowed=False
# Full audit trail
print(sandbox.audit_log())src/
├── runtime.py # Main entry point — load config, run tasks
├── agent.py # Privacy-aware agent with routing logic
├── privacy_router.py # Sensitivity classifier and routing decisions
├── sandbox.py # Filesystem/command sandbox with allowlists
└── models/
├── local_model.py # Ollama client (Llama, Mistral, Phi, etc.)
└── cloud_model.py # Anthropic Claude client
pip install -e ".[dev]"
pytest tests/ -v
# No API keys required — tests mock model calls