RUNTIME / BUILT-IN TOOLS

Small tools with hard edges.

The default coding tools expose common repository operations directly. Their schemas and outputs are bounded so the model can work in smaller, inspectable steps.

The built-in set

ToolPurpose
readRead a text file with 1-based line numbers and paging.
listList a directory tree with depth and output limits.
globFind files by name or path pattern: *, **, ?, {a,b}.
grepSearch file contents and return capped path:line matches.
editApply an exact replacement to a file.
writeCreate or replace a text file.
bashRun a shell command with a timeout; included by default.
recallSearch this project's memory. Read-only, and CLI-registered.

The filesystem environment roots paths to the selected workspace and rejects paths that escape it. Grep and glob walk the workspace in-process and do not require ripgrep.

Why glob exists

Discovery by name pattern is the primitive that keeps an agent from guessing paths or walking a tree level by level. It skips straight to the pattern's literal prefix, so a rooted pattern never traverses the rest of the repository.

tsnah
glob { pattern: "**/page.tsx" }
glob { pattern: "apps/*/src/**/*.tsx" }
glob { pattern: "**/*.{test,spec}.ts" }
grep { pattern: "DocsShell", path: "apps/nah/**/*.tsx" }

grep accepts a glob in path too, which is usually the fastest way to find the code that references something. Both skip node_modules, .git and build output; pass includeHidden to opt back into dotfiles.

glob is registered automatically when the environment implements it, and can be turned off with withGlob: false.

Approval gates

Read-only tools — read, list, grep, glob — are never gated. Mutating tools (edit, write, bash) can be wrapped with an approval callback. If no callback is provided to the SDK, those calls are allowed.

tsnah
const tools = createCodingTools(environment, {
  withBash: false,
  requireReadBeforeWrite: true,
  approveToolCall: async (toolName, input) => {
    return await askUserToApprove(toolName, input);
  },
});

“Always allow” is scoped to the tool for the session. Scoping it to the exact command string meant the agent asked again for every slightly different invocation, which read as the choice not being remembered at all.

Shell behaviour

Commands run with the workspace root as their working directory and a timeout, and the whole process group is killed on timeout so no backgrounded child survives.

textnah
stdin is closed for the command, never an open pipe

Output caps and boundaries

Tool outputs are capped by the package defaults so large files and broad searches cannot overwhelm the conversation. Reads page with offsets and limits; listing, grep and glob are bounded too. Check DEFAULT_CAPS if your integration needs those limits.

Repeated identical tool calls collapse in the transcript to a single line with a tally, and successful read-only results are not echoed — the call itself already says what happened.

Bring your own tools

runAgent accepts any AI SDK v5 tool map. Use the built-ins as a starting point, or supply your own to limit capabilities or connect another execution backend.