Skip to content

Agent Governance Toolkit

strands-agt integrates Microsoft’s Agent Governance Toolkit (AGT) with Strands Agents via the InterventionHandler primitive. It provides deterministic, YAML-based policy enforcement that gates tool calls before execution — no model judgment involved.

  • Deny — block tool calls that violate policy (e.g. file deletion, production access)
  • Allow — permit tool calls that match policy
  • Steer — redirect the agent with guidance instead of a hard block
Terminal window
pip install strands-agt

Define policies in YAML:

policies.yaml
policies:
- name: allow-search
effect: allow
actions: ["search", "read_file"]
principals: ["User::*"]
- name: deny-delete
effect: deny
actions: ["delete_file"]
principals: ["*"]
reason: "File deletion is not permitted"

Attach to your agent:

from strands import Agent
from strands_agt import AGTGovernance
governance = AGTGovernance(policies="policies.yaml")
agent = Agent(
tools=[search_tool, read_file_tool, delete_file_tool],
interventions=[governance],
)
# search_tool executes normally
agent("Search for quarterly reports")
# delete_file_tool is blocked — the model sees the denial reason
agent("Delete the temp files")

Role-based access with principal resolution

Section titled “Role-based access with principal resolution”
from strands_agt import AGTGovernance
governance = AGTGovernance(
policies="role_policies.yaml",
principal_resolver=lambda state: {
"type": state.get("user_role", "User"),
"id": state.get("user_id", "anonymous"),
},
)
agent = Agent(
tools=[...],
interventions=[governance],
)
# Pass identity via invocation_state
agent("Delete the old backups", invocation_state={"user_role": "Admin", "user_id": "alice"})
policies:
- name: rate-limited-email
effect: allow
actions: ["send_email"]
conditions:
session.call_count:
lt: 5

The handler tracks per-tool call counts automatically and includes them in policy evaluation.

governance = AGTGovernance(
policies="env_policies.yaml",
context_enricher=lambda ctx: {
"environment": os.environ.get("DEPLOY_ENV", "development"),
"tenant_id": ctx["invocation_state"].get("tenant_id"),
},
)

Enricher fields are available in policy conditions under session.*.

ParameterTypeDefaultDescription
policiesstr | list[str]requiredYAML policy file path(s) or inline YAML text
principaldict[str, str] | None{"type": "User", "id": "anonymous"}Static principal identity
principal_resolverCallable | NoneNoneDynamic resolver from invocation_state
context_enricherCallable | NoneNoneInjects extra fields into policy context
on_errorstr"throw"Error mode: "throw", "proceed", or "deny"

Each policy has:

FieldRequiredDescription
nameYesUnique policy identifier
effectYesallow, deny, or steer
actionsNoTool names to match (["*"] = all)
principalsNoPrincipal patterns (["Type::id"], ["Type::*"], ["*"])
conditionsNoContext conditions (supports lt, lte, gt, gte, eq, neq, in)
reasonNoMessage shown to the model on deny
guidanceNoFeedback for steer decisions

Deny policies are evaluated first and short-circuit. If no deny matches, steer is checked. If neither matches, the first matching allow wins. No match = deny (fail-closed).