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

An agent that just does what it decides

Before any governance, here is the problem it solves. This lesson builds a shop agent out of plain Python and then watches it do something nobody wanted.

The shop has orders, and four things the agent can do about them. Two are harmless and two are not.

Example
ORDERS = {
    "A17": {"item": "Noise-cancelling headphones", "paid": 249.0},
    "B22": {"item": "Laptop stand", "paid": 39.0},
}

def lookup_order(order_id):
    return ORDERS.get(order_id, {"error": f"no order {order_id}"})

def delete_order(order_id):
    ORDERS.pop(order_id, None)
    return {"deleted": order_id}

print(lookup_order("A17")["item"])

lookup_order reads. delete_order destroys. To the program calling them they are the same shape: a name, some arguments, a dictionary back.

A loop that trusts the agent

Now the piece that turns a message into a call. For the moment it is a dictionary of tools and a function that picks one by looking for words.

Example
TOOLS = {"lookup_order": lookup_order, "delete_order": delete_order}

def decide(message):
    if "delete" in message.lower():
        return "delete_order", {"order_id": "A17"}
    return "lookup_order", {"order_id": "A17"}

for message in ["Where is my order?", "Please delete order A17"]:
    tool, args = decide(message)
    print(tool, "->", TOOLS[tool](**args))

The order is gone. A customer typed a sentence and a record was destroyed, because the only thing standing between the message and the deletion was a function that believed whatever it was told.

This is the whole argument for governance. The agent was not wrong or broken: it did exactly what it decided to do. The missing piece is something with the authority to say no.

The three places you could put a rule

You could check inside delete_order, but then every tool needs its own copy and a new tool arrives with none. You could check inside decide, but that is the part an attacker steers with a sentence. Or you could check in the loop between them, which is the one place every call has to pass.

That last one is what the toolkit does, and lesson 4 is where the loop grows a gate.

Try it yourself
  • Add a third message that mentions deleting order B22, and watch that one go too.
  • Move the if in decide to the bottom, so no message ever deletes anything, then ask yourself what happens the day someone edits that function.
  • Print ORDERS after the loop to see what is left.

Little by little, you're building something great.