Skip to main content
A tool is an AI SDK tool an agent may call. defineTool wraps one with Smithers runtime context: a deterministic idempotency key, side-effect metadata, and the side-effect snapshot hook. The five built-in tools (read, write, edit, grep, bash) are themselves defineTool results and run inside the task’s sandbox.

defineTool

Wrap a Zod-validated execute function into a durable AI SDK tool. Pass the result to an agent’s tools or a <Task>’s tools prop.
name
string
required
Tool name surfaced to the agent and stamped onto ctx.toolName. Also the default description.
description
string
Human-readable description the agent sees. Defaults to name.
schema
ZodType
required
Zod schema for the tool’s input. Validated by the AI SDK before execute runs; execute receives the parsed args.
sideEffect
boolean
default:"false"
Marks the tool as mutating external state. Opts the tool into Smithers side-effect tracking and runs the durability snapshot hook after execute.
idempotent
boolean
default:"!sideEffect"
Whether re-running with the same input is safe. Defaults to true when sideEffect is false. With sideEffect: true, idempotent: false, retries inject a warning that the tool was already called so the agent can verify external state first.
execute
(args, ctx) => Promise<unknown>
required
Runs the tool. args is the parsed input; ctx is the tool context. If sideEffect: true, idempotent: false and execute omits the second ctx parameter, Smithers logs a startup warning, since you almost certainly need ctx.idempotencyKey to handle retries safely.
Tool
object
An AI SDK tool with attached Smithers metadata. Read the metadata with getDefinedToolMetadata.
The sideEffect / idempotent pair drives retry behavior: The rule: if you cannot undo it with git reset, mark it sideEffect: true. Source defineTool.js · context.js · Tests tools-unit.test.js, define-tool-durability.test.js · See also Built-in Tools, SDK agents

getDefinedToolMetadata

Read the Smithers metadata attached by defineTool. Returns null for plain AI SDK tools or non-objects.
value
unknown
required
A tool (or any value). Inspected for the Symbol.for("smithers.tool.metadata") property.
metadata
object | null
Source defineTool.js · Tests tools-unit.test.js · See also defineTool

Built-in tools

Five defineTool results, all sandboxed to ctx.rootDir (the workflow directory by default). Paths resolve against the root; symlink escapes are rejected. Output is truncated to ctx.maxOutputBytes (200KB). Import them individually or as the tools bundle:

read

Read a UTF-8 file from the sandbox.
path
string
required
File path, relative to rootDir or absolute within it.
Returns the file contents. Throws if the file exceeds maxOutputBytes.

write

Write content to a file, creating parent directories as needed.
path
string
required
Destination path, relative to rootDir or absolute within it.
content
string
required
File contents.
Returns "ok". Throws TOOL_CONTENT_TOO_LARGE if content exceeds maxOutputBytes; only the content’s byte size and SHA-256 hash are logged, never the content itself.

edit

Apply a unified-diff patch to an existing file.
path
string
required
File to patch. Must already exist.
patch
string
required
A unified diff. Applied against the current contents.
Returns "ok". Throws TOOL_PATCH_TOO_LARGE (patch over maxOutputBytes) or TOOL_PATCH_FAILED (the patch context does not match the file).

grep

Search for a pattern with ripgrep (rg -n). Requires rg on PATH.
pattern
string
required
Regex to search for.
path
string
default:"."
Directory or file to search, relative to rootDir.
Returns matching lines as file:line:text. No matches returns an empty string; an rg error (exit code 2) throws TOOL_GREP_FAILED.

bash

Run an executable with arguments. There is no shell parsing: pass arguments via args, and for pipes or redirects invoke a shell explicitly, e.g. { cmd: "sh", args: ["-lc", "..."] }.
cmd
string
required
Executable name or path. Up to 8,192 characters.
args
string[]
Arguments. Up to 128 entries, each up to 8,192 characters.
opts
{ cwd?: string }
cwd sets the working directory (sandboxed under rootDir). Defaults to rootDir.
Returns combined stdout and stderr, truncated to maxOutputBytes. A non-zero exit code throws TOOL_COMMAND_FAILED. The process is killed with SIGKILL after ctx.timeoutMs (default 60s; the hard cap is one hour).
Network is blocked unless allowNetwork is enabled (via RunOptions, --allow-network, or server config). When blocked, Smithers rejects commands whose executable basename is curl, wget, npm, bun, or pip, any token beginning with http:// or https://, and git together with a push, pull, fetch, clone, or remote token (throwing TOOL_NETWORK_DISABLED or TOOL_GIT_REMOTE_DISABLED). Local git commands such as git status are allowed.
This denylist is not isolation on Linux. True OS-level network isolation is enforced only on macOS, where a blocked bash runs under sandbox-exec with a network-deny profile (when sandbox-exec is available). On Linux and every other platform, including the environments Smithers runs in for CI, cloud, and production, allowNetwork:false cannot enforce a kernel sandbox and falls back to the token/basename denylist above. That denylist is best-effort defense-in-depth, not a security boundary: it is trivially bypassable by a shell, an interpreter (python -c assembling a URL from parts, bash /dev/tcp), or a renamed binary. When isolation is unenforced, Smithers logs a TOOL_NETWORK_ISOLATION_UNENFORCED observability warning. Do not rely on allowNetwork:false to sandbox untrusted code. For untrusted workloads, run them under a real <Sandbox> provider with egress controls instead.
Source tools/index.js · bash.js, read.js, write.js, edit.js, grep.js · Tests tools-unit.test.js · See also Built-in Tools, Common External Tools, SDK agents