Read, write, confirm and audit
The human's answers are scripted (yes, then no). In an app they come from a confirmation dialog.
Tools that change the world (refund, delete, send, deploy) turn a model mistake or a hostile instruction into a real incident. Separate read from write, ask a human before side effects, give each tool the least power it needs, make writes safe to repeat, and keep an audit log.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 6 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write needs_confirmation(risk) that returns True for "write" and "destructive" and False for "read". Make unknown risks need confirmation (fail closed).
Write audit_line(call_id, tool, decision) that returns "<call_id> <tool> <decision>" and Audit with add(line) and count(decision) that counts lines ending in the decision.
Explain it without notes
Why do read tools and write tools need different treatment in a tool runner?
What is least privilege for a tool, with an example?
What is an idempotency key and why do tool loops need it?
Expected output
call_1 search_orders: {"orders":["A17"]}
asking the user: allow refund_order {"order_id":"A17","amount":20}?
call_2 refund_order: {"refunded":20,"order_id":"A17"}
asking the user: allow refund_order {"order_id":"A18","amount":15}?
call_3 refund_order: {"error":"the user declined this action"}
call_4 export_all_customers: {"error":"unknown tool"}
audit log:
call_1 search_orders read, ran without asking
call_2 refund_order approved by user
call_3 refund_order declined by user
call_4 export_all_customers refused (not registered)