Skip to content

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:

ToolBehavior
shellCombined 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_taskStop a background task, or wait for it to exit. The agent registers them only when background tasks are on.
read_fileLine range, default 2000 lines, 256 KiB cap. Paging footer, binary marker.
write_fileReturns Created, Updated or No change needed: ….
editold_string to new_string. Errors on non-unique or missing matches, with a nearest-match preview.
multi_editSeveral 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_filesDirectory listing.
spawnSub-agent delegation (Sub-agents). The basic preset sets persist: true.

basicTools is the same set without spawn:

TypeScript
import { basicTools, definePreset } from 'zidane/presets'

createAgent({ ...definePreset({ name: 'researcher', tools: basicTools }), provider })

Opt-in tools:

ToolImportNotes
globzidaneMatches through the execution context (process, Docker, sandbox). It skips git-ignored files by default and returns 1000 results at most.
grepzidaneripgrep, 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.
createInteractionToolzidaneHuman-in-the-loop factory (below).
todowrite / todoreadcreateTodoTools from zidane/chatTask checkpoints that persist across prompts.
skills_use, skills_read, skills_run_scriptadded for youInjected once the skills catalog is non-empty (Skills).
web_search, fetch_urlzidane/tools/web-search, zidane/tools/fetch-urlSearch the web and read a page. behavior.fetchUrlAllowHosts limits the hosts.
createGenerateImageToolzidaneGenerates images with the run's image models and saves them in the workspace (Images).
record_artifactrecordArtifact from zidane/toolsThe model marks a deliverable (a PR, a branch, a deployment) so it shows as a session artifact.
codemodebehavior.codemode: trueThe 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:

ToolWhen the agent has it
todowrite, todoreadIn the Build and Codemode profiles
present_plan, ask_userUnless the setting Interaction mode is Disable tools (approvals)
read_chat_turnsAlways. It reads only the chats that the current prompt mentions with #.
record_artifactThe setting Artifacts is on (the default)
model_searchThe setting Allow subagents to use different models is on and the profile has a spawn tool (sub-agents)
generate_imageThe setting Image generation is on (the default) and a connected provider can generate images (Images)
tool_search, call_toolMCP tools load on demand (MCP). call_tool only while the setting Stable tool list (call_tool) is on, the default.
codemodeThe 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_writeDesktop app, while the settings Terminals and Agent can use your terminals are on and a window shows terminals. Needs the daemon.
sessionsThe 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:

TypeScript
createAgent({ provider, tools: { shell }, toolAliases: { shell: 'Bash' } })

toolDescriptions overrides any description, native or MCP, with a string or a function of the current one:

TypeScript
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:

TypeScript
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.tasksDir is unset.
  • behavior.disableBackgroundTasks is true.
  • behavior.disableBackgroundTasks is '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).

TypeScript
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.

TopicPage
steer, followUp, abort, cancelToolAgents
Concurrency, dedupTools, toolBudgets, repeatGuardHooks
Gate, rewrite and observe tool callsHooks

Reference#