Agent Governance Toolkitagent-governance-toolkit 4.1.0 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
28 small wins to finish your pathNext lesson

One gate over both engines

This course taught two engines. The Python PolicyEngine checks the tool name and its arguments; the document PolicyEvaluator checks conditions written in YAML. A real gate calls both, because each catches what the other cannot.

What each engine is good at

The constraint engine from lesson 6 is the fast, absolute layer: this role may call these tools and no others, decided in Python at the choke point. The document engine from lesson 11 is the layer that changes without a deploy: a refund over a hundred needs a human, written in a file an auditor can read. A support agent needs both, the hard tool allow-list and the money rule that a manager might edit.

Calling both

python
from agent_control_plane import AgentKernel, PolicyEngine
from agent_os.policies.schema import PolicyDocument
from agent_os.policies.evaluator import PolicyEvaluator

constraints = PolicyEngine()
constraints.add_constraint("support", ["lookup_order", "issue_refund"])
kernel = AgentKernel(policy_engine=constraints)
money = PolicyEvaluator(policies=[PolicyDocument.from_yaml("refunds.yaml")])


def allowed(tool, args):
    verdict = kernel.intercept_tool_execution("support", tool, args)
    if verdict is not None:
        return False, verdict["policy"]
    decision = money.evaluate({"tool": tool, **args})
    return decision.allowed, decision.matched_rule or decision.action

The tool allow-list runs first. Only a call it permits reaches the document engine, which then judges the arguments against the YAML rules. A call has to pass both to be allowed, and the reason a refusal gives says which layer stopped it.

The four cases

Example
for tool, args in [("lookup_order", {}), ("issue_refund", {"amount": 40}),
                   ("issue_refund", {"amount": 4000}), ("delete_order", {})]:
    print(f"{tool:13} {str(args):18}", allowed(tool, args))

A lookup and a small refund pass both engines. A four-thousand refund clears the tool allow-list and is stopped by the document rule block_big_refunds. A delete is stopped by the constraint engine before the document engine is ever consulted. One function asks both engines and returns a single answer.

Try it yourself
  • Swap the order so the document engine runs first, and find a call whose reason changes.
  • Add a second document with a higher-priority rule and watch it win, as in lesson 13.
  • Return the full decision object instead of a string and read its action field.

Every expert started right here.