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

Writing a rule of your own

Lesson 6 found that the built-in argument checks only know a handful of tool names. Lesson 7 found the second path. This lesson uses that path to write the rule the built-ins do not have: no refund over a hundred pounds.

A custom rule is a small object with a function inside it. The function gets the request and returns True to allow.

Example
from agent_control_plane.agent_kernel import PolicyRule, ActionType

def small_refunds_only(request):
    return request.parameters.get("amount", 0) <= 100

rule = PolicyRule(rule_id="refund-cap", name="small_refunds_only",
                  description="Refunds over 100 need a human",
                  action_types=[ActionType.API_CALL], validator=small_refunds_only)
print(rule.name, rule.priority)

action_types is what decides whether the rule is consulted at all. A rule listing API_CALL never sees a FILE_READ request, so a rule that seems not to run is usually a rule watching the wrong action type.

Registering it

Example
from agent_control_plane import PolicyEngine
policy = PolicyEngine()
policy.add_custom_rule(rule)

for amount in [40, 4000]:
    print(amount, policy.validate_request(make_request(amount)))

The reason names the rule, which is what makes a refusal readable months later when there are thirty rules and somebody asks why a refund did not go through.

The mistake this lesson exists to prevent

Register the same rule, then ask the gate from lesson 4 instead.

Example
from agent_control_plane import AgentKernel
policy.add_constraint("support", ["issue_refund"])
kernel = AgentKernel(policy_engine=policy)

print(kernel.intercept_tool_execution("support", "issue_refund", {"amount": 4000}))

A four thousand pound refund, allowed, by an engine holding a rule that forbids exactly that. The rule is real and registered; it simply is not on this path.

If you write one custom rule in this library, write it knowing it only runs through validate_request. Lesson 30 builds a gate that asks both paths so a rule like this cannot be bypassed by the caller choosing the wrong door.

Rules are sorted by priority when they are added, highest first, and the first one that returns False ends the check.

Try it yourself
  • Add a second rule with a higher priority that allows everything, and see whether the cap still fires.
  • Change action_types to [ActionType.FILE_READ] and watch the rule stop running.
  • Make the validator raise an exception and find out whether the engine fails open or closed.

Slow is fine. Stopping is the only problem.