Module · M3 · Give it hands, and meet the problem
Pinned fields vs {{ai}} slots
Lesson 9 of 21 · 8 min
A tool has fields. Some of them you want the agent to fill — it is the only thing that knows what the customer asked. Others you want fixed for all time, because they decide what the tool touches.
So you pin the dangerous ones and leave the rest as slots. Here is a tool from the flawed build, exactly as configured:
The refund tool, as the builder configured it
Pinned to create a payment on a deal. The only agent-filled field is the payload.
Scroll for all 5 steps →
Read the account tool: pinned to search, pinned to deal. It looks locked down. Now here is what the agent actually did with it, across two runs:
| What the config said | What the agent sent | What the node did |
|---|---|---|
entity_type: deal | "company" | searched companies |
operation: search | "get" | fetched a record by id |
operation: search | "create" plus a payload | created a note — a read-only tool performed a write |
entity_type: deal
- What the agent sent
"company"- What the node did
- searched companies
operation: search
- What the agent sent
"get"- What the node did
- fetched a record by id
operation: search
- What the agent sent
"create"plus a payload- What the node did
- created a note — a read-only tool performed a write
It is worse than “advisory”. In another build a database tool had its entire SQL statement pinned, with no agent-fillable slot anywhere in it. The agent replaced the whole statement with invented SQL against tables that do not exist — twice. The only thing that stopped it was the database’s own table allow-list. A tool with zero fillable fields still had its configuration overwritten.
Why, and the one line that fixes it
A tool’s exposure mode defaults to open. In that mode the model is handed the node’s entire configuration schema as fillable parameters, and is given no signal that anything was pinned. When its arguments arrive, the node merges them over your configuration rather than reserving your keys — so the model’s value wins.
- id: account_lookup
node: database_query
tool_exposure: configured # ← without this line, nothing below is pinned
query_mode: read
query: |
SELECT … FROM deals d
WHERE d.name ILIKE '%' || {{ai:account}} || '%'Verified both ways. With the line, the same agent called the same tool with {} — nothing to fill — and the pinned query ran exactly as written. Every tool in every finished build in this course sets it.
What a slot is for
Once exposure is set, a {{ai}} slot means what it appears to mean, and the design question becomes worth asking properly. Compare:
| “The agent may send a message.” | “The agent may choose the recipient, the template and the amount.” |
|---|---|
| One tool, three pins, one slot: it writes the body and nothing else. | One tool, no pins: it decides who, what and how much. |
One tool, three pins, one slot: it writes the body and nothing else.
- “The agent may choose the recipient, the template and the amount.”
- One tool, no pins: it decides who, what and how much.
And the boundary that needs no configuration at all: the tool you did not attach. A pin is a strong default once exposure is set correctly, and a default is still a thing a future colleague can loosen in the builder in ten seconds. Absence is the only control in this lesson that cannot be undone by a setting.

