Deterministic Authority for AI Agents: Secure the "Confused Deputy" with your existing Identity stack.
predicate-authority is a production-grade pre-execution authority layer that binds AI agent identity to deterministic state. It bridges standard IdPs (Entra ID, Okta, OIDC) with runtime verification so every sensitive action is authorized, bounded, and provable.
Most agent security fails because it relies on static API keys or broad permissions. Predicate introduces short-lived mandates that are cryptographically tied to:
state_hash(what state the agent is in),intent_hash(what action it intends to perform),- policy constraints and required verification labels.
This closes the confused-deputy gap where an agent can misuse delegated credentials.
- Bridge, don't replace: leverage existing enterprise identity and governance.
- Fail-closed by design: deny before execution when state/intent/policy checks fail.
- Deterministic binding: authority is tied to runtime evidence, not only identity.
- Provable controls: each decision can emit signed proof events for audit pipelines.
You should still use Entra/Okta/OIDC for identity and token issuance. predicate-authority adds the runtime control layer those systems do not provide by default for AI agents:
- pre-execution allow/deny checks right before each sensitive action,
- binding authority to current
state_hashandintent_hash, - optional required verification labels from runtime checks (currently web-agent only via predicate-sdk integration),
- fail-closed local enforcement and per-decision proof events.
In practice: IdP answers who the principal is, while predicate-authority answers whether this exact action is allowed right now in this state.
| Package | Purpose |
|---|---|
predicate_contracts |
Shared typed contracts and protocols (ActionRequest, PolicyRule, evidence, decision/proof models). |
predicate_authority |
Runtime authorization engine (PolicyEngine, ActionGuard, mandate signing, proof ledger, telemetry emitter). |
examples/ |
Browser/MCP/HTTP/sidecar examples for local and connected workflows. |
Implemented in this repository:
- local pre-execution
ActionGuard.authorize(...)andenforce(...), - signed local mandates with TTL (
LocalMandateSigner), - policy evaluation with deny precedence and required verification labels,
- typed predicate-sdk integration adapter (
predicate_authority.integrations), - OpenTelemetry-compatible trace emitter (
OpenTelemetryTraceEmitter), - pytest coverage for authorization, mandate, integration, and telemetry flows.
This SDK requires the Predicate Authority Sidecar daemon to be running. The sidecar is a lightweight Rust binary that handles policy evaluation and mandate signing.
| Resource | Link |
|---|---|
| Sidecar Repository | rust-predicate-authorityd |
| Download Binaries | Latest Releases |
| License | MIT / Apache 2.0 |
Option A: Install with sidecar (recommended)
# Install SDK with automatic sidecar download
pip install predicate-authority[sidecar]
# The sidecar binary is downloaded automatically on first use
# Or manually trigger download:
predicate-download-sidecarOption B: Manual download
# Download the latest release for your platform
# Linux x64, macOS x64/ARM64, Windows x64 available
# Extract and run
tar -xzf predicate-authorityd-*.tar.gz
chmod +x predicate-authorityd
# Start with a policy file (local mode)
./predicate-authorityd run --port 8787 --mode local_only --policy-file policy.jsonfrom predicate_authority import run_sidecar, is_sidecar_available, download_sidecar
# Download if not available
if not is_sidecar_available():
download_sidecar()
# Run sidecar as subprocess
process = run_sidecar(port=8787, policy_file="policy.json")
# Later: graceful shutdown
process.terminate()
process.wait()pip install predicate-authority
# Or with sidecar binary:
pip install predicate-authority[sidecar]For local editable development in this monorepo, install both package roots
(do not use pip install -e . at repo root):
make dev-install
# equivalent: python -m pip install -e predicate_contracts -e predicate_authorityRelease note: publish is supported by pushing a synchronized git tag vX.Y.Z
(see docs/pypi-release-guide.md).
For shared contracts directly:
pip install predicate-contractsfrom predicate_authority import ActionGuard, InMemoryProofLedger, LocalMandateSigner, PolicyEngine
from predicate_contracts import (
ActionRequest,
ActionSpec,
PolicyEffect,
PolicyRule,
PrincipalRef,
StateEvidence,
VerificationEvidence,
)
guard = ActionGuard(
policy_engine=PolicyEngine(
rules=(
PolicyRule(
name="allow-payment-submit",
effect=PolicyEffect.ALLOW,
principals=("agent:payments",),
actions=("http.post",),
resources=("https://finance.example.com/transfers",),
),
)
),
mandate_signer=LocalMandateSigner(secret_key="dev-secret"),
proof_ledger=InMemoryProofLedger(),
)
request = ActionRequest(
principal=PrincipalRef(principal_id="agent:payments"),
action_spec=ActionSpec(
action="http.post",
resource="https://finance.example.com/transfers",
intent="submit transfer request #1234",
),
state_evidence=StateEvidence(source="backend", state_hash="state-hash-abc"),
verification_evidence=VerificationEvidence(),
)
decision = guard.authorize(request)
if not decision.allowed:
raise RuntimeError(f"Authority denied: {decision.reason.value}")See runnable examples in:
examples/browser_guard_example.pyexamples/mcp_tool_guard_example.pyexamples/outbound_http_guard_example.py
set -a && source .env && set +a
python examples/delegation/entra_obo_compat_demo.py \
--tenant-id "$ENTRA_TENANT_ID" \
--client-id "$ENTRA_CLIENT_ID" \
--client-secret "$ENTRA_CLIENT_SECRET" \
--scope "$ENTRA_SCOPE"set -a && source .env && set +a
python examples/delegation/oidc_compat_demo.py \
--issuer "$OIDC_ISSUER" \
--client-id "$OIDC_CLIENT_ID" \
--client-secret "$OIDC_CLIENT_SECRET" \
--audience "$OIDC_AUDIENCE" \
--scope "${OIDC_SCOPE:-authority:check}"For development or air-gapped environments without external IdP:
export LOCAL_IDP_SIGNING_KEY="replace-with-strong-secret"
./predicate-authorityd run \
--host 127.0.0.1 \
--port 8787 \
--mode local_only \
--policy-file policy.json \
--identity-mode local-idp \
--local-idp-issuer "http://localhost/predicate-local-idp" \
--local-idp-audience "api://predicate-authority"Connect the sidecar to Predicate Authority control-plane for policy sync, revocation push, and audit forwarding:
export PREDICATE_API_KEY="your-api-key"
./predicate-authorityd run \
--host 127.0.0.1 \
--port 8787 \
--mode cloud_connected \
--control-plane-url https://api.predicatesystems.dev \
--tenant-id your-tenant \
--project-id your-project \
--predicate-api-key $PREDICATE_API_KEY \
--sync-enabled- Sidecar operations guide:
docs/authorityd-operations.md - User manual (sync/integrity/operator behaviors):
docs/predicate-authority-user-manual.md - Control-plane production hardening runbook:
../predicate-authority-control-plane/docs/production-hardening-runbook.md
curl http://127.0.0.1:8787/health
curl http://127.0.0.1:8787/statuscurl -X POST http://127.0.0.1:8787/policy/reloadcurl -X POST http://127.0.0.1:8787/revoke/principal -d '{"principal_id": "agent:orders-01"}'
curl -X POST http://127.0.0.1:8787/revoke/intent -d '{"intent_hash": "<intent_hash>"}'--identity-mode local: deterministic local bridge (default).--identity-mode local-idp: local IdP-style signed token mode for dev/air-gapped workflows.--identity-mode oidc: enterprise OIDC bridge mode.--identity-mode entra: Microsoft Entra bridge mode.
POST /v1/authorize- Core authorization endpointGET /health- Health checkGET /status- Detailed status with metricsPOST /policy/reload- Hot-reload policyPOST /revoke/principal- Revoke by principalPOST /revoke/intent- Revoke by intent hashPOST /revoke/mandate- Revoke by mandate ID
predicate-authority supports fail-closed checks, local proof emission, and sidecar-managed revocation/token lifecycle for long-running agents.
- CI workflow:
.github/workflows/phase1-ci-and-release.yml - Release guide:
docs/pypi-release-guide.md
Publish order is always:
predicate-contractspredicate-authority
Dual-licensed under MIT and Apache 2.0:
LICENSE-MITLICENSE-APACHE
Copyright (c) 2026 Predicate Systems Inc.