Custom tools
Declare a [[tools]] table in your config and it becomes a tool the model can call.
{arg} placeholders are filled from the call and shell-quoted, and the whole thing runs
through the same approval and shell path as run_command.
[[tools]]name = "typecheck"description = "Type-check the project and report errors."command = "npm run -s typecheck"mutating = false
[[tools]]name = "grep_todos"description = "Find TODO comments matching a term."command = "rg -n 'TODO.*{term}' ."args = ["term"]The fields
Section titled “The fields”| Field | Required | What it does |
|---|---|---|
name |
yes | What the model calls. Keep it a verb or a noun phrase the model would guess. |
description |
yes | The only thing the model reads when deciding whether to use it. Say what it does and when. |
command |
yes | The shell command. {arg} placeholders are substituted and shell-quoted. |
args |
no | Names of the placeholders, in the order the model should supply them. |
mutating |
no | true makes it approval-gated like a write. Defaults to asking. |
Writing a good description
Section titled “Writing a good description”The description is the entire interface. A model choosing between search and your
grep_todos has nothing else to go on, so name the situation, not just the action:
description = "Find TODO comments matching a term. Use this instead of search when the user asks about outstanding work."Where they are and are not offered
Section titled “Where they are and are not offered”Custom tools go to the top-level agent only — never to a subagent, and never in plan mode. A subagent is a read-only investigator with its own context; giving it project-specific shell commands is how a “just go look at this” turn ends up running your migration.
Placeholders are quoted, not interpolated
Section titled “Placeholders are quoted, not interpolated”{term} is shell-quoted before substitution, so a model that supplies
foo"; rm -rf /; echo " produces a search for that literal string rather than three
commands. That is the whole safety property — the command shape is yours, and only the
arguments come from the model.
Still: a custom tool is a command you have pre-approved the shape of. Give it the narrowest command that does the job.
The full extension guide — custom tools, skills and role agents together — is in
docs/extensions.md.