tools bundles all five tools keyed by name:
API reference: Tools lists every built-in tool and helper, its options, and links to source and tests.
smthrs/tools subpath also exports lower-level helpers:
Sandboxing
Tools sandbox torootDir (default: workflow directory).
Tool call state
Smithers creates the_smithers_tool_calls table and exposes adapter methods to insert and list rows. The engine durably records the start of every defineTool() invocation before executing it, then reads those rows on retry to detect previously invoked non-idempotent side-effect tools. This start-first record is intentional: a process crash after the external side effect cannot erase the evidence needed for replay protection.
Each invocation receives a unique callToken. Completion and failure updates match only that token, so a late completion cannot overwrite a replacement row that reused the task key after time travel.
defineTool
defineTool() wraps custom AI SDK tools with Smithers runtime context, deterministic idempotency keys, side-effect metadata, and the side-effect snapshot hook.
ctx.idempotencyKeyis stable across retries and resumes for the same task iteration.sideEffect: trueopts the tool into side-effect tracking.idempotent: falsemarks the tool for retry warnings when a previous attempt has a recorded_smithers_tool_callsrow.- The engine persists the durable start row through the Smithers DB adapter before
executeruns.
Side Effects and Idempotency
Every custom tool that modifies external state must declaresideEffect: true; this is how Smithers protects your workflow during retries and resumes. Without it, Smithers treats the tool as a pure read and replays it freely: duplicate emails, double-charged payments, duplicate records.
The two flags work together:
With
sideEffect: true and idempotent: false, Smithers does two things on retry:
- Warns the agent. The retry prompt lists non-idempotent tools already called.
- Provides a stable idempotency key.
ctx.idempotencyKeyis deterministic per task + iteration; pass it to external APIs that support idempotency (Stripe, AWS) to deduplicate.
execute has sideEffect: true, idempotent: false but omits ctx, Smithers logs a startup warning: almost always a bug, since retries need ctx.idempotencyKey to be safe.
What counts as a side effect
If you cannot undo it withgit reset, mark it as a side effect.
A side effect is any mutation the runtime should not blindly repeat on retry: an external API call, a database write, a sent message, a triggered webhook.
The built-in write and edit tools are sideEffect: true, idempotent: false: their file mutations aren’t safe to blindly replay on retry, so like bash, all three built-in mutating tools are treated conservatively.
read
Read a file from the sandbox."File too large" if size exceeds maxOutputBytes.
write
Write content to a file. Creates parent directories as needed."ok"; throws "Content too large" if content exceeds maxOutputBytes. Logs content hash (SHA-256) and byte size, not full content.
edit
Apply a unified diff patch to an existing file."ok"; the file must exist. Reads, patches via applyPatch, writes back. Throws on size limits ("Patch too large", "File too large") or mismatched context ("Failed to apply patch"). Logs patch hash and byte size.
grep
Search for a regex pattern usingripgrep.
rg -n format). Exit 1 (no matches) returns empty string; exit 2 throws stderr as error. Requires ripgrep in PATH.
bash
Run an executable directly with arguments.args for arguments. If you need shell syntax such as pipes or redirects, invoke a shell explicitly, for example cmd: "sh", args: ["-lc", "..."].
Returns combined stdout and stderr; working directory defaults to rootDir. Timeout: 60s (killed with SIGKILL via process group). Non-zero exit codes throw.
Network Blocking
Controlled byallowNetwork in RunOptions, --allow-network on CLI, or server config. Default: blocked.
Blocked means no egress, not no sockets. Loopback stays reachable
(localhost, 127.0.0.0/8, ::1, 0.0.0.0, *.localhost, unix sockets),
so local test compositions (a dev server, a local postgres, a socket
simulator) run under the default.
When blocked, Smithers matches the invoked executable, arguments that are
themselves remote URLs, and git’s resolved subcommand. Argument text is never
scanned, so local commands that merely mention a network tool or a URL still
run: git commit -m "fetch upstream", echo "run npm install".
Local git commands (
git status, git diff, git log) are allowed. Denials
throw TOOL_NETWORK_DISABLED / TOOL_GIT_REMOTE_DISABLED with a message
naming the allowNetwork escape hatch.
Using Tools with Agents
Pass tools to an AI SDK agent and assign the agent to a<Task>: