Skip to content

Custom tools

Custom tools

Custom tools extend the agent with workspace-specific actions, running through the same scoped API as a hook.

Declare a tool

Create +<lower_snake_case>.ts in src/capabilities/tools/ . The filename is the tool name, and the file exports one defineAgentTool:

// src/capabilities/tools/+product_lookup.ts
import { defineAgentTool } from '@norbital-ai/bolt/authoring';
import { Effect, Schema } from 'effect';

export default defineAgentTool({
	description: 'Returns one product by id, with its current stock level.',
	input: Schema.Struct({ productId: Schema.String }),
	run: (api, { productId }) =>
		Effect.gen(function* () {
			const product = yield* api.db.query.products.findFirst({
				where: { id: { eq: productId } }
			});
			return product ?? null;
		})
});

Scoped, not privileged

A custom tool is not a backdoor — it runs with the same scoped API as a hook : policies, hooks, and audit apply to everything it does.

Reserved names

Built-in tool names are owned by the platform — an authored tool with one of those names never runs, because platform calls are matched on the name first. See Built-in tools .