Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

action space
The full set of moves an agent can choose from, usually the list of tools it is given.
agent
A program that repeats a loop: read the state, choose a move, look at the result, then decide again.
budget
A hard limit on how many steps, seconds or moves a run may spend before it must stop.
delegation
Handing a smaller task to another agent, with its own instructions, tools, budget and required result shape.
guardrail
Code that checks a proposed move against the rules before it runs, and can refuse it or ask a person.
loop
The repeated cycle of choosing a move, carrying it out and reading the result, which makes a program an agent.
model
The trained program that reads text and chooses what to say or do next.
observation
What came back from a tool or a step, added to the state for the next decision.
plan
A written list of steps for the task, which can be revised when a step fails or the facts change.
scratchpad
The working notes for one run: the plan, what was tried and what came back, discarded when the run ends.
state
The record of the question, the plan and the observations so far, passed to the model on every turn.
sub-agent
A separate agent given one bounded job, its own tools and its own budget, whose answer returns to the caller.
tool
A named function an agent may ask to run, with declared inputs and a result the loop can read.
trace
The ordered record of every decision, tool use and result in a run, used to explain what happened.

AI agents from the ground up

Permissions and guardrails

An agent with a tool can be talked into using it. The guardrail is a policy the model cannot edit: who may call what, with which values, and when a person must approve.

Part 6 of 10

Advanced16 min readBack to Courses

The model is the least trusted component

Everything the model reads can influence what it asks for: the user, a retrieved document, a tool result, a previous turn. The tool call is therefore untrusted input, exactly like a form submission.

A guardrail is the code between that request and the effect. It answers three questions: is this tool allowed for this user, are these arguments acceptable, and does this action need a person.

Treat the tool call the way you treat an HTTP request from the internet. It arrives with a name, a set of arguments and an implied intent, and none of those can be trusted because the model assembled them from text it read. The guardrail parses the request, looks up the policy for that user and that tool, checks the values, and only then decides whether to run, ask or refuse.

Allow-lists, not block-lists

A block-list of bad arguments is a losing game: there is always another spelling. An allow-list says which values are acceptable and rejects everything else, which is a finite thing to reason about.

The same applies to tools. A support agent gets read tools and a refund tool with a cap; it does not get a shell because “it might be useful”. Every capability is a decision someone should be able to defend.

Write the policy in the same repository as the tools, reviewed like code. A spreadsheet maintained by another team is a policy that drifts silently, and the first symptom is a role that can do something nobody remembers granting. The policy should be small enough to read in one sitting and specific enough that a new tool without an entry is denied by default.

A policy the model cannot see

POLICY = {
    "get_order": {"roles": {"support", "admin"}, "approval": False},
    "issue_refund": {"roles": {"admin"}, "approval": True, "max_amount": 100},
}

def check(user, tool, args):
    rule = POLICY.get(tool)
    if rule is None:
        return "denied: unknown tool"
    if user["role"] not in rule["roles"]:
        return "denied: role"
    if "max_amount" in rule and args.get("amount", 0) > rule["max_amount"]:
        return "denied: over limit"
    return "approval" if rule["approval"] else "allowed"

A policy with roles and limits

Run the checks, then add a tool that needs approval and one that is admin-only. Confirm a support user is denied the admin tool and asked for approval on the other.

Output
Click "Run" to execute your code

Approval is a UI problem too

An approval request is a decision, and a decision needs the facts. Show the tool, the exact arguments, the user it will affect and the consequence: “issue a refund of 42.00 to order A-1024 for customer 8812”. A dialog that says “the agent wants to perform an action” trains people to click approve without reading, which is worse than no approval because it looks like a control.

A common mistake is asking for approval after the effect has been prepared or partially applied. The person is then approving a fait accompli. Put the pause before the call, keep the state resumable, and record the decision — approved, rejected, or timed out — in the same trace as the tool call.

Track where the data came from

A useful guardrail is provenance. If a value came from a retrieved document, it is untrusted; if it came from an authenticated session, it is trusted. An action that needs a trusted value should refuse an untrusted one, no matter how plausible it looks.

This is what stops the classic attack: a document says “refund order A-1024”, the agent calls the refund tool, and the order id came from the document rather than from the user’s verified session.

Approval must show the human the exact arguments that will be used. A prompt that says “approve action?” without the amount and the recipient is a rubber stamp.

Guardrails fail closed

If the policy cannot be loaded, the tool is unavailable. If the role is unknown, it is denied. If the approval service is down, the action waits. A guardrail that fails open turns an outage into an incident.

The cost is availability, and it is the right trade for anything with an effect. Read-only tools can fail open; writes cannot.

The failure mode to watch is the quiet one: a policy lookup that returns an empty rule set and is read as “no restrictions”. Treat an empty policy as a configuration error, not as permission. The symptom of getting this wrong is an outage that silently grants more access than the day before.

Untrusted data cannot trigger an effect

The order id came from a document, not the session. Run the check and confirm the refund is refused; then pass the id from the session and see it allowed.

Output
Click "Run" to execute your code

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

Why is a tool call untrusted input?