name, its description, and its json_schema. Everything about whether a
tool gets called at the right moment, with the right values, is decided by
those three fields.
Treat them as prompt engineering, not as bookkeeping.
name
The function name the model is shown. It must match
^[a-zA-Z_][a-zA-Z0-9_]*$ — a save with anything else is rejected — and it must
be unique in the workspace. Use snake_case and name the capability, not the
implementation: book_appointment, not post_booking_v2.
Three names are reserved by the platform, because the runtime injects tools
under them: knowledge_fetch, stop_recording and submit_result. Creating a
tool with one of those returns 400 '<name>' is reserved by the platform.
description
The description tells the model when to call the tool. This matters as much
as the implementation: a correct tool that fires at the wrong moment is worse
than no tool.
Write the conditions, including the ones that should stop it firing.
Weak:
json_schema
The arguments the model fills in. Two rules do most of the work.
Declare only values the agent can know or ask the caller for. An internal
account UUID is not one of them: the model will invent a plausible-looking one.
Take the order number the caller can read out, and look the UUID up inside the
tree.
Give every property a description. It is the only instruction the model
gets on what to put in that field and how to get it out of the conversation. A
bare {"type": "string"} is how a tool ends up called with “next Tuesday” where
it needed 2026-09-01.
Then: mark as required only what the tool genuinely cannot run without —
everything marked required is something the model will invent a value for rather
than leave out — and use enum wherever the set of values is closed, so
gold, Gold and gold tier cannot all reach your API.
json_schema is replaced wholesale:
Which JSON Schema is accepted
The schema is checked against JSON Schema Draft 2020-12, and the whole vocabulary of that draft is accepted —enum, required, minimum,
maxLength, pattern, format, items, nested properties, $defs,
anyOf. Nothing is stripped on the way in.
Three rules on top of the draft:
One convenience: a schema with no top-level
type is read as an object, so
{"properties": { … }, "required": [ … ]} is accepted and means the same thing
as writing "type": "object" yourself. An empty {} means the tool takes no
arguments.
Two things about how the schema is used:
{{args.NAME}}is checked against the top-levelpropertieskeys only. A nested value is read with dots at runtime —{{args.address.city}}— and validation checksaddressis declared, notcity.- The model’s arguments are validated against the same schema before the tree
runs. A call that violates it never reaches your endpoints; the tool fails
with
Tool arguments are invalid at <path>: <message>and the model is handed that sentence.
Common mistakes
Next
The operation tree
What runs once the model has called the tool.
Templating and data
Reading
{{args.…}} and moving values between operations.