https://github.com/agentcontrol/agent-control
Centralized agent control plane for governing runtime agent behavior at scale. Configurable, extensible, and production-ready.
https://github.com/agentcontrol/agent-control
agentic-workflow ai-safety guardrails llm runtime-guardrails
Last synced: 2 months ago
JSON representation
Centralized agent control plane for governing runtime agent behavior at scale. Configurable, extensible, and production-ready.
- Host: GitHub
- URL: https://github.com/agentcontrol/agent-control
- Owner: agentcontrol
- License: apache-2.0
- Created: 2026-01-30T23:23:24.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-04-21T23:03:35.000Z (2 months ago)
- Last Synced: 2026-04-22T01:13:18.906Z (2 months ago)
- Topics: agentic-workflow, ai-safety, guardrails, llm, runtime-guardrails
- Language: Python
- Homepage: https://agentcontrol.dev
- Size: 5.31 MB
- Stars: 215
- Watchers: 3
- Forks: 27
- Open Issues: 39
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
Agent Control
Agent Control Website |
Docs |
Quickstart |
Examples |
Slack
Enforce runtime guardrails through a centralized control layer—configure once and apply across all agents. Agent Control evaluates inputs and outputs against configurable rules to block prompt injections, PII leakage, and other risks without changing your agent’s code.

- **Centralized safety** - define controls once, apply across agents, update without redeploying
- **Runtime configuration** - manage controls via API or UI, no code changes needed
- **Pluggable evaluators** - built-in (regex, list, JSON, SQL) or bring your own
- **Framework support** - works with LangChain, CrewAI, Google ADK, AWS Strands, and more
## Quick Start
Prerequisites: Docker and Python 3.12+.
Quick start flow:
```
Start server
↓
Install SDK
↓
Wrap a model or tool call with @control() and register your agent
↓
Create controls (UI or SDK/API)
```
### 1. Start the server
No repo clone required:
```bash
curl -L https://raw.githubusercontent.com/agentcontrol/agent-control/refs/heads/main/docker-compose.yml | docker compose -f - up -d
```
This starts PostgreSQL and Agent Control at `http://localhost:8000`, including
the UI/dashboard.
Note: This starts server without API keys configured which is dangerous for any real world usage.
Set appropirate env vars to override defaults like:
* Exposed ports
* Agent and admin API keys
* Postgres DB Password
```bash
export AGENT_CONTROL_SERVER_HOST_PORT=18000
export AGENT_CONTROL_DB_HOST_PORT=15432
export AGENT_CONTROL_API_KEY_ENABLED=true
export AGENT_CONTROL_API_KEYS="agent-api-key"
export AGENT_CONTROL_ADMIN_API_KEYS="admin-api-key"
export AGENT_CONTROL_POSTGRES_PASSWORD="postgres-password"
curl -L https://raw.githubusercontent.com/agentcontrol/agent-control/refs/heads/main/docker-compose.yml | docker compose -f - up -d
```
Verify it is up:
```bash
curl http://localhost:8000/health
```
If you changed `AGENT_CONTROL_SERVER_HOST_PORT`, use that port in the health check URL.
### 2. Install the SDK
Run this in your agent project directory.
Python:
```bash
uv venv
source .venv/bin/activate
uv pip install agent-control-sdk
```
TypeScript:
- See the [TypeScript SDK example](examples/typescript_sdk/README.md).
### 3. Wrap a call and register your agent
```python
# my_agent.py
import asyncio
import agent_control
from agent_control import control, ControlViolationError
# Protect any function (like LLM calls)
@control()
async def chat(message: str) -> str:
# In production: response = await LLM.ainvoke(message)
# For demo: simulate LLM that might leak sensitive data
if "test" in message.lower():
return "Your SSN is 123-45-6789" # Will be blocked!
return f"Echo: {message}"
# Initialize your agent
agent_control.init(
agent_name="awesome_bot_3000", # Unique name
agent_description="My Chatbot",
)
async def main():
try:
print(await chat("test")) # ❌ Blocked
except ControlViolationError as e:
print(f"❌ Blocked: {e.control_name}")
finally:
await agent_control.ashutdown()
if __name__ == "__main__":
asyncio.run(main())
```
Use `agent_control.shutdown()` or `await agent_control.ashutdown()` before process exit so short-lived scripts flush pending observability events cleanly.
External integrations can register a sink for the same finalized
control-event payloads:
```python
from agent_control import (
register_control_event_sink,
unregister_control_event_sink,
)
from agent_control_telemetry import BaseControlEventSink, SinkResult
class MyControlEventSink(BaseControlEventSink):
def write_events(self, events):
for event in events:
forward_to_external_system(event.model_dump(mode="json"))
return SinkResult(accepted=len(events), dropped=0)
sink = MyControlEventSink()
register_control_event_sink(sink)
# Later, when tearing down the integration:
unregister_control_event_sink(sink)
```
Registered sinks receive the same local, server, and merged control-execution
events the SDK emits through its normal event-construction flow. If no
external sink is registered, the default OSS delivery path is unchanged. If one
or more sinks are registered, they replace the default built-in delivery path.
Next, create a control in Step 4, then run the setup and agent scripts in
order to see blocking in action.
### 4. Add controls
This example adds the control with a small SDK setup script. You can also
create and attach controls through the UI or direct API calls.
Minimal SDK example (assumes the server is running at `http://localhost:8000`
and uses the same `agent_name` as Step 3):
```python
# setup.py - Run once to configure agent controls
import asyncio
from datetime import datetime, UTC
from agent_control import AgentControlClient, controls, agents
from agent_control_models import Agent
async def setup():
async with AgentControlClient() as client: # Defaults to localhost:8000
# 1. Register agent first
agent = Agent(
agent_name="awesome_bot_3000",
agent_description="My Chatbot",
agent_created_at=datetime.now(UTC).isoformat(),
)
await agents.register_agent(client, agent, steps=[])
# 2. Create control (blocks SSN patterns in output)
control = await controls.create_control(
client,
name="block-ssn",
data={
"enabled": True,
"execution": "server",
"scope": {"stages": ["post"]},
"condition": {
"selector": {"path": "output"},
"evaluator": {
"name": "regex",
"config": {"pattern": r"\b\d{3}-\d{2}-\d{4}\b"},
},
},
"action": {"decision": "deny"},
},
)
# 3. Associate control directly with agent
await agents.add_agent_control(
client,
agent_name=agent.agent_name,
control_id=control["control_id"],
)
print("✅ Setup complete!")
print(f" Control ID: {control['control_id']}")
asyncio.run(setup())
```
Controls now store leaf `selector` and `evaluator` definitions under `condition`, which also enables composite `and`, `or`, and `not` trees.
**Tip**: If you prefer a visual flow, use the UI instead - see the [UI Quickstart](https://docs.agentcontrol.dev/core/ui-quickstart).
Run both scripts in order:
```bash
uv run setup.py
uv run my_agent.py
```
Expected output:
```text
Blocked: block-ssn-demo
```
## Examples:
Explore working examples for popular frameworks.
- [Customer Support Agent](examples/customer_support_agent/) - PII protection, prompt injection defense, and tool controls
- [Steer Action Demo](examples/steer_action_demo/) - observe, deny, and steer decisions in one workflow
- [LangChain](examples/langchain/) - protect a SQL agent from dangerous queries
- [CrewAI](examples/crewai/) - combine Agent Control with CrewAI guardrails
- [AWS Strands](examples/strands_agents/) - protect Strands workflows and tool calls
- [Google ADK Decorator](examples/google_adk_decorator/) - add controls with `@control()`
## How It Works

Agent Control evaluates agent inputs and outputs against controls you configure at runtime. That keeps guardrail logic out of prompt code and tool code, while still letting teams update protections centrally.
Read more about [Controls](https://docs.agentcontrol.dev/concepts/controls) and Learn how controls, selectors, and evaluators work
## Performance
| Endpoint | Scenario | RPS | p50 | p99 |
| ---------------- | ----------------------------- | ------- | -------- | -------- |
| Agent init | Agent with 3 tool steps | 509 | 19 ms | 54 ms |
| Evaluation | 1 control, 500-char content | 437 | 36 ms | 61 ms |
| Evaluation | 10 controls, 500-char content | 349 | 35 ms | 66 ms |
| Evaluation | 50 controls, 500-char content | 199 | 63 ms | 91 ms |
| Controls refresh | 5-50 controls per agent | 273-392 | 20-27 ms | 27-61 ms |
- Agent init handles create and update as an upsert.
- Local laptop benchmarks are directional, not production sizing guidance.
_Benchmarked on Apple M5 (16 GB RAM), Docker Compose (`postgres:16` + `agent-control`)._
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines, development workflow, and quality checks.
## License
Apache 2.0. See [LICENSE](LICENSE) for details.