Skip to main content
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.
The smithers-orchestrator/tools subpath also exports lower-level helpers for advanced integrations:

Sandboxing

All tools are sandboxed to rootDir (defaults to the workflow directory). Paths are resolved relative to this root; escapes via symlinks are rejected.

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.

defineTool

defineTool() wraps custom AI SDK tools with Smithers runtime context, deterministic idempotency keys, side-effect metadata, and the side-effect snapshot hook.
  • ctx.idempotencyKey is stable across retries and resumes for the same task iteration.
  • sideEffect: true opts the tool into Smithers side-effect tracking.
  • idempotent: false marks the tool for retry warnings when a previous attempt has a recorded _smithers_tool_calls row.
  • The engine persists the durable start row through the Smithers DB adapter before execute runs.

Side Effects and Idempotency

Every custom tool that modifies external state must declare sideEffect: 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, potentially sending duplicate emails, double-charging payments, or creating duplicate records. The two flags work together: With sideEffect: true and idempotent: false, Smithers does two things on retry:
  1. Warns the agent. The retry prompt lists which non-idempotent tools were already called.
  2. Provides a stable idempotency key. ctx.idempotencyKey is deterministic for a given task + iteration; pass it to external APIs that support idempotency (Stripe, AWS) to deduplicate.
If your execute function has sideEffect: true, idempotent: false but omits the ctx parameter, Smithers logs a startup warning. This is almost always a bug: you need ctx.idempotencyKey to handle retries safely.

What counts as a side effect

The rule is simple: if you cannot undo it with git reset, mark it as a side effect. A side effect is any mutation the runtime should not blindly repeat on retry. If a custom tool talks to an external API, writes to a database, sends a message, or triggers a webhook, mark it. The built-in write and edit tools are registered as sideEffect: true and idempotent: false because their file mutations are not safe to blindly replay on retry; like bash, they are treated conservatively. All three built-in mutating tools (write, edit, bash) are side-effecting.

read

Read a file from the sandbox.
Returns file contents as UTF-8. Throws "File too large" if size exceeds maxOutputBytes.

write

Write content to a file. Creates parent directories as needed.
Returns "ok". Throws "Content too large" if content exceeds maxOutputBytes. Logs content hash (SHA-256) and byte size; full content is not stored.

edit

Apply a unified diff patch to an existing file.
Returns "ok". The file must exist. Reads current contents, applies the patch 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 using ripgrep.
Returns matching lines with file paths and line numbers (rg -n format). Exit code 1 (no matches) returns empty string. Exit code 2 throws stderr as error. Requires ripgrep in PATH.

bash

Run an executable directly with arguments.
Use 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 by allowNetwork in RunOptions, --allow-network on CLI, or server config. Default: blocked. When blocked, Smithers tokenizes cmd plus args. Executable basenames are matched for known network tools, URL tokens are blocked by prefix, and git plus a remote-operation token is blocked. Local git commands (git status, git diff, git log) are allowed.
Enforcement vs. bypassable denylist. 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 degrades to the token/basename denylist in the table 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. Run untrusted workloads under a real <Sandbox> provider with egress controls instead.

Using Tools with Agents

Pass tools to an AI SDK agent and assign the agent to a <Task>:
The full bundle works too:

Configuration

See Also