On this page
Add a custom tool with an extension
An extension is a small TypeScript or JavaScript module that gives the agent your own tools, or hooks into what Haarness does: adding context to a prompt, answering a permission prompt, or setting environment variables for shell commands.
Extensions run with Bun. From the command line and the terminal UI you need Bun
on your PATH, or HAARNESS_BUN set to its full path; Haarness does not install it for you.
Desktop brings its own copy.
Create your first extension
haarness extension init ./my-extensionThis creates index.ts, its type definitions and a package.json. The extension is named after
its folder, here my_extension; pass --name to choose another. The starter adds a greet tool
(shortened here):
import type { Extension } from "./api";
export default {
apiVersion: 1,
name: "my_extension",
tools: {
greet: {
description: "Greet someone by name",
parameters: {
type: "object",
properties: { name: { type: "string" } },
required: ["name"],
},
execute(args: { name: string }) {
return `Hello, ${args.name}!`;
},
},
},
} satisfies Extension;Edit it in any editor; the type definitions give you autocomplete for every tool and hook.
Install it
haarness extension install ./my-extension
haarness extension checkinstall runs the extension once to validate it, then turns it on. check loads every enabled
extension and reports problems with names, hooks or tool schemas; add --verbose to see the
extension's console output.
The agent sees your tool as ext__my_extension__greet, and /tools lists it. An extension tool
cannot replace a built-in or MCP tool.
Haarness reloads a changed local extension once no turn is running. Run install again to check
the new version first; if it fails to load, the previous version keeps running.
Pass settings to an extension with --options '{"greeting":"Hello"}'. Add --project to any
extension command to manage this project's extensions instead of your own.
Install one from npm
haarness extension install npm:[email protected]Haarness installs the exact version into its own folder, with package install scripts turned off. It never downloads missing dependencies while running.
A package says where its extension is in package.json:
{
"name": "haarness-extension-example",
"version": "1.2.3",
"type": "module",
"haarness": { "extension": "src/index.ts" }
}Without that field, Haarness uses main or module, or an index.ts, index.mjs or index.js
file.
To move to a newer npm version, remove the extension and install the new version.
Turn extensions off or remove one
haarness extension list # what is installed; runs no extension code
haarness extension disable my_extension # one extension, by name or list number
haarness extension disable # all extensions
haarness extension enable my_extension
haarness extension remove my_extension # unregister it; your files stayNaming rules
Extension and tool names are 1 to 24 lowercase letters, digits or single underscores. Double underscores are not allowed.
Before you install
Installing an extension is a decision to trust it: its code runs on your machine with your user's access. Extensions run in a separate process and can be cancelled. Changes take effect when no turn is running. A project's extensions load only while project configuration is on. Limits on what an extension may use are in Execution budgets.
Related
- Run commands on chat events (hooks), for a script instead of a module
- Add an MCP server
- Trust boundaries