Kernel Documentation
Kernel is a decision enforcement SDK for autonomous AI agents. Your agent calls Kernel before every consequential action. Kernel returns a verdict (ALLOW, REQUIRE_HUMAN, DENY) so your agent knows whether to proceed. Your credentials and downstream calls never leave your infrastructure.
What problem does it solve?
When you give an AI agent access to tools (payment APIs, databases, messaging services), you lose control of what it does and when it does it. An agent could:
- Send a refund 10x larger than intended
- Leak sensitive customer data in a request payload
- Spiral into a loop and exhaust your API budget
- Be manipulated via a prompt injection to execute dangerous commands
- Access a database and silently read personal user data it was never supposed to see
Kernel runs as a decision enforcement layer inside your agent's runtime. Before any consequential action, your agent calls Kernel. Kernel evaluates the action against your rules and returns a verdict. ALLOW means your agent proceeds. REQUIRE_HUMAN pauses execution and routes the action to a human supervisor. DENY blocks the action. Your credentials and downstream calls never leave your infrastructure: the agent makes the actual API call, Kernel only decides whether the agent is allowed to make it.
How it works, the 30-second version
Your Agent (running in your infrastructure)
│
│ Kernel.check(action, context)
▼
┌─────────────────────────────────────────────────────┐
│ Kernel Decision Engine │
│ │
│ 1. Is the payload safe? (Guardrails) │
│ (no secrets, no PII, no injections) │
│ │
│ 2. Are the limits respected? (Control Groups) │
│ (spend cap, rate limits, error budget) │
│ │
│ 3. Is this action allowed? (Policy Engine) │
│ (business rules, HITL escalation) │
│ │
│ Returns: ALLOW / REQUIRE_HUMAN / DENY │
└─────────────────────────────────────────────────────┘
│
│ verdict
▼
Your Agent
│
│ ALLOW → execute the action with your credentials
│ REQUIRE_HUMAN → wait for supervisor decision
│ DENY → abort, log the denial
▼
Stripe / Postgres / Slack / any API
(called by your agent, with your credentials)
Every layer must pass. If any one of them rejects the request, Kernel returns a non-ALLOW verdict and an audit entry is created automatically.
Quick Start
1. Run the Kernel decision engine
The decision engine starts on port 8080. The supervisor dashboard is at http://localhost:8080/dashboard/.
2. Register your business
3. Log in and get your JWT
Save the token from the response. You will use it as Authorization: Bearer <token> for all management API calls.
4. Set up your governance stack
Governance is a three-piece stack: Guardrail, Control Group, Policy. Think of them as nested layers of rules, from most fundamental to most specific.
Step 4a, Create a Guardrail (security scanners)
The response will contain a
guardrail_id. Save it.
Step 4b, Create a Control Group (budget & rate limits)
The response will contain a
control_id. Save it.
Step 4c, Create a Policy (business rules)
You write the policy in YAML. Kernel compiles it automatically. You do not need to know how policies work under the hood.
Tip: Instead of writing policies from scratch, you can start from a Blueprint and just fill in the values that matter for your use case.
5. Register an agent
The response contains an
api_key. This is the agent's credential to call Kernel. Store it securely, it will not be shown again.
6. Attach the policy to the agent
An agent without an attached policy is always denied. This is intentional: deny-by-default.
7. Your agent asks Kernel before each action
From your agent code, call the Kernel SDK (or its HTTP endpoint directly) before executing any consequential action. Kernel returns a verdict. Your agent acts on it.
The
targetfield is policy context (which downstream the agent intends to call), not a routing instruction. Kernel does not call Stripe. Your agent does.
Verdict, ALLOW (amount < 50 EUR):
Your agent now calls Stripe with its own credentials and processes the refund.
Verdict, REQUIRE_HUMAN (amount >= 50 EUR):
Your agent polls GET /v1/approvals/apr_789 until the supervisor approves or rejects in the dashboard. On approval, your agent proceeds with the Stripe call.
Verdict, DENY:
Your agent aborts the action and logs the denial.
Core Concepts
Agents
An agent is any autonomous process (an LLM, a script, a workflow runner) that needs to call APIs on your behalf.
Each agent has:
- A unique ID and name
- An API key used to authenticate calls to Kernel (
ok_live_<tenant>_<agent>_<random>) - An attached Policy that governs what it can do
Agents are tenant-scoped. They belong to your business account and are invisible to other tenants.
Sessions & Intent
Before an agent executes actions, it declares what it intends to do. This is called a session intent.
Available intents:
| Intent | What it allows | Risk level |
|---|---|---|
financial | Refunds, charges, transfers, payments | High |
data_access | Queries, record reads, data exports | Medium |
communication | Emails, SMS, Slack messages | Medium |
infrastructure | Deployments, scaling, log access | High |
code | Pull requests, issues, CI pipelines | Low |
Intent drift detection: If an agent with intent financial asks Kernel about a deploy action (which belongs to infrastructure), Kernel returns DENY immediately and logs an intent_drift event. The agent cannot stray outside its declared purpose for that session.
Policies & Rules
A Policy is a named set of rules that governs what an agent can do.
You write policies in YAML. Kernel reads them and compiles them automatically into an internal policy format that the engine understands. You express what you want in plain terms; the system handles the technical translation.
Rules produce one of three verdicts:
| Verdict | Meaning | What your agent does |
|---|---|---|
ALLOW | Automatically approved | Execute the action immediately |
REQUIRE_HUMAN | Needs a supervisor | Pause; poll the approval ID; execute after approval |
DENY | Forbidden | Abort the action; log the denial |
If no rule matches an action, the default verdict is DENY. Kernel is deny-by-default. The wildcard "*" rule is a common explicit catch-all.
Policy Blueprints
Writing a policy from scratch requires knowing which actions to allow, which to escalate, and which to block, and getting it wrong has consequences.
Blueprints are pre-built policy templates for the most common governance scenarios. You pick the one that matches your use case and only fill in the values that are specific to your team: thresholds, limits, and any custom rules you want to add.
What makes Blueprints different from regular policies:
- They ship with safe defaults already filled in. The most conservative settings come pre-configured.
- You can modify any value without needing to understand how the policy engine works internally.
- You can add or remove rules to match your exact business logic.
- Once you instantiate a Blueprint into a policy, it is yours. The original template does not affect your live policy.
Planned blueprint library (shapes not yet finalised):
| Blueprint | Best for | What comes pre-configured |
|---|---|---|
financial-standard | Payment and refund agents | Auto-approve below a threshold, HITL above, block bulk ops |
data-read-only | Reporting and analytics agents | Allow reads, block all writes and deletes |
communication-safe | Messaging agents | Allow single sends, block mass messaging |
infra-observer | Monitoring agents | Allow metrics and log reads, block deploys and restarts |
zero-trust | Starting fresh | Block everything. Unlock actions one by one |
Status: Blueprint templates are planned. The policy compilation pipeline is already production-ready. Blueprints will use the same engine, just with a starting template.
Guardrails, Layer 1: Security
Guardrails run first, before the policy engine. They scan every action's payload for dangerous content. If anything is found, Kernel returns DENY immediately. The policy rules are never even evaluated.
| Scanner | What it catches | Hard block? |
|---|---|---|
| PII | Social security numbers, credit card numbers, email addresses in params | Yes |
| Secrets | Stripe keys, AWS keys, bearer tokens, RSA private keys | Yes |
| Injection | Prompt injection phrases ("ignore previous instructions"), jailbreak patterns | Yes |
| CodeGuard | import os, exec(), system() and similar patterns | Yes |
| Exfiltration | Requests targeting domains outside your allowlist | Yes |
Example, what gets denied:
Control Groups, Layer 2: Economics
Control Groups run after Guardrails and before the Policy engine. They enforce quantitative limits so that even a correctly-behaving agent cannot exceed what you have budgeted for it.
| Governor | What it enforces |
|---|---|
| Quota | Max number of actions per time window (e.g. 500 actions/hour) |
| Budget | Maximum spend in a period (e.g. 1,000 EUR/month) |
| Circuit Breaker | Suspends an agent that errors repeatedly (e.g. 5 errors in 60s, 5 min cooldown) |
The Circuit Breaker works like an electrical fuse: if an agent causes too many errors in a short window, Kernel suspends it for a cooldown period. This prevents runaway loops from damaging your data or exhausting your budget.
Human-in-the-Loop (HITL)
When a policy rule returns REQUIRE_HUMAN, Kernel does not return ALLOW. Instead, it returns an approval_id and creates a pending approval in the supervisor dashboard immediately.
The supervisor can:
- Approve: a one-time execution token is issued; your agent proceeds with the action
- Reject: the action is permanently denied with an optional reason
Agent-side polling:
Every HITL decision is logged in the audit trail with the approver's email and a decision_source: "manual" marker.
Sensitive Data Encryption
When an agent queries a database for sensitive user data (personal information, health records, financial details), a risk exists even when the agent is behaving correctly: the agent reads the data, which means it could log it, leak it, or be manipulated into disclosing it.
Kernel can keep this data unreadable to the agent end-to-end. The agent retrieves the encrypted record, forwards it to the end user, but never has the ability to read what is inside.
How it works
Database Your Agent End User
│ │ │
│ encrypted │ │
│ record + DEK │ │
│ ───────────────► │ │
│ │ forwards blob │
│ │ (cannot decrypt) │
│ │ ───────────────────► │
│ │ │ decrypts
│ │ │ with private key
The agent at no point holds the decryption key. Even if the agent's code or memory is compromised, an attacker cannot read the data: they only get an encrypted blob.
The encryption scheme
The design uses asymmetric envelope encryption, the same pattern behind AWS KMS, PGP, and the age tool.
Storing data (at rest):
- Each sensitive record is encrypted with a random Data Encryption Key (DEK) using AES-256-GCM.
- The DEK is then encrypted with the end user's public key (RSA or X25519) and stored alongside the ciphertext.
- A cryptographic salt (random, unique per record) is stored with the record. Used during key derivation to prevent precomputed attacks.
Retrieving data (agent request):
- The agent fetches the encrypted record and the encrypted DEK from the database.
- The agent receives:
{ ciphertext, encrypted_dek, salt, key_id }. - The agent forwards this bundle to the end user without reading it.
- The end user decrypts the DEK with their private key, then decrypts the record with the DEK.
Why key-pairs and salt?
| Choice | Why |
|---|---|
| Asymmetric key-pair (RSA-OAEP or X25519) | Only the user with the private key can decrypt. The agent, the database server, and Kernel itself are all excluded. |
| Per-record DEK (AES-256-GCM) | If one DEK is ever compromised, only that one record is exposed, not the whole dataset. |
| Salt + Argon2id for key derivation | If a key is derived from a user's passphrase, the salt makes brute-forcing computationally infeasible. |
Status: Encryption scheme is designed. Implementation is planned and will be activated via a per-agent policy flag (
encrypt_sensitive_responses: true).
API Reference
Authentication
| Route | Who uses it | Credential |
|---|---|---|
All /v1/* routes | Agents (or the SDK) | Authorization: Bearer <api-key> or X-Agent-Key: <api-key> |
All /api/* routes | Dashboard / humans | Authorization: Bearer <jwt> |
Agent Endpoints
POST /v1/agent-action, Verdict endpoint
The recommended way for agents to request a verdict before executing an action. Runs all enforcement layers in a single call and returns ALLOW, REQUIRE_HUMAN, or DENY.
Request headers:
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Agent API key |
X-Session-Intent | Yes | Intent category (financial, data_access, etc.) |
X-Session-Id | No | Reuse an existing session across multiple calls |
Request body:
Response status codes:
| Code | Verdict | Description |
|---|---|---|
200 | ALLOW | Agent may proceed with the action |
202 | REQUIRE_HUMAN | Awaiting human supervisor; agent should poll the approval_id |
403 | DENY | Policy denial or guardrail block; agent must abort |
401 | (none) | Invalid or missing API key |
503 | (none) | Circuit breaker is open for this agent |
POST /v1/sessions, Create a session
POST /v1/sessions
Authorization: Bearer <agent-api-key>
{ "intent": "financial" }
Returns a session_id valid for 60 minutes. Pass it as X-Session-Id in subsequent /v1/agent-action calls to preserve the intent context across multiple actions.
GET /v1/approvals/{id}, Poll approval status
GET /v1/approvals/apr_abc123
Returns the current status of a pending HITL approval: pending, approved, denied, or expired.
Management Endpoints (require JWT)
| Method | Path | Description |
|---|---|---|
POST/GET | /api/agents | Register an agent / list all agents |
POST | /api/agents/{id}/policies | Attach a policy to an agent |
POST/GET | /api/policies | Create / list policies |
GET | /api/policies/raw | View compiled policy YAML for all agents |
POST | /api/guardrails | Create a guardrail set |
POST | /api/controls | Create a control group |
GET | /api/approvals | List pending HITL approvals |
POST | /api/approvals/decision | Approve or reject a pending approval |
GET | /api/audit | Full audit log for your tenant |
GET | /api/telemetry/kpis?days=N | Allow / deny / blocked / human counts |
GET | /api/telemetry/volume?days=N | Decision volume over time |
GET | /api/circuit/status | Circuit breaker states per agent |
POST | /api/circuit/reset?id=<agent-id> | Reset a tripped circuit |
GET | /api/events | Real-time SSE audit stream |
GET | /health | Liveness check |
Audit Log
Every decision (ALLOW, REQUIRE_HUMAN, DENY) produces an immutable audit entry. Compliance references are attached automatically.
Audit entry fields
| Field | Type | Description |
|---|---|---|
id | string | Unique event UUID |
timestamp | ISO 8601 | When the event occurred |
event | string | Event type (see below) |
agent_id | string | Which agent triggered the event |
customer_id | string | Your tenant ID |
chain_id | string | Groups all events from one request chain |
action | string | The action that was attempted |
amount | number | Financial amount, if applicable |
reasoning_trace | string | Agent's chain-of-thought (if provided) |
decision_source | string | "kernel" (automated) or "manual" (human) |
approver | string | Email of the human supervisor (if manual) |
references | array | OWASP / EU AI Act compliance references |
tags | array | Custom labels (editable via dashboard) |
Event types
| Event | When it fires |
|---|---|
decision_allow | Verdict ALLOW returned to agent |
decision_deny | Verdict DENY returned to agent |
escalated | Verdict REQUIRE_HUMAN; awaiting supervisor |
approved | Human supervisor approved the action |
rejected | Human supervisor rejected the action |
blocked | Guardrail hard-blocked the action (returned DENY) |
secret_blocked | A credential was detected in parameters |
pii_detected | PII was detected in parameters |
intent_drift | Action fell outside the declared session intent |
circuit_trip | Circuit breaker opened due to repeated errors |
anomaly_detected | Secondary signal raised alongside another event |
agent_registered | A new agent was created |
policy_attached | A policy was linked to an agent |
Real-time stream
Connect to GET /api/events (SSE) to receive audit events as they happen:
Compliance
Kernel maps enforcement events to recognised compliance frameworks automatically. Each audit entry is annotated with the relevant references.
| Standard | What it covers | Enforced by |
|---|---|---|
| OWASP LLM01, Prompt Injection | Unauthorised instruction overrides | Injection scanner (Layer 1) |
| OWASP LLM02, Sensitive Info Disclosure | Credentials, PII, and encrypted data handling | Secrets + PII scanners + Encryption layer |
| OWASP LLM04, Denial of Service | Resource exhaustion and loops | Circuit breaker (Layer 2) |
| OWASP LLM06, Excessive Agency | Actions outside authorised scope | Policy rules + intent drift (Layer 3) |
| EU AI Act Art. 10 | Data governance for high-risk AI | PII controls + encryption |
| EU AI Act Art. 14 | Human oversight of high-risk AI | HITL escalation flow |
Common Patterns
Pattern 1, Tiered financial approvals
Refunds under 50 EUR are instant. Anything above requires a supervisor.
Pattern 2, Read-only agent
The wildcard "*" catch-all ensures any action not explicitly listed is denied.
Pattern 3, Sensitive data retrieval (encrypted response)
When an agent fetches user records that contain PII, enable the encryption flag so the agent cannot read the response:
The end user decrypts the response with their private key. The agent and the audit trail never contain the plaintext. (flag planned, see Sensitive Data Encryption)
Pattern 4, Orchestrator to Sub-agent chain
When a supervisor agent delegates to a sub-agent, pass the calling context so the full chain appears in the audit trail:
All events share the same chain_id, making it easy to trace multi-agent execution end-to-end.
Environment Variables
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string |
PORT | No | Server port (default: 8080) |
DASHBOARD_DIST_PATH | No | Path to compiled dashboard static files |
VAULT_MASTER_KEY | No | 32-byte AES-GCM master key |
Deployment
Docker Compose
Manual
Health check
GET /health → 200 OK
Kernel, deterministic decision enforcement for autonomous AI agents.