Skip to main content

openagent-control

The zero-config security, governance, and telemetry proxy for the autonomous AI workforce.

What it is

Autonomous agents typically run on static service accounts and hardcoded API keys. That forces a choice between over-privileged agents and brittle workflows, and leaves no cryptographically trustworthy record of what an agent actually did.

openagent-control sits between an agent and the tools it calls — today, MCP (tools/list / tools/call) — and enforces three things on every call:

  1. Identity — the agent is a workload with its own identity, not a shared secret.
  2. Policy — every tool call is evaluated against explicit policy (Open Policy Agent / Rego) before it reaches the target system; a scoped, short-lived credential is issued only on allow.
  3. Audit — every decision produces an Ed25519-signed, hash-chained receipt, so a compliance reviewer can prove after the fact what was authorized and executed.

See docs/design.md for the full design, docs/adr/ for the reasoning behind each decision — including what's a real implementation today versus a deliberate v1 stub — docs/roadmap.md for where the codebase stands against the phased enterprise rollout plan, and docs/user-journeys.md for how an agent developer, platform engineer, registry operator, or compliance reviewer actually uses it, and docs/deployment.md for installing and running it.

Status

Early foundation, not production-ready. In particular:

  • Identity defaults to a stub. OAC_IDENTITY_MODE=header (the default) trusts an X-Spiffe-ID header rather than performing real SPIFFE/SPIRE attestation — only safe behind a network boundary that has already authenticated the caller. OAC_IDENTITY_MODE=jwt-svid cryptographically validates a SPIFFE JWT-SVID bearer token (the shape SPIRE issues) but still needs an actual SPIRE deployment to be a full production path — see ADR-0005. OAC_IDENTITY_MODE=oidc-jwks validates a real access token from Okta or Microsoft Entra ID against its published JWKS — see ADR-0010.
  • Token exchange defaults to a stub, with real Okta-compatible (RFC 8693) and Microsoft Entra (OBO) adapters available via OAC_TOKEN_EXCHANGE_MODE — see ADR-0004.
  • The ledger's signing key defaults to in-process (regenerated on restart) unless you inject your own ReceiptSigner; there's no KMS/HSM adapter yet. Chain state itself, however, is durable and replica-safe once OAC_DATABASE_URL is set — see ADR-0003 and ADR-0009.
  • No Human-in-the-Loop approval flow, no sidecar/native-SDK deployment pattern, no cross-organization (DID/VC) identity yet — tracked in ADR-0001 and ADR-0007.

Architecture

Hexagonal (ports & adapters) — see ADR-0006.

src/openagent_control/
├── domain/          # pure models + Protocol ports — no I/O, no framework imports
├── application/       # GovernedExecutionService — the transport-agnostic use case
├── adapters/            # concrete implementations of each port (OPA, ledger, identity, db, ...)
└── gateway/               # FastAPI app: routes + dependency wiring, no policy/crypto logic
Port Default adapter Also available (settings-selected)
PolicyEngine Open Policy Agent (Rego), policies/mcp_authz.rego —
IdentityProvider header-trusting stub JWT-SVID validation, OIDC/JWKS (Okta, Entra ID)
AgentRegistry file (registry/agents.yaml, git-reviewed) Postgres (oac.agents), optionally Redis-cached
Ledger in-process Ed25519 hash-chained receipts Postgres-backed, replica-safe chain (oac.execution_receipts)
TokenExchange stub RFC 8693 (Okta-compatible), Microsoft Entra OBO — optionally Redis-cached to each token's own expiry
MCPUpstream MCP Streamable HTTP via the official MCP SDK (ADR-0011) plain JSON-RPC over HTTP, for non-MCP internal endpoints
AuditExporter stdout/log —

Install

pip install openagent-control                  # gateway + OPA
pip install 'openagent-control[persistence]'   # + Postgres / Redis support

openagent-control init ./oac                   # starter registry + policy
export OAC_REGISTRY_PATH=./oac/agents.yaml
openagent-control doctor                       # checks every dependency
openagent-control serve

Or with containers — docker compose up (gateway + OPA), --profile persistence for Postgres/Redis, --profile demo for the walkthrough stack. Full guide: docs/deployment.md.

With no registry configured the gateway starts and denies every agent — a fresh install trusts nothing until you register something.

Development

make install      # poetry install --all-extras
make quality      # black --check, ruff, mypy
make test         # pytest with coverage (95% gate)
make check        # quality + test
make up           # docker compose: gateway + OPA
make up-demo      # + demo IdP and governed MCP server
make doctor       # verify config and dependencies
make test-packaging  # build a wheel, install it clean, run it from elsewhere

Requires Python 3.11+ and Poetry. The integration tests additionally need the opa binary (brew install opa); without it they skip rather than substitute a fake policy engine.

Once running (make up), obtain an access token the way a real workload does — an OAuth 2.0 client-credentials grant — then send a governed tool call:

TOKEN=$(curl -s -X POST http://localhost:8090/oauth2/v1/token \
  -u finance-invoice-svc:scenario-only-not-a-real-secret \
  -d grant_type=client_credentials | jq -r .access_token)

curl -X POST http://localhost:8000/mcp/v1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"read_query","arguments":{"quarter":"Q3"}}}'

The upstream MCP server validates the short-lived credential the gateway brokers for it, so the same request sent directly to localhost:8080 is refused. See examples/enterprise_scenario/.

Persistence & caching (optional)

Unset by default — the gateway runs with the in-process ledger and file registry, zero extra infrastructure. The Postgres/Redis stack is an optional extra (pip install 'openagent-control[persistence]' / poetry install --extras persistence) and is lazy-imported, so the default deployment doesn't pay its ~20MB of resident memory or its install footprint. Set OAC_DATABASE_URL to switch the registry and ledger to Postgres (own oac schema, migrated via Alembic), and OAC_REDIS_URL to cache registry lookups (30s TTL) and brokered tokens (capped at each token's own expiry). See ADR-0009.

make up-persistent               # docker compose --profile persistence: + postgres, redis
make db-upgrade                  # alembic upgrade head against OAC_DATABASE_URL

To point at your own Postgres instance instead: export OAC_DATABASE_URL=postgresql+asyncpg://user:pass@host/db then make db-upgrade.

Examples

  • examples/enterprise_scenario/ — the full stack with nothing stubbed. A LangGraph agent, real OIDC/JWKS identity, real OPA, real RFC 8693 credential brokering, and a real MCP server over real SQLite that validates the brokered credential's signature, audience, and scope. It also demonstrates the property that distinguishes a control plane from a logging proxy: an agent that bypasses the gateway is refused by the upstream, because the token it holds is scoped to the gateway, not to the API. The same assertions run in CI (tests/integration/), so the demo cannot rot.

    brew install opa && poetry install --with examples
    poetry run python -m examples.enterprise_scenario.scenario
    

    Its keycloak/ suite runs the same identity and RFC 8693 adapters against real Keycloak 26.4 — an IdP this repo didn't write, so it can't share our bugs. That check earned its keep on the first run: it caught the identity adapter misreading Keycloak's service-account sub as a human sponsor, which would have 401'd every autonomous agent.

    The same is done for the MCP protocol itself against GitHub's production MCP server (tests/integration/test_github_mcp_conformance.py), which is how we found that the original upstream adapter did not speak MCP at all — see ADR-0011.

  • examples/langgraph_governed_agent/ — a deterministic, zero-API-key demo of a LangGraph agent whose tool calls are allowed, denied, and cryptographically receipted by the gateway:

    poetry install --with examples
    make up
    poetry run python -m examples.langgraph_governed_agent.demo
    
  • examples/oidc_identity_demo/ — the gateway authenticating agents with real Okta/Entra-shaped OIDC access tokens (signature, audience, and orphan-agent checks), fully offline against a mock IdP:

    poetry run python -m examples.oidc_identity_demo.demo
    

Metadata

Release files for openagent-control 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openagent-control 0.1.0
File Size Uploaded Provenance Actions
openagent_control-0.1.0.tar.gz 41.7 kB Without provenance Details for openagent_control-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for openagent-control 0.1.0
File Interpreter ABI Platform Actions
openagent_control-0.1.0-py3-none-any.whl Python 3 none any Details for openagent_control-0.1.0-py3-none-any.whl

Total release size: 99.1 kB

Release files / openagent_control-0.1.0.tar.gz

Download URL openagent_control-0.1.0.tar.gz
Size 41.7 kB
Tags Source
SHA-256 checksum
How to use checksums
28865e29f3bbee708d433f301d84cc33a191b3448b664e76ae6a27ec4e6d8177
BLAKE2b-256 checksum
How to use checksums
48220b3cd4b05358154bc345cc8cb003f67564dc02cbebfb38a4a403322d482b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.14.5 Darwin/25.5.0

Release files / openagent_control-0.1.0-py3-none-any.whl

Download URL openagent_control-0.1.0-py3-none-any.whl
Size 57.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e241ab81c1a9bf4cb4dae5be1d63d0befbc3b09a476c3ebddc96f4a593d15f51
BLAKE2b-256 checksum
How to use checksums
fa219e4d22c2c7375bc702e35aa7209a14ae3bb1dffb8d275c101bf6eb76c8be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.14.5 Darwin/25.5.0

Security for openagent-control 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page