Expand description
PPE is a policy enforcement runtime for AI agents.
It is a deterministic reference monitor between an agent and every capability it invokes: tools, prompts, resources, inference providers, and A2A methods. Each operation runs through a policy-defined pipeline that can resolve identity, make an authorization decision (delegated to an engine like Cedar or CEL), exchange and reduce credentials before a downstream call, redact inputs and outputs, track information flow across calls, and audit. You write that policy declaratively in APL, the configuration that defines each operation’s pipeline; PPE evaluates and enforces it at the boundary, against state the model cannot observe or forge.
- Source and issues: https://github.com/praxis-proxy/policy
§This crate
praxis-policy is the host facade: one dependency that re-exports the PPE
runtime (praxis-policy-core, praxis-policy-apl-core, praxis-policy-apl-cmf, praxis-policy-apl-runtime), so a host depends
on this crate instead of pinning each of them separately.
By default it is the engine only: no builtin plugins are compiled in. The bundled plugins, PDPs and session stores are registered from here, each behind a feature, and only what you enable is compiled.
§Usage
Engine only (register your own factories):
use std::sync::Arc;
use praxis_policy::PolicyEngine;
let mgr = Arc::new(PolicyEngine::default());
// ... register host factories, then `praxis_policy_apl_runtime::register_apl(&mgr, opts)`.With the bundled builtins (enable the builtins feature):
use std::sync::Arc;
use praxis_policy::PolicyEngine;
let mgr = Arc::new(PolicyEngine::default());
// Register every enabled builtin factory and install the APL config
// visitor (in-process defaults) in one call:
praxis_policy::install_builtins(&mgr);
// ... then load a config that references the enabled `kind`s.§Features
No plugins are on by default (praxis-policy alone is the engine).
builtins enables every bundled extension, including the Valkey session
store; or pick a granular subset (jwt, oauth, elicitation-ciba,
cedar, cel, opa, valkey). Any of them brings in the registration
helpers, and each one re-exports its own concrete factory type here.
§Plugins the host supplies
A plugin does not have to be bundled. Implement PluginFactory and hand it
to PolicyEngine::register_factory under the kind: your YAML names;
prelude is the surface to write it against. An unrecognised kind is a
load-time error, so a missing registration fails at startup rather than
silently skipping the plugin.
reference/plugins/ in this repository holds two worked examples, a PII
scanner and an audit logger. Neither is published or bundled; a host registers
them.
Re-exports§
pub use praxis_policy_apl_cmf;pub use praxis_policy_apl_core;pub use praxis_policy_apl_runtime;pub use praxis_policy_core;
Modules§
- prelude
- Curated re-exports for plugin authors, so a plugin crate can depend on this
facade alone. See
praxis_policy_core::prelude. Curated re-exports for plugin authors. Curated surface for plugin authors.
Structs§
- AplOptions
- Configuration for
register_apl. All runtime collaborators APL needs to do its work are funneled through here so the call site reads as a single block instead of a multi-step builder. - Cedar
Direct PdpFactory - Factory for
CedarDirectResolver. Reportskind() = "cedar-direct"; builds resolvers from the unified-config block viaCedarDirectResolver::from_config. - CelPdp
Factory - Factory for
CelResolver. Reportskind() = "cel"; builds resolvers from the unified-config block viaCelResolver::from_config. - Ciba
Approver Factory - Factory for
kind: elicitation/cibaplugins. Instantiates aCibaApproverfrom theconfig:block and registers it on theelicithook. - Dispatch
Cache - Host-owned dispatch cache. Construct once, share via
Arc<DispatchCache>across allCmfPluginInvoker::for_requestcalls so plans built for one request can be reused by the next. - JwtIdentity
Factory - Factory for
kind: identity/jwtplugins. Instantiates aJwtIdentityResolverfrom theconfig:block and registers it on theidentity.resolvehook. - Memory
Session Store - In-process
SessionStorebacked by aHashMapofHashSets. Suitable for tests, single-process deployments, and as the default when no distributed store is configured. Cloning the store viaArcshares state across all consumers. - OAuth
Delegator Factory - Factory for
kind: delegator/oauthplugins. Instantiates anOAuthDelegatorfrom theconfig:block and registers it on thetoken.delegatehook. - OpaPdp
Factory - Factory for
OpaResolver. Reportskind() = "opa"; builds resolvers from the unified-config block viaOpaResolver::from_config. - Plugin
Instance - The two types a host needs to accept a plugin it did not compile in:
PolicyEngine::register_factorytakes aBox<dyn PluginFactory>, andPluginInstanceis what that factory returns. - Policy
Engine - Owns registered plugins and dispatches hook invocations to them.
- Valkey
Config - Parsed
global.apl.session_storeconfig forkind: valkey. - Valkey
Session Store Factory - Factory the host registers via
AplOptions.session_store_factories.
Constants§
- CIBA_
KIND - The plugin
kind:string operators write in PPE YAML to declare a CIBA elicitation handler. - JWT_
KIND - The plugin
kind:string operators write in PPE YAML to declare a JWT identity resolver. - OAUTH_
KIND - The plugin
kind:string operators write in PPE YAML to declare an OAuth RFC 8693 token-exchange delegator. - VALKEY_
KIND - The
kind:discriminator this factory builds. Part of the public surface — it is the string operators write in their config.
Traits§
- PdpFactory
- Build a
PdpResolverfrom a unified-config block. Implemented per PDP backend (cedar-direct, opa, …) and registered with the praxis-policy-apl-runtime visitor so unified-config YAML can declare PDPs without the host pre-constructing them in code. - Plugin
Factory - The two types a host needs to accept a plugin it did not compile in:
PolicyEngine::register_factorytakes aBox<dyn PluginFactory>, andPluginInstanceis what that factory returns. - Session
Store - Pluggable session-state backend. Implementations must be
Send + Sync— the same store is shared across all concurrent requests. - Session
Store Factory - Factory the visitor consults when it encounters a
global.apl.session_storeblock in the unified config. Mirrorspraxis_policy_apl_core::step::PdpFactory: each factory advertises akind()string matching the YAML block’skind:field, andbuildturns the block into a live store. Registered up front viacrate::AplOptions::session_store_factories; the visitor selects the active store from config during its global-config walk, before any route handler captures the store.
Functions§
- builtin_
pdp_ factories - The enabled PDP factories, ready to drop into
AplOptions::pdp_factories. A route’scedar:,cel:oropa:step selects which one runs. - builtin_
session_ store_ factories - The enabled session-store factories, ready to drop into
AplOptions::session_store_factories. Aglobal.apl.session_store: { kind: ... }config block selects one; absent that, the in-processMemorySessionStoredefault stays active. - install_
builtins - Register every enabled plugin factory and install the APL config visitor on
mgrwith in-process defaults (aMemorySessionStoreand the default baseline capabilities). The enabled PDP and session-store factories are wired in, so a later config load can reference any of them bykind. - register_
apl - Build an
AplConfigVisitorfrom the supplied options and register it on the engine. Returns theArc<AplConfigVisitor>so the caller can stash it for later inspection (or callregister_pdpon it after the fact for late-bound resolvers) — but in the typical case the return value is dropped and the visitor lives inside the engine’s visitor list. - register_
builtin_ plugins - Register every enabled by-kind plugin factory on
mgr: identity (jwt), delegators (oauth), and elicitation approvers (elicitation-ciba). Call before loading a config so the engine can instantiate plugins whose YAMLkind:matches.