Tools
Built-in tools, background tasks and human-in-the-loop input.
A tool is a typed definition (ToolDef) that the model can call. This page lists the built-in tools and shows how to rename them, run shell commands in the background and ask a human for input. MCP servers add more tools.
Built-in tools#
The basic preset (zidane/presets) has:
| Tool | Behavior |
|---|---|
shell | Combined stdout and stderr, capped at 32 KiB. Past the cap, commands that only read, search, list or run read-only git, in every stage of a pipe, keep the start and the end of the output. Other commands keep the end, with a …(N bytes truncated from head)… marker. maxOutputBytes: 0 turns off the cap. |
shell_kill, wait_task | Stop a background task, or wait for it to exit. The agent registers them only when background tasks are on. |
read_file | Line range, default 2000 lines, 256 KiB cap. Paging footer, binary marker. |
write_file | Returns Created, Updated or No change needed: …. |
edit | old_string to new_string. Errors on non-unique or missing matches, with a nearest-match preview. |
multi_edit | Several edits to one file, in order. A failed edit does not stop the others. The file is written when at least one edit applied, and the result lists each edit as applied or failed. |
list_files | Directory listing. |
spawn | Sub-agent delegation (Sub-agents). The basic preset sets persist: true. |
basicTools is the same set without spawn:
import { basicTools, definePreset } from 'zidane/presets'
createAgent({ ...definePreset({ name: 'researcher', tools: basicTools }), provider })Opt-in tools:
| Tool | Import | Notes |
|---|---|---|
glob | zidane | Matches through the execution context (process, Docker, sandbox). It skips git-ignored files by default and returns 1000 results at most. |
grep | zidane | ripgrep, with a fallback when rg is missing. The input follows Claude Code's Grep and adds patterns, paths, globs and exclude. A ! glob skips files (!*.lock). A missing root among several is skipped with a note. head_limit defaults to 250 lines. |
createInteractionTool | zidane | Human-in-the-loop factory (below). |
todowrite / todoread | createTodoTools from zidane/chat | Task checkpoints that persist across prompts. |
skills_use, skills_read, skills_run_script | added for you | Injected once the skills catalog is non-empty (Skills). |
web_search, fetch_url | zidane/tools/web-search, zidane/tools/fetch-url | Search the web and read a page. behavior.fetchUrlAllowHosts limits the hosts. |
createGenerateImageTool | zidane | Generates images with the run's image models and saves them in the workspace (Images). |
record_artifact | recordArtifact from zidane/tools | The model marks a deliverable (a PR, a branch, a deployment) so it shows as a session artifact. |
codemode | behavior.codemode: true | The model writes one short script that calls the other tools. The script runs in a sandbox (reference). |
Tools the apps add#
In the terminal and desktop apps, each session gets the tools of its agent profile. The Build and Codemode profiles have the basic tools plus glob, grep, web_search and fetch_url. The Plan profile has only read_file, list_files, glob, grep, web_search and fetch_url. Plan shares Build's agent: the request keeps Build's tool list, and a gate refuses the tools Plan does not have (profiles). The apps then add these tools:
| Tool | When the agent has it |
|---|---|
todowrite, todoread | In the Build and Codemode profiles |
present_plan, ask_user | Unless the setting Interaction mode is Disable tools (approvals) |
read_chat_turns | Always. It reads only the chats that the current prompt mentions with #. |
record_artifact | The setting Artifacts is on (the default) |
model_search | The setting Allow subagents to use different models is on and the profile has a spawn tool (sub-agents) |
generate_image | The setting Image generation is on (the default) and a connected provider can generate images (Images) |
tool_search, call_tool | MCP tools load on demand (MCP). call_tool only while the setting Stable tool list (call_tool) is on, the default. |
codemode | The setting Codemode is on |
browser_* | Desktop app, while the settings Browser tab and Agent can use the browser are on |
terminal_list, terminal_read, terminal_write | Desktop app, while the settings Terminals and Agent can use your terminals are on and a window shows terminals. Needs the daemon. |
sessions | The Main session only, with the setting Main session on |
A /side session gets only the Plan tools and read_parent_session. The apps add none of the tools above to it.
Aliasing and descriptions#
toolAliases changes the name the model sees:
createAgent({ provider, tools: { shell }, toolAliases: { shell: 'Bash' } })toolDescriptions overrides any description, native or MCP, with a string or a function of the current one:
createAgent({
provider,
toolDescriptions: {
shell: cur => `${cur}\nNever invoke sudo.`,
mcp_github_create_pull_request: 'Open a PR. Always target `develop`.',
},
})Background tasks#
With run_in_background: true, shell returns a bash_<n> handle at once. Output goes to a log file that the model reads with read_file. shell_kill stops the task. wait_task blocks until the task exits. When a task finishes, the next turn gets a <task-notification> block, so the model does not have to poll.
Set a log directory to turn it on:
import { createAgent, resolveTasksDir } from 'zidane'
const tasksDir = resolveTasksDir({ userDir: '/var/lib/my-agent', sessionId: session.id })
const agent = createAgent({
provider,
session,
behavior: { tasksDir }, // required
})The built-in shell hides run_in_background from the model, and the agent does not register shell_kill and wait_task, in each of these cases:
behavior.tasksDiris unset.behavior.disableBackgroundTasksistrue.behavior.disableBackgroundTasksis'non-durable'and the detached tasks of the context are not durable.- The context cannot detach tasks.
The full lifecycle is in docs/RUN_IN_BACKGROUND.md.
agent.destroy() sends SIGTERM to each task's process group and flushes its log before tearing down the execution handle.
Interaction tool#
createInteractionTool pauses the agent until onRequest returns the structured input of a human. It takes schema, onRequest and an optional name and description. No preset includes it. The apps have their own ask_user and present_plan (approvals).
import { createInteractionTool } from 'zidane'
const askUser = createInteractionTool({
name: 'ask_user',
schema: { type: 'object', properties: { question: { type: 'string' } }, required: ['question'] },
onRequest: async ({ question }) => ({ answer: await promptUser(question) }),
})
createAgent({ provider, tools: { ...basicTools, ask_user: askUser } })Calls a crash cut off#
ToolDef.replay says what a durable run does with a call of the tool that a process death left unfinished. 'safe' runs it again, for reads with no side effect. 'unsafe' (the default) reports it to the model as interrupted. See safe and unsafe tools.
Related#
| Topic | Page |
|---|---|
steer, followUp, abort, cancelTool | Agents |
Concurrency, dedupTools, toolBudgets, repeatGuard | Hooks |
| Gate, rewrite and observe tool calls | Hooks |