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
23 small wins to finish your pathNext lesson

The choke point

Lesson 1 said the rule belongs in the loop between deciding and running. This lesson puts it there, which is the single idea the whole toolkit is built on.

The kernel is the object that owns the gate. It takes a policy engine, and it gives you one method to call before any tool runs.

Example
from agent_control_plane import AgentKernel, PolicyEngine

policy = PolicyEngine()
policy.add_constraint("support", ["lookup_order", "issue_refund"])

kernel = AgentKernel(policy_engine=policy)
print(kernel.intercept_tool_execution("support", "lookup_order", {"order_id": "A17"}))

None is the answer you want. The method returns nothing at all when the call is allowed, which reads strangely the first time and is the convention the rest of the toolkit follows.

What a refusal looks like

Example
verdict = kernel.intercept_tool_execution("support", "delete_order", {"order_id": "A17"})
for key in sorted(verdict):
    print(key, "=", verdict[key])

A dictionary instead of None, saying what was refused and why. The keys are sorted here because a dictionary printed whole has no promised order, and a lesson whose output changes between runs is a lesson that cannot be checked.

mute is the toolkit's name for the shape of this refusal: the tool produces nothing, and the agent is told the call failed rather than being told a lie about it succeeding.

The gate in the loop

Now put it back in the loop from lesson 1. The only new line is the one that asks the kernel first.

Example
from pretend_agent_governance import PretendAgent, TOOLS

agent = PretendAgent()
for message in ["Where is order A17?", "please delete order A17"]:
    tool, args = agent.decide(message)
    verdict = kernel.intercept_tool_execution("support", tool, args)
    if verdict is None:
        print(tool, "ran:", TOOLS[tool](**args))
    else:
        print(tool, "refused:", verdict["error"])

The deletion from lesson 1 does not happen now. The agent still decided to do it, the message still said what it said, and the order is still there.

The kernel writes a line to Python's logging module on every decision, so you will see BLOCKED: on your terminal. That goes to standard error, which is why it is not part of the captured output above.
What one call passes through
The agent decides. A message becomes a tool name and argumentsStep 1 of 5

That last step is worth sitting with. intercept_tool_execution does not reach into your program and stop anything. It returns an answer, and your loop is what honours it. Lesson 27 comes back to what that means when the agent is written by someone else.

Try it yourself
  • Add issue_refund to a message and watch it pass, since it is on the allow-list.
  • Delete the add_constraint line entirely and run it again. Lesson 5 explains what you see.
  • Change if verdict is None to if verdict and watch a gate that is wired in backwards let everything through.

This is what real progress feels like.