Skip to content

zidane/tools

The built-in tools, the factories for shell, spawn, skills and interaction tools, and the ToolDef types.

import { … } from 'zidane/tools'src/tools/index.ts

Use zidane/tools to pick tools one by one instead of the basic preset, or to write your own. It holds the file tools (readFile, writeFile, edit, multiEdit, listFiles, glob, grep), shell with its background-task companions, the spawn factory and the ToolDef and ToolContext types. The web tools are in zidane/tools/web-search and zidane/tools/fetch-url. See Tools.

TypeScript
import { createAgent } from 'zidane'
import { anthropic } from 'zidane/providers/anthropic'
import { glob, grep, listFiles, readFile } from 'zidane/tools'

const agent = createAgent({
  provider: anthropic(),
  tools: { read_file: readFile, list_files: listFiles, glob, grep },
})

await agent.run({ prompt: 'Find where retries are configured and explain how.' })

Functions#

createGenerateImageToolFunction#

Build the generate_image tool.

createInteractionToolFunction#

Create an interaction tool that lets the agent request structured input.

The model calls this tool with a payload matching the schema. onRequest is called with the payload and should return the response (string or object) that gets sent back to the model as the tool result.

createModelSearchToolFunction#

Build the model_search tool over a spawn model catalog. Register it alongside createSpawnTool({ models }) — typically only when the catalog is too large to embed in the spawn schema, though it is harmless (and occasionally useful) alongside an embedded catalog too.

createShellToolFunction#

Creates the shell tool, which runs a command in the execution context, in the foreground or as a background task.

The default exported shell is equivalent to createShellTool({ allowBackground: true }). Hosts that use createAgent typically do not call this directly: when behavior.tasksDir is unset or behavior.disableBackgroundTasks: true is set, the agent rewrites the registered built-in shell using this factory.

Truncation is tail-priority: when stdout+stderr combined exceeds maxOutputBytes, the head is dropped and a marker …(N bytes truncated from head)… is inserted before the tail. Errors and exit summaries usually live at the end of output, so keeping the tail preserves the model's most useful signal. Commands that only explore (cat, sed -n, grep, ls, git log…) keep their start and end instead: what a read shows first is what it was run for.

The combined cap defaults to 32 KiB and the per-call timeout follows the execution context's own default (30 s for in-process).

Read-only commands run in parallel with other safe tool calls. Anything else runs alone.

createSkillsReadToolFunction#

Creates the skills_read tool, which reads a bundled resource file of an active skill. Unknown skill names are rejected at runtime.

createSkillsRunScriptToolFunction#

Creates the skills_run_script tool, which runs a script from an active skill's scripts/ directory in the execution context.

createSkillsUseToolFunction#

Factory for skills_use. Auto-injected into the agent's tool set by the agent runtime when a non-empty skills catalog is available (unless SkillsConfig.tool === false).

The name property carries no enum so the tool list stays byte-stable across catalogs; unknown names are rejected at runtime with the list of available skills.

createSpawnToolFunction#

Create a configured spawn tool.

State (children, totalChildStats, counters, active count) is scoped to the returned instance. Multiple parent agents using the same instance will share counters + stats + concurrency slots — call createSpawnTool() per agent (or use the stateless default spawn) to keep them isolated.

createToolSearchToolFunction#

Factory for tool_search. Auto-injected by the agent when behavior.toolDisclosure === 'lazy' and at least one MCP tool is in the registry. Opt out via behavior.toolSearch.tool === false.

formatModelLineFunction#

One display line per model: id, provider, real pricing, context window, reasoning flag. The single source of truth for how models render in BOTH the spawn schema's embedded catalog and model_search output, so the model never sees two spellings of the same entry.

getReadStateFunction#

Get or lazily create the per-session read-state map. Returns undefined when no session is provided.

Most tool callers should prefer resolveReadStateMap, which additionally honors an explicit ctx.readState (the path spawn's shareReadState: true uses to forward the parent's map into a sessionless child). Use this helper directly only when the Session-keyed map is exactly what you want and you don't need to accept an override.

hashContentFunction#

64-bit content hash: two independent 32-bit FNV-1a-style lanes (different offset bases + multipliers) concatenated as 16 hex chars. Fast, non-cryptographic — but wide enough that the requireReadBeforeEdit drift gate, which silently corrupts a file on a false "unchanged" verdict, isn't betting on a 32-bit birthday bound (~1 in 4 billion per pair; uncomfortably reachable over many files × many sessions). Entries live only in per-session in-memory maps, so widening needs no stored-format migration. Still cheaper than allocating a Buffer and pulling in crypto.

hydrateReadStateFromSessionFunction#

Rebuild the per-session read-state map from durable session turns.

Durable replay runtimes may return recorded tool results without re-running the tool body, so in-memory side effects like readState.set(...) can be missing even though the transcript contains the successful read_file. This helper is intentionally opt-in: live hosts keep the normal side-effect behavior unless they call it themselves.

Hydration only fills missing keys. Live in-memory state may already reflect a newer read or edit from the current run, and durable history cannot prove it is fresher. Relative paths are resolved against the current execution cwd, matching replay hosts that run sessions from a stable workspace.

hydrateReadStateFromSessionAsyncFunction#

Async replay hydrator for durable hosts that can cheaply read the current full file through their execution context. Transcript-only reconstruction is still preferred for full reads; partial/truncated read_file entries fall back to readFileForHash and hash those full current bytes.

isSpawnToolFunction#

Narrow a ToolDef to a SpawnTool (i.e. it exposes withSubagents). In its own module so callers can test a tool without loading the spawn tool.

matchModelEntriesFunction#

Case-insensitive multi-term filter across id, display name, and provider. Every whitespace-separated term must match somewhere (mirrors the TUI picker's filterModelCatalog semantics). Empty / whitespace queries pass everything through.

readStateKeyFunction#

Canonical read-state key for a (cwd, path) pair.

ctx.execution.readFile(handle, path) resolves the model-provided path against handle.cwd before touching disk — so src/App.tsx, ./src/App.tsx, and /abs/cwd/src/App.tsx all read the same bytes. The read-state map MUST mirror that resolution: without it, a model that reads src/App.tsx and then edits ./src/App.tsx trips the requireReadBeforeEdit gate for a file it demonstrably already saw (the gate's "has not been read in this session" message fires on a stale key).

node:path's resolve(cwd, path) short-circuits when path is already absolute, so absolute and relative shapes converge on the same canonical form. We don't realpath() symlinks — the file IS the path the model addressed, not the realpath behind it; the host's execution context decides how to dereference.

resolveReadStateMapFunction#

Resolve the active read-state map from a tool context. An explicit ctx.readState wins (used by spawn's shareReadState opt-in to forward the parent's map into a sessionless child); otherwise the usual Session-keyed lookup applies.

Tools should call this helper instead of getReadState(ctx.session) directly so the shareReadState plumbing is honored uniformly.

tailTruncateFunction#

Keep the last maxBytes UTF-8 bytes of text, dropping the head and prefixing a marker. A non-positive maxBytes disables truncation and returns text unchanged.

maxBytes budgets the kept tail only; the marker is added on top and may push the returned string slightly past maxBytes. That tradeoff is intentional — folding the marker into the budget would shrink the content actually shown. A leading run of U+FFFD (left by an upstream raw-byte slice that landed mid-codepoint) is stripped from the kept tail.

validateToolArgsFunction#

Validates a tool input against its JSON Schema and coerces values the model typed loosely, such as numeric strings. Items of arrays that cannot be coerced are dropped.

withIsolatedSpawnToolFunction#

Give a preset its own spawn tool state (see SpawnTool.isolated). Agent profiles are module constants holding ONE spawn instance, so a host that builds agents from them repeatedly (one per session in the chat host; one per activation / session switch in the TUI) must isolate at each build, or every agent shares one slot pool and child-label counter. Apply AFTER extension composition: its withSubagents rebuild keeps the shared state.

Constants#

DEFAULT_IMAGE_DIRConstant#

Folder for images saved without a path.

editConstant#

Surgical edit — replace old_string with new_string in a single file.

Mirrors Claude Code's Edit semantics so models post-trained on Anthropic's tool surface need no relearning. Fails clearly when old_string isn't unique (unless replace_all: true) and when not found, with a nearest-match preview so the model can recover without a separate read_file round-trip.

globConstant#

The glob tool. Lists files in the execution context that match a glob pattern.

Delegates matching to ExecutionContext.listFiles with { glob: true }. This keeps filesystem semantics inside the execution context (process / docker / sandbox) instead of reaching around it from the tool.

Results are capped at 1000 entries by default to keep model input bounded. The cap applies after the directory filter, so dirs don't consume the file budget.

Patterns are deliberately NOT confined to the workspace: like read_file, ../-prefixed patterns may match outside the cwd — the execution context is the sandbox boundary, not this tool.

By default, contexts that can cheaply provide metadata return <path>\t<size>\t<mtime> rows. Contexts without cheap metadata support return paths only. Pass metadata: false to request plain newline-separated paths.

grepConstant#

The grep tool. Searches file contents for regular expressions, using ripgrep when it is available and a JavaScript fallback otherwise.

Wraps ripgrep (rg) when available; when it's not, falls back to a regex search that enumerates files via the execution context's shell (find over exec) and reads them via ctx.execution.readFile. Both legs go through the ToolContext.execution seam, so the search runs wherever the context's files actually live — in-process, a container, or a remote sandbox — without the tool ever touching the host filesystem directly.

The tool surface mirrors Claude Code's Grep so models authored against the Anthropic tool surface need no relearning. Output modes:

  • files_with_matches (default) — newline-separated paths.
  • content — path:line:match (line numbers on by default).
  • count — path:N per matching file.

Results are capped via head_limit (default 250) to keep model input bounded; offset lets the caller page through. Pagination operates on OUTPUT LINES, not match groups — in content mode, context lines and -- separators consume the budget too (documented in the schema).

A line cap is not enough on its own: ripgrep is line-oriented, so a minified / single-line file collapses to ONE match line that is the entire file, and head_limit would happily return megabytes — enough to blow the model's context window. Output is therefore ALSO byte-bounded: each line is clipped to MAX_LINE_BYTES and the total to OUTPUT_BYTE_CAP, mirroring the byte discipline read_file already enforces.

path is deliberately NOT confined to the workspace: like read_file, absolute paths and ../ traversal are allowed — the execution context is the sandbox boundary, not this tool.

listFilesConstant#

The list_files tool. Lists the entries of one directory, capped at 1000 entries.

multiEditConstant#

The multi_edit tool. Applies a list of string replacements to one file in order, each on the output of the previous one. Best-effort, per-hunk semantics.

Each step replaces old_string with new_string against the file contents as left by the previous applied edit. A per-step failure (old_string not found, ambiguous match without replace_all, identical strings, malformed input) is recorded against THAT step only — the remaining steps still run. The file is written iff at least one step applied. The result text reports per-hunk outcomes inline and (when any step failed) carries an <edit-outcomes>…</edit-outcomes> annotation block so the chat layer

  • replay can paint per-hunk badges via parseEditOutcomesFromResult.

Per-hunk approval is a TUI/host concern. When the user partially denies a multi_edit from the file-edit modal, the gate handler rebinds ctx.input.edits to the approved subset before this tool runs — so the body sees a smaller all-approved batch and reports outcomes keyed against THAT subset. The host's tool:transform hook merges this subset-keyed result with the approval-side denied entries (1:1 with the model's ORIGINAL edits list) before the canonical <edit-outcomes> block lands on the wire — see mergeApprovalAndBodyOutcomes in chat/edit-approval.ts.

Wire / replay format (see parseEditOutcomesFromResult):

Text
Edited <path>: applied N of M edits (R replacements).
edit #2 failed: old_string not found in <path>.

<edit-outcomes>
#1 applied
#2 failed: old_string not found in <path>
#3 applied
</edit-outcomes>

The annotation is omitted entirely on the all-applied path — the renderer's isEditErrorResult check then suppresses the paired tool-result so the diff stands alone.

readFileConstant#

The read_file tool. Reads one file, or several files and ranges in one call, from the execution context, with line-based offset/limit and a hard byte cap.

Defaults are tuned for source code: 2000 lines / 256 KiB. A typical source file, lockfile, or large config fits in one read; logs and very large fixtures get truncated with a footer that documents how to fetch the remainder.

Binary files are detected on the leading characters of the decoded text — if the sample contains a NUL or a high proportion of U+FFFD replacement characters, we return a marker so the model doesn't drown in mojibake.

RECORD_ARTIFACT_TOOLConstant#

Name of the recordArtifact tool.

recordArtifactConstant#

The record_artifact tool. Records a pull request, branch, commit, file or custom artifact on the session.

shellConstant#

Default shell tool with background mode enabled.

Most hosts use this directly via basicTools. When the agent's behavior.tasksDir is unset OR behavior.disableBackgroundTasks: true is set, createAgent auto-rewrites this identity to a createShellTool({ allowBackground: false }) variant so the model never sees a flag it can't use. Hosts who want to bypass that auto-rewrite can register a createShellTool({ allowBackground }) directly — the rewrite only fires on identity-equal references to this constant.

shellKillConstant#

The shell_kill tool. Sends SIGTERM to a background shell task by task_id.

WAIT_TASK_TIMED_OUT_PREFIXConstant#

Stable prefix on the timed-out result. The agent's notification suppression keys on it: results carrying this prefix mean the task is still running, so the pending <task-notification> must survive.

waitTaskConstant#

The wait_task tool. Waits for a background shell task to exit and returns its final status. On timeout the task keeps running.

writeFileConstant#

Write a file, with an idempotency signal when the content is unchanged.

Three return shapes — chosen so the model can recognize a no-op without a separate read:

  • Created path (N bytes) — file did not exist
  • Updated path (N bytes) — content differed from on-disk
  • No change needed: path already at target state (N bytes) — equal

Race window: in non-process execution contexts (docker, sandbox) shared by multiple agents, another writer can mutate the file between our read and our write. Local process context is single-writer per agent so the race is a non-issue there. Documented rather than locked because the cost of cross-context locking outweighs the cost of a stale "No change" message.

Interfaces#

ChildAgentInterface#

A running child agent started by the spawn tool.

CreateShellToolOptionsInterface#

Options for createShellTool.

ExtensionSubagentDefInterface#

A subagent def carried by an extension's registerSubagent — same as SubagentDef but carrying its own dispatch name (the registry key). Self-describing so the def survives the trip from extension setup through the merged ExtensionRegistry to the host's SpawnTool.withSubagents merge.

GenerateImageToolOptionsInterface#

Options for createGenerateImageTool.

HydrateReadStateOptionsInterface#

ImageModelSourceInterface#

A provider the tool can generate with.

InteractionToolOptionsInterface#

Options for createInteractionTool.

LazyToolEntryInterface#

A tool the model can discover through tool_search and unlock on demand.

ReadStateEntryInterface#

What the last read_file of a file returned, kept to deduplicate re-reads and to detect changes before an edit.

SkillsReadToolOptionsInterface#

Options for createSkillsReadTool.

SkillsRunScriptToolOptionsInterface#

Options for createSkillsRunScriptTool.

SkillsUseToolOptionsInterface#

Options for createSkillsUseTool.

SpawnModelEntryInterface#

A ModelInfo paired with the runtime Provider.name that serves it. provider must match a Provider.name available to the run (the primary or a fallback-chain provider — see ToolContext.providers); the spawn tool routes the child agent to that instance.

SpawnTaskInputInterface#

Input accepted by SpawnTool.runTask — the typed mirror of the execute schema. Fields beyond task only take effect when the tool was built with the matching capability (a subagent registry for subagent_type, a model catalog for model).

SpawnTaskOutcomeInterface#

Structured outcome of one spawned child run — the host-facing shape behind SpawnTool.runTask. message is the exact model-facing string execute returns (header + stats + response), while text is the child's bare final response so hosts don't have to parse the formatted message.

SpawnToolInterface#

The object createSpawnTool returns: a ToolDef that also exposes live SpawnToolState plus SpawnTool.withSubagents for rebuilding the tool against a merged subagent registry (the seam the extension system uses to add / edit spawnable subagents).

SpawnToolOptionsInterface#

Options for createSpawnTool.

SpawnToolStateInterface#

Read-only view of the children a spawn tool instance has run.

SubagentDefInterface#

Per-type subagent override applied when the model calls spawn({ subagent_type: '…' }). All fields are optional; absent fields fall back to the parent's resolved configuration (see SpawnToolOptions comments for the merge order).

TailTruncateOptionsInterface#

Options for tailTruncate.

ToolContextInterface#

Runtime context passed to every tool execution. Provides access to the agent's provider, abort signal, execution environment, and hooks.

The preset-y fields (name, system, tools, toolAliases, toolDescriptions, mcpServers, skills, behavior) mirror the agent's own options so child-spawning tools can inherit them.

ToolDefInterface#

A tool the agent can call: its spec and its execute function, plus scheduling hints.

ToolDescriptionTargetInterface#

What a ToolDescriptionOverride function receives alongside the current description: the canonical name, the spec as the framework built it (after every built-in rewrite), and the owning MCP server when the tool was discovered from one.

ToolSearchToolOptionsInterface#

Options for createToolSearchTool.

ValidationResultInterface#

Result of validateToolArgs.

Types#

ReadStateMapType#

Read-state entries keyed by readStateKey.

SubagentOverrideType#

Editing function for an existing subagent. Receives the current def (host- or extension-provided; undefined when the name is unknown) and returns the replacement — or undefined to delete the entry.

SubagentRegistryType#

Map of subagent-type key → preset. Keys are case-sensitive and appear verbatim in the spawn input schema's enum so the model emits them with the same casing. Common conventions: 'Explore', 'Plan', 'Verification', 'general-purpose' (Claude Code SDK's built-in set).

ToolDescriptionOverrideType#

One entry of AgentOptions.toolDescriptions. A string replaces the description wholesale; a function receives the current text and returns the new one — the form to reach for when amending, since it keeps any framework-generated prose (e.g. shell's background-mode gate and "prefer the dedicated tool" block) intact.

ToolDescriptionsType#

Canonical-name-keyed record of ToolDescriptionOverrides.

ToolMapType#

Tools keyed by name.

Re-exports#

These names are documented on the entry point that owns them.