ACP — AI Control Plane: deterministic governance and execution control for enterprise AI agents.
Project description
ACP — AI Control Plane
Deterministic governance and execution control plane for enterprise AI agents and autonomous systems.
Note: “ACP” means many things in other industries (medical, political, nonprofit, and more). In this project it always means ACP — AI Control Plane, not a generic acronym.
Add governance, approvals, policy enforcement, and execution visibility to AI agents in minutes.
Works with CrewAI, LangGraph, Strands, Google ADK, MCP tools, and custom Python workflows.
Requires: Docker Desktop (Compose v2).
Quick start
Make sure Docker Desktop is already running before you start ACP.
pip install acp-ai
acp init # creates starter policies in ~/.acp/policies
acp up
acp dashboard # open governance UI
| Step | Command |
|---|---|
| Install | pip install acp-ai |
| Initialize policies | acp init |
| Start stack | acp up |
| Open UI | acp dashboard → http://localhost:3090/dashboard/ |
| Stop | acp down |
For a real local integration, the usual sequence is:
acp init- start Docker Desktop
acp upexport ACP_INTERCEPTOR_URL=http://localhost:8080export ACP_BEARER_TOKEN=...- run your governed agent
If Docker is not already running, acp up will fail with Docker daemon / compose connection errors.
Why ACP — AI Control Plane?
Most agents call tools, APIs, and other agents directly. Teams then scatter rules across Python, workflows, and frameworks:
if supplier_risk_score > threshold:
require_human_approval()
That becomes inconsistent, hard to audit, easy to bypass, and duplicated everywhere.
ACP — AI Control Plane centralizes governance outside agent code:
| Capability | What you get |
|---|---|
| Centralized governance | One place for rules, not copy-paste per team |
| Policy enforcement | OPA/Rego evaluates every governed call |
| Approvals | Escalate high-risk actions to humans |
| A2A governance | Governed agent-to-agent calls |
| A2T governance | Governed agent-to-tool calls |
| Audit & visibility | Decisions, traces, registry in one dashboard |
Architecture
Agent runtime -> ACP SDK -> Interceptor / Gateway -> OPA / Rego -> allow | deny | escalate -> governed execution
ACP sits at the execution boundary:
- agent frameworks keep reasoning and orchestration
- the interceptor validates identity, routes policy, and records audit traces
- OPA / Rego returns deterministic allow, deny, or escalate decisions
- only allowed or approved requests reach tools, APIs, MCP servers, or other agents
Request sequence
Typical governed flow:
- the agent calls a governed function through the ACP SDK
- the interceptor validates JWT identity and normalizes the request
- OPA / Rego evaluates policy for the tool, action, and claims
- ACP records the decision and exposes it in the dashboard
- the SDK executes only on
allow, waits for review onescalate, and blocks ondeny
Dashboard
The ACP — AI Control Plane dashboard is a core differentiator: live allow/deny/escalate decisions, approvals, agent registry, and policy catalog. Open http://localhost:3090/dashboard/ after acp up.
Overview & activity
Decisions & approvals
Registry & policies
Forensics
Deployment modes
| Mode | How | Best for |
|---|---|---|
| Local | acp up via pip + Docker |
Demos, dev, quickstart |
| SDK | @governed_tool in your agent code |
CrewAI, LangGraph, Strands, custom Python |
| Gateway | Single origin on :3090 (dashboard + API proxy) |
Local unified URL; pattern for prod ingress |
| Cloud / self-hosted | Docker Compose, Kubernetes, ECS/EKS on AWS/Azure/GCP | Team or enterprise rollout |
Local endpoints
| URL | Purpose |
|---|---|
| http://localhost:3090/dashboard/ | Governance dashboard |
| http://localhost:8080 | Interceptor API (/tool-call, /api/v1/*) |
Self-hosted (example)
https://acp.your-company.example
Example: governed tool
Set ACP_INTERCEPTOR_URL and ACP_BEARER_TOKEN before defining a @governed_tool.
The decorator constructs its ACP client at decoration time, so setting those env vars later inside main() is too late.
import os
from acp import governed_tool
# Set env vars before decorator evaluation.
os.environ.setdefault("ACP_INTERCEPTOR_URL", "http://localhost:8080")
os.environ.setdefault("ACP_BEARER_TOKEN", "<dev-jwt>")
@governed_tool(
agent_id="texas-weather-agent",
tool="weather_api",
action="read_weather",
)
def get_texas_weather(city: str):
return {"city": city, "status": "pending_review"}
The AI Control Plane intercepts the call, evaluates policy, then allows, denies, or escalates.
tool="weather_api" is the governed ACP tool id. It does not have to match the Python function name (get_texas_weather). ACP policy keys on tool, not the Python symbol name.
The JWT agent_id claim must match agent_id="texas-weather-agent" in @governed_tool(...).
Example: policy (Rego)
package acp.policy
allow {
input.identity.role == "supply-chain-manager"
input.action.tool == "supplier_approval"
input.risk_score < 70
}
Edit policies in ~/.acp/policies/ after acp init.
Adding a new governed tool
acp init creates starter policy files in ~/.acp/policies/, but you still need to wire new tools into policy yourself.
For a brand-new governed tool, update all of these:
- choose an ACP tool id, for example
weather_api - add tool-to-role mapping in
~/.acp/policies/rbac.rego - route the tool in
~/.acp/policies/router.rego - add or reuse a domain policy file such as
weather.rego - mint and export
ACP_BEARER_TOKEN - make sure the JWT
agent_idclaim matches@governed_tool(agent_id=...) - run the agent
Two valid patterns:
Pattern 1: reuse an ACP tool bucket
Use one ACP tool id for multiple Python functions in the same policy domain.
@governed_tool(
agent_id="texas-weather-agent",
tool="weather_api",
action="read_weather",
)
def get_texas_weather(city: str):
...
~/.acp/policies/rbac.rego
"weather_api": ["weather"],
~/.acp/policies/router.rego
decision = weather.decision {
input.tool == "weather_api"
rbac.decision.decision == "allow"
}
~/.acp/policies/weather.rego
package acp.weather
default decision = {
"decision": "allow",
"reason": "weather_action_allowed",
"policy": "acp/weather",
}
decision = {
"decision": "deny",
"reason": "weather_action_not_permitted",
"policy": "acp/weather",
} {
not input.action == "read_weather"
not input.action == "read_weather_batch"
}
Pattern 2: add a brand-new ACP tool id
If you want policy to key directly on a new id such as get_texas_weather, add that id to both rbac.rego and router.rego, then route it to the right domain policy file.
If your starter router.rego or rbac.rego references a tool id, make sure the corresponding domain policy file also exists.
Local JWT dev example
Local governed /tool-call requests require a bearer token when JWT auth is enabled. ACP_INTERCEPTOR_URL alone is not enough.
Set:
ACP_INTERCEPTOR_URL=http://localhost:8080ACP_BEARER_TOKEN=<signed-jwt>
If ACP_BEARER_TOKEN is missing, governed calls may fail with 401 Unauthorized / missing bearer token.
One dev-friendly way to mint a token is:
python -m pip install pyjwt cryptography
export ACP_BEARER_TOKEN="$(
python - <<'PY'
from pathlib import Path
import time
import jwt
private_key = (Path.home() / ".acp" / "jwt" / "private.pem").read_text()
token = jwt.encode(
{
"sub": "agent:texas-weather-agent",
"agent_id": "texas-weather-agent",
"roles": ["weather"],
"iss": "acp-dev",
"aud": "acp-interceptor",
"exp": int(time.time()) + 3600,
},
private_key,
algorithm="RS256",
)
print(token)
PY
)"
Use these claims for local development:
sub=agent:texas-weather-agentagent_id=texas-weather-agentroles=["weather"]iss=acp-devaud=acp-interceptor
agent_id in the JWT must match the agent_id passed to @governed_tool(...).
Example: governance flow
Supply Chain Agent
→ ACP — AI Control Plane validates identity (JWT)
→ OPA evaluates policy
→ Decision: ESCALATE
→ Human approves in dashboard
→ Execution resumes
What the AI Control Plane provides
- Policy enforcement — OPA/Rego (Cedar on roadmap)
- Identity — JWT from Okta, Auth0, Keycloak, or your IdP
- Approvals — human-in-the-loop for risky actions
- Observability — dashboard for decisions, traces, agents, tools
- Agent registry — lightweight catalog of agents and capabilities
- Framework-friendly — keep CrewAI / LangGraph / Strands for reasoning; govern execution here
Philosophy
Orchestration frameworks handle reasoning, planning, and workflows.
ACP — AI Control Plane handles governance, trust, approvals, policy, and auditability.
Reasoning stays autonomous. Execution stays governed.
Roadmap
- Gateway / proxy execution mode (production hardening)
- MCP-native governance
- Policy studio and replay
- Enterprise topology views
- Multi-cloud deployment templates
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file acp_ai-0.2.9.tar.gz.
File metadata
- Download URL: acp_ai-0.2.9.tar.gz
- Upload date:
- Size: 79.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f95c8b2fca6208ba36f7427d60eda45171ef985d884c12cd17415319dfa0e638
|
|
| MD5 |
25c31d138800306fcd1feb40647e8195
|
|
| BLAKE2b-256 |
744d18c7aab26f9e5aff6826d11cbc2d33a9e0540af050b67ba81d4f90ba4641
|
File details
Details for the file acp_ai-0.2.9-py3-none-any.whl.
File metadata
- Download URL: acp_ai-0.2.9-py3-none-any.whl
- Upload date:
- Size: 105.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6cfeeaad279791dcca7638110720fcd5696279325ee55e1260d2326a076e3c65
|
|
| MD5 |
cc0d006b1972c261401cc478e720c653
|
|
| BLAKE2b-256 |
ade75c1db23a3f66ec6d6f8ce01e1ebcbf91fdb630e89b1ab939f1a254f4f871
|