How permit0-ai/permit0-core works
1. Overall shape
- Permit0 is a Rust workspace centered on a policy engine that sits between AI agent tool calls and the real side effects they would trigger.
- The repo is split into a small number of clear planes: decision engine, pack DSL and taxonomy, state/audit storage, UI/API, CLI/hook tooling, and language/integration adapters.
2. Core runtime: permit0-engine
- This is the main execution path for policy decisions.
- It takes a normalized action plus context, runs the decision pipeline, applies policy/cache checks, risk evaluation, session amplification, and routing to allow/deny/human review.
- The engine is the boundary where deterministic policy enforcement happens; everything else feeds it or consumes its outputs.
3. Action vocabulary and normalization: permit0-types, permit0-dsl, permit0-normalize
- permit0-types defines the canonical taxonomy, normalized action model, permissions, risks, and tool-call types.
- permit0-dsl owns the YAML pack model, validation, loading, normalization evaluation, and risk rule execution.
- permit0-normalize provides reusable normalization primitives such as aliases, registries, fallbacks, and context-aware helpers.
- Architecturally, this is the “translation layer” that maps vendor/tool-specific calls into Permit0’s canonical action space.
4. Packs as policy content: packs/permit0/email
- Packs are the repo’s policy content format: YAML normalizers, risk rules, lockfiles, and tests.
- The shipped email pack is the reference implementation, covering Gmail and Outlook surfaces.
- Packs are what make the engine extensible without changing core code; the engine consumes packs, while the pack directory defines the supported action boundaries.
5. Scoring and session-aware decisions: permit0-scoring and permit0-session
- permit0-scoring computes risk based on taxonomy dimensions and configured amplifiers, producing the numeric score and tier routing used by the engine.
- permit0-session tracks multi-call behavior, maintains per-session context, and applies amplification/block rules when repeated actions increase risk.
- These crates represent the “decision intelligence” layer: the engine is not just matching rules, it is combining action semantics with session state.
6. State and persistence: permit0-store
- This crate owns durable state for both policy decisions/caches and audit logging.
- It supports multiple backends: SQLite and PostgreSQL for state, plus several audit sinks including SQLite, Postgres, stdout, memory, and OpenTelemetry.
- The audit subsystem includes digest chaining, signing, redaction, teeing, and export, which makes the audit trail a first-class subsystem rather than an afterthought.
7. Human-in-the-loop and review workflows: permit0-ui
- The UI is the operator surface for approvals, pack browsing, and dashboard-style review.
- It includes server routes, approval handling, pack routes, and authentication with OIDC/session support.
- This is where human review decisions are made when the engine routes an action above the allow threshold or when unknown actions are blocked.
8. Command-line entrypoints and host integration: permit0-cli, hooks, and gateway
- permit0-cli provides operational commands such as serve, check, calibrate, digest, audit, pack, gateway, and hook.
- The hook path is the critical integration boundary for agent hosts like Claude Code: it intercepts pre-tool execution, consults the daemon, and returns the enforcement verdict.
- The gateway path is the broader service boundary for non-hook integrations or remote enforcement setups.
9. Language bindings and external agent integrations
- permit0-node and permit0-py expose the core functionality to JavaScript/TypeScript and Python consumers.
- integrations/permit0-openclaw is a concrete adapter that wraps OpenClaw execution through Permit0’s decision flow.
- These adapters sit outside the core policy engine, but they are important architectural boundaries because they are the entrypoints from different agent runtimes.
10. Testing and calibration data
- corpora/calibration contains real-world policy calibration cases for Gmail and Outlook actions.
- The repository also includes crate-level tests, pack integration tests, CLI snapshots, and integration tests for the Node/Python bindings.
- This indicates the system is designed around repeatable policy calibration and regression safety, not just unit-level correctness.
11. Deployment and infrastructure
- The repo is designed to run in Docker and can compose an engine + dashboard stack alongside external MCP servers.
- It uses Rust 1.85+, SQLite by default, PostgreSQL when deployed centrally, and OpenTelemetry for audit/export integration.
- OIDC appears in the UI as the identity boundary for operators; the hook config determines whether human review is handled in the UI or returned to the caller.
12. End-to-end data flow
- A tool call originates in an agent host, passes through the hook or gateway, gets normalized by a pack into a canonical action, then is scored and routed by the engine.
- The decision is cached and written to audit/state storage; if needed, it is surfaced to the UI for human approval.
- The result flows back to the caller as allow/deny/escalate, while the signed audit chain preserves a verifiable record of what happened.
Main entry points: permit0-engine Engine · permit0-dsl DSL · permit0-store Store · permit0-cli CLI
Components 17
Core policy
Canonical types, normalization, policy evaluation, scoring, session state, and persistence.
- Engine · Main decision pipeline that evaluates normalized actions and routes allow, deny, or human review.
crates/permit0-engine - Types · Canonical action model, permissions, risks, and tool-call vocabulary.
crates/permit0-types - DSL · Pack schema, loading, validation, normalization evaluation, and risk-rule execution.
crates/permit0-dsl - Normalize · Reusable normalization primitives such as aliases, registries, fallbacks, and context helpers.
crates/permit0-normalize - Scoring · Converts taxonomy and amplifiers into numeric risk scores and routing tiers.
crates/permit0-scoring - Session · Tracks multi-call context and applies amplification or block rules across a session.
crates/permit0-session - Store · Persistent policy state, decision cache, and audit chain with multiple storage and sink backends.
crates/permit0-store
Policy content
Packs and calibration corpora that define and validate policy behavior.
- Email pack · Reference policy pack for Gmail and Outlook normalizers, risk rules, and lockfile.
packs/permit0/email - Calibration · Real-world calibration cases used to tune and regress policy decisions.
corpora/calibration
Interfaces
Operator UI, CLI entrypoints, and language-facing client crates.
- UI · Operator dashboard for approvals, pack browsing, authentication, and review workflows.
crates/permit0-ui - CLI · Operational commands for serving, checking, calibrating, digesting, auditing, packaging, gateway, and hooks.
crates/permit0-cli - Agent client · Client-side helper for talking to Permit0 and presenting reviewer flows.
crates/permit0-agent - Node binding · JavaScript/TypeScript binding around the core policy flow.
crates/permit0-node - Python binding · Python binding around the core policy flow.
crates/permit0-py
Integrations
External adapters and host-facing execution boundaries.
- OpenClaw · TypeScript adapter that routes OpenClaw execution through Permit0 decisions.
integrations/permit0-openclaw
Ops and auth
Supporting authentication, tokens, and shell dispatch for host integration.
- Shell dispatch · Shell command parsing and YAML-based dispatch used by host hooks.
crates/permit0-shell-dispatch - Token · Token/provider utilities for secure client and service access.
crates/permit0-token
Connections 25
- CLI → Engine: serves · CLI launches or drives the policy engine for local and daemon modes.
- CLI → Shell dispatch: hook path · CLI hook mode uses shell dispatch to intercept tool execution.
- CLI → Store: manages · CLI commands operate on policy state, digests, and audits.
- CLI → DSL: packs · CLI exposes pack inspection, validation, and calibration flows.
- Engine → Types: uses · Engine consumes the canonical taxonomy and normalized action model.
- Engine → DSL: evaluates · Engine loads and executes pack-defined policy content.
- Engine → Normalize: normalizes · Engine depends on reusable normalization primitives.
- Engine → Scoring: scores · Engine computes routing risk from taxonomy and amplifiers.
- Engine → Session: tracks · Engine applies session-aware amplification and block logic.
- Engine → Store: persists · Engine writes and reads cached decisions and audit state.
- DSL → Types: models · DSL schemas and loaders are built around the canonical action types.
- DSL → Normalize: applies · Pack normalization uses shared normalization helpers and registries.
- DSL → Email pack: loads · DSL is the runtime for pack content such as the email reference pack.
- DSL → Calibration: validates · Calibration cases exercise pack behavior and decision boundaries.
- Scoring → Types: interprets · Scoring maps taxonomy dimensions into numeric risk outcomes.
- Session → Store: stores · Session state relies on durable backing storage.
- Store → UI: feeds · UI reads decision and audit data for review and operations.
- Store → Engine: serves state · Policy cache and audit lookups support engine decisions.
- UI → Token: authenticates · UI uses token and identity plumbing for operator access.
- UI → Store: reviews · UI surfaces approvals, state, and audit history.
- Agent client → UI: reviews · Agent helper connects callers into review and approval flows.
- Node binding → Engine: wraps · Node binding exposes core decisions to JS/TS consumers.
- Python binding → Engine: wraps · Python binding exposes core decisions to Python consumers.
- OpenClaw → Engine: enforces · OpenClaw adapter routes execution through Permit0 policy decisions.
- Shell dispatch → Engine: consults · Hook dispatch consults the policy engine before side effects occur.