Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vercel/eve/llms.txt

Use this file to discover all available pages before exploring further.

A tool is a typed action the agent can call: hitting an API, running a query, reading a database, or triggering a workflow. The implementation lives in your code, runs in your app runtime with full access to process.env, and is never exposed to the sandbox. The file path under agent/tools/ determines the tool name the model sees — no registration step required.

Defining a tool

Create a file under agent/tools/. The filename slug (without the .ts extension) becomes the model-facing tool name. A file at agent/tools/get_weather.ts is exposed as get_weather.
agent/tools/get_weather.ts
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
  description: "Get the current weather for a city.",
  inputSchema: z.object({ city: z.string().min(1) }),
  async execute({ city }, ctx) {
    return { city, condition: "Sunny", temperatureF: 72 };
  },
});
Every tool definition needs:
  • A filename slug under agent/tools/ — this is the model-facing name. Use snake_case.
  • description — what the tool does, written for the model, not for humans.
  • inputSchema — a Zod schema, any Standard Schema, or a plain JSON Schema object. Required. For no input, pass z.object({}). Zod and Standard Schema infer the input type in execute. Plain JSON Schema types it as Record<string, unknown>.
  • execute(input, ctx) — the implementation. May be sync or async.
For tools that return structured data, add an optional outputSchema. With Zod or Standard Schema it also types the execute return value.

The ctx parameter

The second argument to execute is a context object carrying runtime accessors:
AccessorDescription
ctx.sessionSession metadata: turn number, auth, parent lineage.
ctx.getSandbox()Returns a live sandbox handle. Async. Only works inside authored runtime execution.
ctx.getSkill(id)Returns a packaged skill’s metadata and file handle. Read skill files from authored tools.
ctx.getToken(provider)Resolve a bearer token for an inline auth provider. Use for tools that call OAuth-protected services.
ctx.requireAuth(provider)Evict and re-authorize an inline provider. Call after a downstream 401 rejects a token from ctx.getToken.
Running in the app runtime is what lets a tool import shared code from lib/, read process.env, and take part in eve’s durable pause/resume model.
agent/tools/run_analysis.ts
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
  description: "Run a Python analysis script and return its output.",
  inputSchema: z.object({ script: z.string() }),
  async execute({ script }, ctx) {
    const sandbox = await ctx.getSandbox();
    await sandbox.writeTextFile({ path: "analysis/run.py", content: script });
    const result = await sandbox.run({ command: "python analysis/run.py" });
    return { stdout: result.stdout };
  },
});

Tool execution and replay

eve never runs authored tools during discovery. The model sees descriptors first, and only what it actually calls gets executed. Completed steps never re-run — eve replays the recorded result. A step interrupted mid-execution re-runs, so make non-idempotent side effects (charges, emails) idempotent, or gate them with approval.

Shaping what the model sees

By default the model sees the full execute return. Use toModelOutput to project it down when the tool returns rich data a channel needs for rendering but the model only needs the gist:
agent/tools/audit_report.ts
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
  description: "Run a security audit and return a full report.",
  inputSchema: z.object({ domain: z.string() }),
  async execute({ domain }) {
    const report = await runAudit(domain);
    return report; // full data for channels and hooks
  },
  toModelOutput(output) {
    return { type: "text", value: `Report for ${output.domain}: score ${output.score}.` };
  },
});
toModelOutput receives the full typed execute return and only affects what the model sees. Channel event handlers and hooks still get the full output on action.result. Return { type: "text", value } for a summary, or { type: "json", value } for a smaller object.
Tool outputs must be JSON-serializable. Return plain objects, arrays, strings, numbers, booleans, or null. Do not return secrets, credentials, unnecessary personal data, or unbounded sensitive content.

Human-in-the-loop: gating tools on approval

A tool can require a person to sign off before it runs. Set needsApproval using the helpers from eve/tools/approval:
agent/tools/refund_charge.ts
import { defineTool } from "eve/tools";
import { always } from "eve/tools/approval";
import { z } from "zod";

export default defineTool({
  description: "Refund a charge.",
  inputSchema: z.object({ chargeId: z.string(), amount: z.number() }),
  needsApproval: always(),
  async execute(input) {
    return refund(input);
  },
});
HelperBehavior
never()Never require approval (the default when needsApproval is omitted).
once()Require approval only the first time the tool runs in a session; auto-allow after.
always()Require approval before every call.
When the approval decision depends on the input values, pass your own predicate instead of a helper. It receives { toolName, toolInput, approvedTools } and returns a boolean:
needsApproval: ({ toolInput }) => (toolInput?.amount ?? 0) > 1000,
Gating a side effect on approval is also how you make non-idempotent work safe across replays: a charge or email behind always() can’t fire from a re-run step without a fresh human decision.
By default, omitted needsApproval behaves like never(). Require human approval for sensitive, irreversible, regulated, financial, healthcare, employment, housing, legal, safety-impacting, or external side-effecting actions.

The ask_question built-in tool

The built-in ask_question tool lets the model pause mid-turn and ask the user a clarifying question or prompt a choice. It is part of the default harness — no definition required. The model calls it with:
  • prompt: the question to put to the user.
  • options (optional): a list of choices. Channels render these as buttons or a select menu.
  • allowFreeform (optional): whether the user may answer with free text instead of picking an option.
ask_question produces the same durable pause as an approval and resumes exactly where it left off.

Default harness tools

Every agent gets these built-in tools automatically, targeting the agent’s sandbox:
ToolDoes
bashRun a shell command in the sandbox
read_fileRead a file under /workspace
write_fileWrite a file under /workspace
globFind files by pattern
grepSearch file contents
web_fetchFetch a URL
web_searchSearch the web
todoManage a task list for multi-step work
load_skillLoad a skill’s markdown into the active context
ask_questionPause and ask the user a question
agentDelegate a subtask to a copy of the agent (or a subagent)

Overriding default harness tools

The framework defaults are importable from eve/tools/defaultsbash, readFile, writeFile, glob, grep, webFetch, webSearch, todo, loadSkill. Author a file at the same slug to replace the built-in:
agent/tools/write_file.ts
import { defineTool } from "eve/tools";
import { writeFile } from "eve/tools/defaults";

export default defineTool({
  ...writeFile, // keep the default description, schema, and executor
  async execute(input, ctx) {
    console.log("[write_file]", input.path);
    return writeFile.execute(input, ctx);
  },
});
Spread the default to keep its description, schema, and any framework-managed state (such as the todo tool’s durable state key). Drop the spread and your replacement owns its own context entirely.

Disabling built-in tools

To remove a built-in tool, author a file at agent/tools/<tool_name>.ts that exports disableTool:
agent/tools/web_search.ts
import { disableTool } from "eve/tools";

export default disableTool();
If the filename matches no known framework tool, resolution fails at build time rather than silently removing nothing. An authored tool at agent/tools/agent.ts takes priority over the built-in agent tool.

Build docs developers (and LLMs) love