Tools
Executable agent tools that run in the Reforma sandbox.
Tools let a plugin expose executable behavior to the agent inside the Reforma sandbox.
Use a tool for operations that are better expressed as code than instructions — for example, running a CLI, inspecting or transforming project files, controlling a preview, or intentionally overriding a built-in tool.
For task-specific instructions, use a skill. For SaaS APIs and authenticated external services, prefer MCP.
Tools are Reforma-specific.
Layout
Put each tool in its own TypeScript file under tools/:
tools/
KitPing.ts
Grep.tsThe filename defines the tool name:
KitPing.ts → KitPing
Grep.ts → GrepThere is no separate name field in the tool definition.
By default, Reforma can namespace plugin tools when exposing them to the model. Set override: true only when the tool is intended to use its bare filename and replace a same-named host tool.
Define a tool
Default-export defineTool from @reforma/plugin-sdk:
import { defineTool, z } from "@reforma/plugin-sdk";
export default defineTool({
description: "Echo a message from the plugin tool.",
inputSchema: z.object({
message: z.string().min(1).describe("Message to echo"),
}),
async execute({ message }, ctx) {
return {
pong: message,
toolName: ctx.toolName,
};
},
});z is a Zod re-export from the SDK.
Definition
| Field | Purpose |
|---|---|
description | Required model-facing description of what the tool does |
inputSchema | Zod schema for tool input |
execute(input, ctx) | Runs the tool inside the Reforma sandbox |
override | Optional; expose the bare filename instead of a plugin-namespaced tool name |
defineTool also passes through supported AI SDK tool options such as output schemas, model-output conversion, approval requirements, examples, provider options, and input lifecycle callbacks.
Execution context
The second argument to execute contains Reforma runtime context:
| Field | Purpose |
|---|---|
ctx.pluginDir | Absolute path to the installed plugin |
ctx.env | Resolved variables configured for the plugin |
ctx.toolName | Runtime name of the tool |
ctx.toolCallId | Current tool-call identifier |
ctx.abortSignal | Abort signal for the current execution |
For example:
import { resolve } from "node:path";
async execute({ path }, ctx) {
const absolutePath = resolve(ctx.pluginDir, path);
// perform the operation…
return { path: absolutePath };
}Values declared through extensions.reforma.variables, including configured secret values, are available through ctx.env.
Overriding a tool
Set override: true when the plugin intentionally replaces a tool exposed under the same bare name:
import { defineTool, z } from "@reforma/plugin-sdk";
export default defineTool({
override: true,
description: "Search the workspace using this plugin's implementation.",
inputSchema: z.object({
pattern: z.string(),
}),
async execute({ pattern }) {
// …
},
});Because overrides affect the agent's global tool surface, use them deliberately.
Packing
The catalog packer bundles source files under tools/ into a single:
tools.mjsThe packed module exports a map of tool names to definitions.
The packed plugin manifest also receives:
{
"extensions": {
"reforma": {
"tools": "./tools.mjs",
"toolOffers": [
{
"name": "KitPing",
"description": "Echo a message from the plugin tool."
}
]
}
}
}toolOffers is generated for catalog and integration UI metadata; do not maintain it by hand.
@reforma/plugin-sdk, ai, and zod remain external when tools are bundled and are provided by the Reforma host runtime.