Session 4. Bounded tools — Thu 17 Sep

Conclusion

You read the tool registry as a contract: a name, a description that is the model's only manual, and a function you control.

What you did

The failure you handled

Prompt injection in tool output. guard_tool_output flags an order aimed at the model, returns the text unchanged, and says which shape it matched.

It matches the shape of an order, not the topic, because a guard that flags "the setup instructions are in SETUP.md" is a guard somebody switches off.

What to carry forward

The rule underneath all of it: tool output is data, the guard is the boundary, and the agent never executes what a tool returns.

Every tool you built reads. Nothing writes, spends, or mutates — that is the blast radius, and it is a design decision, not an accident of the corpus.

Into session 5

Session 5 assumes these five tools exist and that ToolError is how a tool says no. It adds the loop around them: max_tool_calls, the trace, and the exit conditions you design before you need them.

Homework

One tool your assistant should never call, and one it should call only after a human says yes. Then add a sixth injection shape and find the ordinary sentence it flags by mistake.