Platform Intelligence Layer — context governance for autonomous agents
Project description
AutoPIL — Platform Intelligence Layer
Context governance middleware for autonomous AI agents.
AutoPIL sits between your agents and your data sources, enforcing who can retrieve what, under what conditions — and logging every access decision with an immutable audit trail.
Agent → @guard.protect(...) → Policy Engine → Data Source
↓ ↓
Audit Log AlertEngine → webhook / email
↓
OTEL Spans + Metrics → Datadog / Grafana / Splunk
Why AutoPIL
As enterprises deploy multi-agent AI systems, the gap that emerges isn't in the LLMs — it's in what context they're allowed to retrieve. Most governance tools operate at the output layer (content filtering, hallucination detection). AutoPIL operates at the retrieval layer, before sensitive data ever enters the agent's context window.
Key problems it solves:
- An underwriting agent accessing another customer's credit data
- A customer service bot retrieving internal risk models it has no business seeing
- One agent in a pipeline hijacking another agent's session context
- No audit trail of what data was retrieved and when
- No alerting when denial spikes or policy violations occur
- No observability in existing monitoring tooling
Architecture
┌─────────────────────────────────────────────────────────┐
│ Your Agent │
└────────────────────────┬────────────────────────────────┘
│ @guard.protect(...)
┌────────────────────────▼────────────────────────────────┐
│ ContextGuard │
│ 1. Cross-agent session isolation check │
│ 2. Policy evaluation (allow / deny) ◄──────── PolicyEngine
│ 3. OTEL span + metrics emitted │
│ 4. Execute retrieval (if allowed) │
│ 5. Hash context for provenance │
│ 6. Record immutable audit event ──────────► AlertEngine
└──────────────┬────────────────────────┬─────────────────┘
│ │
┌──────────────▼──────┐ ┌─────────────▼───────────────┐
│ Storage Backend │ │ OTEL Collector │
│ SQLite (default) │ │ Datadog / Grafana / Splunk │
│ Postgres (prod) │ └─────────────────────────────┘
└─────────────────────┘
Enforcement mechanisms:
| Mechanism | Description |
|---|---|
| Source allowlist | Agent can only access explicitly permitted data sources |
| Source denylist | Certain sources are always blocked, regardless of allowlist |
| Sensitivity ceiling | Each role has a maximum data sensitivity level it can access |
| Task scoping | Roles can be restricted to specific task types (allowed_tasks / denied_tasks) |
| Cross-agent isolation | A session belongs to the first agent that used it — others are denied |
| Session lifecycle | Sessions expire by TTL or can be revoked; expired/revoked sessions are denied |
| Default deny | No matching policy = access denied |
Integration modes:
| Mode | How it works | Best for |
|---|---|---|
| Python decorator | @guard.protect(...) wraps retrieval functions directly |
LangGraph, LangChain, custom Python agents |
| REST API | POST /v1/context/evaluate from any language |
Polyglot stacks, TypeScript, Java, Go |
| MCP server | evaluate_context / record_action as native MCP tools |
Claude Desktop, GPT-4, Gemini, any MCP-compatible agent |
| FastAPI / ASGI middleware | AutoPILMiddleware intercepts requests at the API layer |
Enforcing governance without touching agent code |
| AWS Bedrock Agents | BedrockGuard.wrap_invoke_agent() |
Bedrock-hosted agents |
| LangChain / LangGraph | LangChainGuard.wrap_tool() |
LangChain tools and graphs |
| LlamaIndex | LlamaIndexGuard.wrap_query_engine() |
LlamaIndex query engines |
| OpenAI Agents SDK | OpenAIAgentsGuard — @guard.function_tool() decorator |
OpenAI Assistants and function tools |
| Gemini | GeminiGuard.call_if_allowed() |
Gemini-based agents |
Integration channels — source_type values:
| Channel | Class | source_type |
|---|---|---|
| REST API | ContextGuard + FastAPI |
rest |
| MCP | MCPGuard / mcp server |
mcp |
| Python SDK | ContextGuard |
sdk |
| FastAPI / ASGI | AutoPILMiddleware |
api |
| AWS Bedrock Agents | BedrockGuard |
bedrock |
| LangChain / LangGraph | LangChainGuard |
langchain |
| LlamaIndex | LlamaIndexGuard |
llamaindex |
| OpenAI Agents SDK | OpenAIAgentsGuard |
openai_agents |
| Gemini | GeminiGuard |
gemini |
Every audit event is stamped with the source_type of the channel that produced it. The /v1/audit/stats endpoint returns a by_source_type breakdown showing totals, allowed, and denied counts per channel.
Quickstart
Install
pip install -e .
For the REST server:
pip install -e ".[server]"
For OpenTelemetry (gRPC — Datadog, Splunk):
pip install -e ".[otel]"
For OpenTelemetry (HTTP — Grafana Cloud):
pip install -e ".[otel-http]"
For the MCP server (Claude Desktop, GPT-4, Gemini, any MCP-compatible agent):
pip install -e ".[mcp]"
For Postgres:
pip install -e ".[postgres]"
Define a policy
# policies/my_policy.yaml
policies:
- name: analyst_policy
agent_role: analyst
allowed_sources:
- reports
- market_data
denied_sources:
- executive_comms
max_sensitivity: high
allowed_tasks: # optional — restrict to specific task types
- summarization
- qa
denied_tasks: # optional — block specific task types
- extraction
Wrap your retrieval functions
from autopil import ContextGuard, SensitivityLevel
guard = ContextGuard(
policy_path="policies/my_policy.yaml",
audit_db="autopil.db",
)
@guard.protect(
agent_role="analyst",
user_id="user_123",
source_id="reports",
sensitivity_level=SensitivityLevel.HIGH,
session_id="session_abc",
)
def retrieve_reports(query: str) -> list:
return vectorstore.search(query)
# Authorized — returns results
results = retrieve_reports("Q3 performance")
# Unauthorized — raises PermissionError, logs the denial
results = retrieve_reports_from_exec_comms("board notes")
For async agents, use protect_async instead:
@guard.protect_async(
agent_role="analyst",
user_id="user_123",
source_id="reports",
sensitivity_level=SensitivityLevel.HIGH,
session_id="session_abc",
)
async def retrieve_reports_async(query: str) -> list:
return await vectorstore.asearch(query)
protect_async uses contextvars.ContextVar for last_event_id, so concurrent asyncio Tasks never overwrite each other's state.
View the audit trail
events = guard.get_audit_trail("session_abc")
for e in events:
print(e.decision, e.source_id, e.context_hash)
Framework Integrations
LangChain
from autopil import LangChainGuard
guard = LangChainGuard(policy_path="policies/", audit_db="autopil.db")
safe_tool = guard.wrap_tool(my_langchain_tool, agent_role="analyst", source_id="reports")
LlamaIndex
from autopil import LlamaIndexGuard
guard = LlamaIndexGuard(policy_path="policies/", audit_db="autopil.db")
safe_engine = guard.wrap_query_engine(query_engine, agent_role="analyst", source_id="docs")
result = await safe_engine.aquery("Q3 summary")
AWS Bedrock Agents
from autopil import BedrockGuard
guard = BedrockGuard(policy_path="policies/", audit_db="autopil.db")
safe_invoke = guard.wrap_invoke_agent(agent_role="analyst", source_id="bedrock_kb")
response = safe_invoke(agentId=..., sessionId=..., inputText="...")
FastAPI / ASGI Middleware
from autopil import AutoPILMiddleware, RouteRule
app.add_middleware(
AutoPILMiddleware,
guard=guard,
rules=[RouteRule(path="/v1/retrieve/{doc_id}", agent_role="analyst",
source_id="reports", sensitivity_level="high")],
)
Denied requests receive a 403 JSON response. Set on_deny="log" on a RouteRule for shadow/dry-run mode — the request passes through but the denial is still recorded.
Running the API Server
First start
On first start, AutoPIL creates a default tenant and prints a one-time superadmin API key:
AutoPIL API Server
Policy : policies/
Database : sqlite @ autopil_audit.db
⚠ First start — created 'default' tenant and superadmin key:
apl_<your-key-here>
Save this — it will not be shown again.
Docs : http://localhost:8000/docs
Use this key in the X-API-Key header for all API requests.
Local development (two terminals)
Terminal 1 — backend:
cd packages/core
python3.11 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
python3 serve.py --policy policies/
Terminal 2 — dashboard:
cd packages/dashboard
npm install
npm run dev
Open http://localhost:5173 for the dashboard (Vite proxies API calls to :8000 automatically).
Open http://localhost:8000/docs for the interactive API docs.
With OpenTelemetry
export OTEL_SERVICE_NAME=autopil
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.mycompany.com:4317
python3 serve.py --policy policies/
The server prints OTEL: <endpoint> on startup when OTEL is configured.
With Postgres
export DATABASE_URL=postgresql://user:pass@localhost:5432/autopil
python serve.py --policy policies/
Docker
docker compose up --build
The server starts on http://localhost:8000.
- Dashboard: http://localhost:8000
- API docs: http://localhost:8000/docs
Alerting
AutoPIL includes a rules engine that monitors the audit log and fires notifications when anomalies are detected. Rules are created via the REST API and evaluated synchronously on every audit event.
Rule types
| Type | Fires when |
|---|---|
denial_spike |
X denials occur within N minutes |
new_source |
A source_id is accessed that has never appeared in the audit log before |
isolation_violation |
A cross-agent session isolation violation is recorded |
high_deny_rate |
Denial percentage exceeds a threshold within a time window |
Create an alert rule
curl -X POST http://localhost:8000/v1/alerts/rules \
-H "X-API-Key: apl_yourkey" \
-H "Content-Type: application/json" \
-d '{
"name": "denial spike",
"rule_type": "denial_spike",
"threshold": 10,
"window_minutes": 15,
"cooldown_minutes": 30,
"webhook_url": "https://hooks.slack.com/services/..."
}'
Rules can deliver to a webhook URL (HTTP POST with JSON payload) or an email address (requires SMTP_HOST env var). Both can be set on the same rule.
Alert endpoints
POST /v1/alerts/rules — create alert rule
GET /v1/alerts/rules — list rules for this tenant
PUT /v1/alerts/rules/{rule_id} — update a rule
DELETE /v1/alerts/rules/{rule_id} — delete a rule
GET /v1/alerts/fired — recent alert deliveries
OpenTelemetry
AutoPIL emits OTEL spans and metrics from every policy evaluation. When OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_TRACES_EXPORTER is set, the integration is active. When neither is set, there is zero overhead — all OTEL instruments are no-ops.
Span
Every evaluation emits an autopil.evaluate span with attributes:
| Attribute | Value |
|---|---|
autopil.agent_role |
The role making the request |
autopil.source_id |
The data source requested |
autopil.tenant_id |
Tenant identifier |
autopil.session_id |
Session identifier |
autopil.sensitivity_level |
Sensitivity level (if provided) |
autopil.decision |
ALLOW or DENY |
autopil.policy_name |
Policy that matched |
autopil.reason |
Human-readable decision reason |
autopil.latency_ms |
Evaluation latency in milliseconds |
DENY decisions set StatusCode.ERROR on the span.
Metrics
| Metric | Type | Description |
|---|---|---|
autopil.evaluate.count |
Counter | Total evaluations, tagged with decision and tenant_id |
autopil.evaluate.denied.count |
Counter | Denied evaluations, tagged with decision |
autopil.evaluate.duration |
Histogram (ms) | Evaluation latency |
Configuration
| Variable | Description |
|---|---|
OTEL_SERVICE_NAME |
Service name in traces (default: autopil) |
OTEL_EXPORTER_OTLP_ENDPOINT |
OTLP collector endpoint (grpc:// or https://) |
OTEL_EXPORTER_OTLP_HEADERS |
Comma-separated key=value auth headers |
OTEL_TRACES_EXPORTER |
Set to console for local span output |
OTEL_METRICS_EXPORTER |
Set to console for local metrics output |
SDKs
TypeScript / Node
npm install @vibrantcapital/autopil
import { AutoPilClient } from "@vibrantcapital/autopil";
const client = new AutoPilClient({
baseUrl: "https://api.autopil.ai",
apiKey: process.env.AUTOPIL_API_KEY!,
});
const result = await client.context.evaluate({
query: "Q3 earnings summary",
agent_role: "analyst",
user_id: "u_123",
source_id: "financial_reports",
});
if (result.decision === "DENY") {
throw new Error(`Access denied: ${result.reason}`);
}
Zero runtime dependencies. Requires Node 18+. See sdk/typescript/ for the full reference.
Go
go get github.com/vibrantcapital/autopil-go
Stdlib only — no third-party dependencies. Covers all resources: Context, Audit, Sessions, Policies. See sdk/go/ for the full reference.
Java
<dependency>
<groupId>ai.vibrantcapital</groupId>
<artifactId>autopil-java</artifactId>
<version>0.1.0</version>
</dependency>
Jackson only. Builder-pattern models for all resources. See sdk/java/ for the full reference.
MCP Server
AutoPIL ships an MCP (Model Context Protocol) server that exposes governance as native tools for any MCP-compatible agent — Claude, GPT-4, Gemini, or any custom agent that speaks MCP. No code changes required in the agent; the governance layer sits between the model and your data.
Install
pip install -e ".[mcp]"
Start the server
python mcp_serve.py --policy policies/ --db autopil.db
# or via the installed console script:
autopil-mcp --policy policies/ --db autopil.db
Claude Desktop configuration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"autopil": {
"command": "python",
"args": ["/path/to/mcp_serve.py", "--policy", "/path/to/policies/"],
"env": {}
}
}
}
Available tools
| Tool | Description |
|---|---|
evaluate_context |
Policy check before retrieval — returns ALLOW or DENY with reason and event_id |
record_action |
Link a downstream decision to the audit event that authorized it |
query_audit_log |
Query recent audit events (filterable by role, decision, session) |
get_audit_stats |
Aggregate stats — totals, deny rate, top roles |
list_policies |
List active policies (filterable by industry, agent_role) |
reload_policies |
Hot-reload policies from disk without restarting |
get_session_status |
Session summary — owner, event count, sources accessed |
System prompt pattern
Before accessing any data source, call evaluate_context with agent_role, user_id,
source_id, sensitivity_level, and session_id. Only proceed if decision is ALLOW.
After retrieval, call record_action with the event_id to log what you did.
See docs/mcp_integration.md for the full reference.
API Authentication
All /v1/* endpoints require an API key in the X-API-Key header:
curl -H "X-API-Key: apl_yourkey" http://localhost:8000/v1/policies
Key management
# Create a new key (scoped to your tenant)
curl -X POST http://localhost:8000/v1/keys \
-H "X-API-Key: apl_yourkey" \
-H "Content-Type: application/json" \
-d '{"name": "production_agent"}'
# List keys for your tenant
curl http://localhost:8000/v1/keys \
-H "X-API-Key: apl_yourkey"
# Revoke a key
curl -X DELETE http://localhost:8000/v1/keys/{key_id} \
-H "X-API-Key: apl_yourkey"
Keys are hashed (SHA-256) at rest. The plaintext is returned once at creation and never stored.
Multi-Tenancy
AutoPIL supports multiple tenants with row-level data isolation. Each tenant's audit events, policies, alert rules, API keys, and stats are fully isolated.
Create a tenant (superadmin required)
curl -X POST http://localhost:8000/v1/admin/tenants \
-H "X-API-Key: apl_superadminkey" \
-H "Content-Type: application/json" \
-d '{"name": "acme_corp"}'
Response includes tenant_id and admin_key — the initial key for that tenant. Save it; it won't be shown again.
Project Structure
This is a monorepo with three packages managed via npm workspaces.
autopil/
├── packages/
│ ├── core/ # Python backend (FastAPI + policy engine)
│ │ ├── autopil/
│ │ │ ├── __init__.py # Public API: ContextGuard, Decision, SensitivityLevel
│ │ │ ├── models.py # Dataclasses: ContextRequest, AuditEvent, AgentAction, enums
│ │ │ ├── policy_engine.py # YAML policy loader — file or recursive directory
│ │ │ ├── audit_log.py # Shim → SQLiteAuditLog
│ │ │ ├── guard.py # ContextGuard decorator — core enforcement + action lineage
│ │ │ ├── alerting.py # AlertEngine — threshold rules + webhook/email delivery
│ │ │ ├── telemetry.py # OpenTelemetry spans and metrics (optional)
│ │ │ ├── cli.py # autopil-serve entry point
│ │ │ ├── mcp_server.py # MCP server — dispatch_tool(), create_mcp_server(), run_stdio_server()
│ │ │ ├── db/
│ │ │ │ ├── __init__.py # create_stores() factory (7-tuple)
│ │ │ │ ├── base.py # Abstract base classes for all store types
│ │ │ │ ├── sqlite.py # SQLite backend (default)
│ │ │ │ └── postgres.py # Postgres backend (production)
│ │ │ └── api/
│ │ │ ├── app.py # FastAPI application factory
│ │ │ ├── schemas.py # Pydantic request/response models
│ │ │ └── static/ # Built dashboard assets (copied at Docker build time)
│ │ ├── policies/ # 45 pre-built policies across 4 industries
│ │ │ ├── financial_services/
│ │ │ │ ├── consumer_banking.yaml # loan_underwriter, customer_service, fraud_analyst, collections_agent
│ │ │ │ ├── wealth.yaml # wealth_advisor, investment_analyst, kyc_agent, intake_agent
│ │ │ │ ├── risk_compliance.yaml # compliance_officer, aml_investigator, credit_risk_analyst, compliance_agent
│ │ │ │ └── operations.yaml # settlement_agent, ops_support, data_pipeline_agent, risk_agent
│ │ │ ├── healthcare/
│ │ │ │ ├── clinical_operations.yaml # clinical_summary_agent, medication_review_agent, care_gap_agent, triage_agent
│ │ │ │ ├── revenue_cycle.yaml # prior_auth_agent, claims_coding_agent, denial_management_agent, patient_billing_agent
│ │ │ │ └── compliance_privacy.yaml # hipaa_audit_agent, consent_management_agent, breach_detection_agent
│ │ │ ├── telecom/
│ │ │ │ ├── network_operations.yaml # network_fault_agent, capacity_planning_agent, change_management_agent
│ │ │ │ ├── customer_experience.yaml # cx_support_agent, churn_prediction_agent, provisioning_agent
│ │ │ │ └── fraud_assurance.yaml # subscription_fraud_agent, revenue_assurance_agent, wangiri_detection_agent
│ │ │ └── logistics/
│ │ │ ├── supply_chain.yaml # demand_forecast_agent, procurement_agent, inventory_reconciliation_agent
│ │ │ ├── fleet_operations.yaml # route_optimization_agent, driver_compliance_agent, maintenance_scheduling_agent
│ │ │ └── customs_compliance.yaml # trade_compliance_agent, sanctions_screening_agent, import_export_agent
│ │ ├── scripts/
│ │ │ └── simulate_data.py # Populate dashboard with realistic multi-industry demo data
│ │ ├── examples/
│ │ │ ├── langgraph_demo.py # Single agent with LangGraph
│ │ │ └── multi_agent_demo.py # Cross-agent isolation in action
│ │ ├── tests/
│ │ │ ├── conftest.py # Shared fixtures
│ │ │ ├── test_policy_engine.py # 23 policy evaluation tests
│ │ │ ├── test_audit_log.py # 14 audit persistence tests
│ │ │ ├── test_guard.py # 16 ContextGuard enforcement tests
│ │ │ ├── test_api.py # 86 REST API endpoint tests
│ │ │ ├── test_auth.py # 15 API key authentication tests
│ │ │ ├── test_tenants.py # 13 multi-tenancy and isolation tests
│ │ │ ├── test_alerting.py # 21 alerting rules and delivery tests
│ │ │ ├── test_telemetry.py # 17 OTEL span and metrics tests
│ │ │ ├── test_policy_editor.py # 12 policy CRUD and versioning tests
│ │ │ ├── test_multi_industry.py # 65 multi-industry tests
│ │ │ ├── test_mcp_server.py # 42 MCP server tool dispatch tests
│ │ │ └── test_postgres.py # 11 Postgres backend tests (skipped unless DATABASE_URL set)
│ │ ├── Dockerfile # 3-stage build: dashboard → Python builder → runtime
│ │ ├── pyproject.toml
│ │ ├── mcp_serve.py # MCP server entry point (autopil-mcp console script)
│ │ └── serve.py
│ │
│ ├── dashboard/ # React + TypeScript control plane UI
│ │ ├── src/
│ │ │ ├── components/ # UI components (tabs, layout, drawers, charts)
│ │ │ ├── hooks/ # usePoll — background data refresh
│ │ │ ├── lib/ # api.ts (authenticated fetch), utils.ts
│ │ │ ├── types/ # api.ts — TypeScript interfaces for all API shapes
│ │ │ ├── App.tsx # Root component — auth, tab routing, data loading
│ │ │ ├── main.tsx # React 18 entry point
│ │ │ └── index.css # Dark theme design system
│ │ ├── vite.config.ts # Vite config — dev proxy to :8000, configurable outDir
│ │ └── package.json
│ │
│ └── website/ # Marketing site (static HTML)
│
├── sdk/
│ ├── typescript/ # @vibrantcapital/autopil — TypeScript/Node SDK
│ │ ├── src/
│ │ │ ├── client.ts # AutoPilClient with typed resource groups
│ │ │ ├── types.ts # TypeScript interfaces for all shapes
│ │ │ ├── errors.ts # AutoPilError
│ │ │ └── index.ts # Public exports
│ │ └── test/
│ │ └── client.test.ts
│ ├── go/ # github.com/vibrantcapital/autopil-go — Go SDK (stdlib only)
│ └── java/ # ai.vibrantcapital:autopil-java:0.1.0 — Java SDK (Jackson only)
├── docker-compose.yml # Postgres + AutoPIL container (uses packages/core/Dockerfile)
└── package.json # npm workspaces root
Policy Reference
A policy file is a YAML document with a top-level policies list. Each entry maps to one agent role.
policies:
- name: my_policy # Unique identifier, appears in audit log
agent_role: analyst # Must match agent_role passed to guard.protect()
allowed_sources: # Empty list [] = allow all non-denied sources (admin wildcard)
- reports
- market_data
denied_sources: # Always blocked, takes priority over allowed_sources
- executive_comms
max_sensitivity: high # Ceiling: low | medium | high | restricted
allowed_tasks: [] # Optional — empty = allow all non-denied tasks
denied_tasks: [] # Optional — blocks specific task_type values
# industry and category are auto-injected from directory path when loading from a
# policies/<industry>/<category>.yaml structure — no need to add them manually
When loading from a directory (--policy policies/), AutoPIL recursively finds all *.yaml files and injects industry and category from the path. Point the server at a directory to enable multi-industry support:
python serve.py --policy policies/
Evaluation order (first match wins):
- Is
source_idindenied_sources? → DENY - Is
task_typeindenied_tasks? → DENY - Is
allowed_tasksnon-empty andtask_typenot in it? → DENY - Is
allowed_sourcesnon-empty andsource_idnot in it? → DENY - Does
sensitivity_levelexceedmax_sensitivity? → DENY - No issues found → ALLOW
- No policy matched for this
agent_role→ DENY (default deny)
Policies can also be managed via the REST API (POST /v1/policies, PUT /v1/policies/{name}) — changes are versioned and appear in GET /v1/policies/{name}/history.
REST API Reference
Base URL: http://localhost:8000
All /v1/* routes require X-API-Key header. /health is exempt.
Context
POST /v1/context/evaluate
{
"query": "Q3 loss rates",
"agent_role": "loan_underwriter",
"user_id": "user_001",
"source_id": "credit_scores",
"sensitivity_level": "high",
"session_id": "optional-uuid",
"task_type": "optional-task-label"
}
Sessions
GET /v1/sessions — list active sessions for this tenant
GET /v1/sessions/{id} — session status (active | expired | revoked)
DELETE /v1/sessions/{id} — revoke a session immediately
Audit
GET /v1/audit/sessions/{session_id} — full audit trail for a session
GET /v1/audit/events?decision=DENY&limit=100
GET /v1/audit/export?format=csv — bulk export (CSV or JSON)
GET /v1/audit/stats
POST /v1/audit/lineage — record an agent action against an audit event
GET /v1/audit/lineage/{event_id} — retrieve event + all linked downstream actions
Policies
GET /v1/policies — list (optional: ?industry=&category=)
POST /v1/policies
PUT /v1/policies/{name}
DELETE /v1/policies/{name}
GET /v1/policies/{name}/history
POST /v1/policies/reload
Alert rules
POST /v1/alerts/rules
GET /v1/alerts/rules
PUT /v1/alerts/rules/{rule_id}
DELETE /v1/alerts/rules/{rule_id}
GET /v1/alerts/fired
Keys
POST /v1/keys
GET /v1/keys
DELETE /v1/keys/{key_id}
Tenant management (superadmin)
POST /v1/admin/tenants
GET /v1/admin/tenants
DELETE /v1/admin/tenants/{id}
Storage Backends
SQLite (default)
Zero configuration. Used for development and single-instance deployments.
python serve.py --policy policies/ --db /data/autopil.db
Postgres (production)
pip install "autopil[postgres]"
export DATABASE_URL=postgresql://user:pass@host:5432/autopil
python3 serve.py --policy policies/
Schema is created automatically on first start. Supports horizontal scaling.
Docker Compose (Postgres)
docker compose up --build
The default docker-compose.yml starts AutoPIL with a postgres:16-alpine service wired via DATABASE_URL.
Docker Reference
Build
The Dockerfile is a 3-stage build: it compiles the React dashboard, installs the Python package, then assembles the runtime image with the dashboard assets served by the API.
docker build -f packages/core/Dockerfile -t autopil:0.1.0 .
Run
docker run -d \
-p 8000:8000 \
-v $(pwd)/packages/core/policies:/app/policies:ro \
-v autopil-data:/data \
-e AUTOPIL_POLICY=/app/policies \
autopil:0.1.0
Environment variables
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
(unset) | postgresql://... — uses Postgres if set, otherwise SQLite |
AUTOPIL_POLICY |
/app/policies |
Policy file or directory path |
AUTOPIL_DB |
/data/autopil_audit.db |
SQLite audit DB path |
AUTOPIL_HOST |
0.0.0.0 |
Bind host |
AUTOPIL_PORT |
8000 |
Listen port |
OTEL_EXPORTER_OTLP_ENDPOINT |
(unset) | OTLP collector URL — enables OTEL when set |
OTEL_SERVICE_NAME |
autopil |
Service name in traces |
AUTOPIL_SESSION_TTL_MINUTES |
(unset) | Default session TTL in minutes. Unset = sessions never expire. |
SMTP_HOST |
(unset) | SMTP host for alert email delivery |
Running the Examples
LangGraph demo — loan underwriting agent
python examples/langgraph_demo.py
Runs a 3-node LangGraph pipeline that makes 4 retrieval attempts (2 allowed, 2 denied) and prints the full audit trail.
Multi-agent demo — cross-agent isolation
python examples/multi_agent_demo.py
Runs a 4-agent wealth onboarding pipeline and demonstrates cross-agent isolation violations being blocked while the legitimate pipeline still reaches an APPROVED decision.
Running the Test Suite
Python
pip install -e ".[dev]"
pytest tests/ -v --ignore=tests/test_postgres.py
312 tests, all passing (11 skipped without Postgres):
| File | Tests | What it covers |
|---|---|---|
test_policy_engine.py |
23 | Allow/deny paths, sensitivity ceiling, admin wildcard, task scoping |
test_audit_log.py |
14 | Persistence, session isolation, context hash |
test_guard.py |
16 | Decorator enforcement, audit creation, cross-agent isolation |
test_api.py |
86 | REST endpoints, filtering, export, lineage, session lifecycle, task scoping |
test_auth.py |
15 | API key creation, listing, revocation, auth enforcement |
test_tenants.py |
13 | Tenant lifecycle, data isolation, superadmin enforcement |
test_alerting.py |
21 | Rule CRUD, all rule types, cooldown, delivery, API integration |
test_telemetry.py |
17 | OTEL spans, metrics, guard integration, API integration |
test_policy_editor.py |
12 | Policy CRUD, version history, restore, reload |
test_multi_industry.py |
65 | Directory loading, path metadata, 45-policy real set, industry/category filters, multi-industry evaluate, task scoping |
test_mcp_server.py |
42 | All 7 MCP tools — evaluate, audit query/stats, list policies, record action, reload, session status, server wiring |
test_postgres.py |
11 | Postgres backend (runs when DATABASE_URL is set) |
TypeScript SDK
cd sdk/typescript
npm install
npm test
28 tests covering all resource groups, error handling, query params, and URL normalisation.
Go SDK
cd sdk/go
go test ./...
Java SDK
cd sdk/java
mvn test
Sensitivity Levels
Ordered from least to most sensitive:
| Level | Value | Example data |
|---|---|---|
| Low | low |
Public product catalogs, FAQ knowledge bases |
| Medium | medium |
Account summaries, transaction history |
| High | high |
Credit scores, identity records, loan history |
| Restricted | restricted |
Regulatory filings, internal risk models, audit logs |
License
AutoPIL is licensed under the Business Source License 1.1.
What this means in practice:
- Free to use for development, research, evaluation, and any non-commercial purpose
- Free for internal production use — deploy it inside your own organization without restriction
- Commercial restriction — you may not offer AutoPIL or a substantially similar product as a managed service or SaaS to third parties without a commercial license
- Converts to MIT on March 25, 2030 — the full codebase becomes open source automatically on that date
For commercial licensing or enterprise deployments: anil@vibrantcapital.ai
Version
0.1.0 — initial release
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 autopil-0.1.2.tar.gz.
File metadata
- Download URL: autopil-0.1.2.tar.gz
- Upload date:
- Size: 172.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 |
19e4e460b527fe5c9699061612eaa4f6237f4d12f6746387466b2ead7ce30846
|
|
| MD5 |
919b00190b3e9b828671833fcba939ea
|
|
| BLAKE2b-256 |
0fcbb08b6825a4c2e3622b357d8ddd2f590590c8cd46251a0cccbce459df5125
|
Provenance
The following attestation bundles were made for autopil-0.1.2.tar.gz:
Publisher:
publish.yml on anil-solleti/autopil
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
autopil-0.1.2.tar.gz -
Subject digest:
19e4e460b527fe5c9699061612eaa4f6237f4d12f6746387466b2ead7ce30846 - Sigstore transparency entry: 1203740107
- Sigstore integration time:
-
Permalink:
anil-solleti/autopil@e4844edf3fc2f5e500282e79cbd10d5059d6a410 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/anil-solleti
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e4844edf3fc2f5e500282e79cbd10d5059d6a410 -
Trigger Event:
push
-
Statement type:
File details
Details for the file autopil-0.1.2-py3-none-any.whl.
File metadata
- Download URL: autopil-0.1.2-py3-none-any.whl
- Upload date:
- Size: 125.8 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 |
e25332ca1a915a7d2232817185b7cb761b00a4ccc912311493f710e3e3120652
|
|
| MD5 |
f185ed1fbde79fb79a7c7d064143de16
|
|
| BLAKE2b-256 |
00b482e161579dceab93ec05fe9cc6fca8169439ade39a0dd385c63264b4d5c4
|
Provenance
The following attestation bundles were made for autopil-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on anil-solleti/autopil
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
autopil-0.1.2-py3-none-any.whl -
Subject digest:
e25332ca1a915a7d2232817185b7cb761b00a4ccc912311493f710e3e3120652 - Sigstore transparency entry: 1203740132
- Sigstore integration time:
-
Permalink:
anil-solleti/autopil@e4844edf3fc2f5e500282e79cbd10d5059d6a410 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/anil-solleti
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e4844edf3fc2f5e500282e79cbd10d5059d6a410 -
Trigger Event:
push
-
Statement type: