[Agent Control](https://github.com/agentcontrol/agent-control) provides an open-source runtime control plane for all your AI agents — configurable rules that evaluate inputs and outputs at every step in your agent against a set of policies managed centrally, without modifying your agent’s code. It integrates with Strands via the `AgentControlPlugin` or `AgentControlSteeringHandler`:

-   **AgentControlPlugin** — hooks into Strands lifecycle events (`BeforeToolCallEvent`, `AfterModelCallEvent`, etc.) and enforces hard blocks (deny) or corrective steering on violations
-   **AgentControlSteeringHandler** — integrates with Strands’ experimental steering API to convert Agent Control `steer` matches into `Guide()` actions, prompting the agent to rewrite its output before proceeding

Controls are defined on a central server (or locally via `controls.yaml`) and evaluated at runtime — no redeployment needed when rules change.

## Installation

```bash
pip install "agent-control-sdk[strands-agents]"
```

The SDK connects to a running Agent Control server. Point it at your instance via the `AGENT_CONTROL_URL` environment variable (defaults to `http://localhost:8000`). See the [Agent Control docs](https://docs.agentcontrol.dev/) for server setup options.

## Usage

### Basic setup with AgentControlPlugin

```python
import agent_control
from agent_control.integrations.strands import AgentControlPlugin
from strands import Agent
from strands.models.openai import OpenAIModel

# Initialize once at startup — registers the agent and fetches controls
agent_control.init(agent_name="my-agent")

# Attach the plugin — all lifecycle events are intercepted automatically
agent_control_plugin = AgentControlPlugin(agent_name="my-agent")

agent = Agent(
    model=OpenAIModel(model_id="gpt-4o-mini"),
    system_prompt="You are a helpful assistant.",
    tools=[...],
    plugins=[agent_control_plugin],
)

result = await agent.invoke_async("Hello!")
```

When a control matches, the plugin raises an exception that should be caught above the agent call site.

### Adding steering for LLM output correction

For cases where you want the agent to *fix* its output rather than hard-block, combine the plugin with `AgentControlSteeringHandler`:

```python
from agent_control.integrations.strands import AgentControlPlugin, AgentControlSteeringHandler
from strands.hooks import BeforeToolCallEvent, AfterToolCallEvent

# Plugin handles tool-stage deny checks
agent_control_plugin = AgentControlPlugin(
    agent_name="my-agent",
    event_control_list=[BeforeToolCallEvent, AfterToolCallEvent],
)

# Steering handler converts steer matches into Strands Guide() retries
steering = AgentControlSteeringHandler(agent_name="my-agent")

agent = Agent(
    model=model,
    system_prompt="...",
    tools=[...],
    plugins=[agent_control_plugin, steering],  # both registered as plugins
)
```

When a `steer` control matches on LLM output, `AgentControlSteeringHandler` returns a `Guide(reason=<steering_context>)` and the agent retries with that guidance injected.

## Configuration

**AgentControlPlugin**

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `agent_name` | `str` | required | Agent identifier, must match the name used in `agent_control.init()` |
| `event_control_list` | `list[type] | None` | `None` | Strands event types to intercept. Defaults to all supported events (`BeforeInvocationEvent`, `BeforeModelCallEvent`, `AfterModelCallEvent`, `BeforeToolCallEvent`, `AfterToolCallEvent`, `BeforeNodeCallEvent`, `AfterNodeCallEvent`) |
| `on_violation_callback` | `Callable | None` | `None` | Called on every violation with `(info_dict, EvaluationResult)`. Useful for logging or metrics |
| `enable_logging` | `bool` | `True` | Emit debug log lines for control checks and violations |

**AgentControlSteeringHandler**

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `agent_name` | `str` | required | Agent identifier, must match the name used in `agent_control.init()` |
| `enable_logging` | `bool` | `True` | Emit debug log lines for steering evaluations |

### Environment variables

| Variable | Default | Description |
| --- | --- | --- |
| `AGENT_CONTROL_URL` | `http://localhost:8000` | Server URL |
| `AGENT_CONTROL_API_KEY` | — | API key (if auth is enabled) |

## Troubleshooting

**“AgentControl not initialized”** — call `agent_control.init()` before creating the plugin.

**Controls not triggering** — verify the server is running (`curl http://localhost:8000/health`) and controls are attached to your agent (re-run your setup script).

**Import errors** — make sure you installed the `strands-agents` extra: `pip install "agent-control-sdk[strands-agents]"`.

## References

-   [GitHub](https://github.com/agentcontrol/agent-control)
-   [PyPI](https://pypi.org/project/agent-control-sdk/)
-   [Documentation](https://docs.agentcontrol.dev/)
-   [Strands integration examples](https://github.com/agentcontrol/agent-control/tree/main/examples/strands_agents)