Skip to main content
A tool is a named operation the agent can invoke. The model sees a description and an input schema; the Engine routes the call to the right implementation. This page is the reference for adding a custom tool, plus the design rules that keep tools usable.

The tool definition

A tool definition has three required fields and one optional one:

Implementation kinds

Platform

The tool is implemented in src/utility_directory/:
ref is the Python function name registered in platform_registry.py. Adding a new platform tool means writing the function, registering it, and exposing it in the catalog.

Skill

The tool is implemented as a skill — a prompt template plus optional helper scripts:
Skills are easier to add than platform tools because they’re data, not code. See Skills endpoints for how to create one.

MCP

The tool is exposed by a connected MCP server:
You don’t usually write these by hand. When a user connects an MCP server, the Engine auto-registers its actions.

Where tools live

Platform tools and skills are loaded from the catalog directory (CATALOG_DIR). Layout:
After editing the catalog, hot-reload with POST /admin/reload-catalog — no Engine restart needed. MCP tools are populated dynamically; they aren’t in the catalog.

Description rules

The description is the single most important field. The model uses it to decide when to call your tool.

Be specific

Name inputs and outputs

Hint when to use

Hint when not to use

This is what disambiguates similar tools. Without “do not use this for X” hints, the model picks the most prominent option.

Schema rules

Type every field

{"type": "string"} is the floor. Add format, pattern, minLength, maxLength, enum where they apply.

Use enums for closed sets

The model picks from the list. Without an enum, you’ll see “Medium” and “medium” inconsistently.

Mark required fields

The model treats unmarked fields as optional. Use required to express your contract.

Add description to every property

The description is documentation the model reads at call time:
A field without a description gets filled with whatever the model guesses.

Output

There’s no output_schema. Tools return a string (or a JSON-serializable object that the Engine stringifies). The schema for output is whatever your description says it is.

Keep output small

Tools that return huge blobs hurt:
  • They eat context, which costs money and slows the model down.
  • They survive compaction less gracefully.
  • They overwhelm the model’s attention.
Cap output at a few KB. If your underlying source returns more, summarize or chunk at the tool layer.

Structured output beats prose

The model parses JSON cleanly. Prose has to be re-parsed and is more ambiguous.

Errors

When the tool fails, return a structured error:
The Engine puts this in the tool_result.error field. The model can react — retry, switch tools, ask the user.

Versioning

Tools are part of the agent’s contract. Changing a tool’s name or schema is a breaking change. Patterns:
  • Adding a field. Backwards-compatible if it has a default.
  • Removing a field. Breaking. Add a new tool with the new schema; deprecate the old.
  • Renaming. Breaking. Treat as remove + add.
  • Changing semantics. Always breaking, even if the schema looks the same.
When you change a tool, run regression evals before merging.

Testing tools

Test tools against the agent, not just in isolation:
The integration test catches description problems (the model didn’t pick the tool because the description was unclear) that unit tests miss.

See also