> ## Documentation index
> Fetch the complete documentation index at: https://haarness.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 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](https://bun.sh). 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

```sh
haarness extension init ./my-extension
```

This 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):

```ts
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

```sh
haarness extension install ./my-extension
haarness extension check
```

`install` 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

```sh
haarness extension install npm:haarness-extension-example@1.2.3
```

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`:

```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

```sh
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 stay
```

## Naming 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](https://haarness.ai/docs/security/execution-budgets.md).

## Related

- [Run commands on chat events (hooks)](https://haarness.ai/docs/cli/hooks.md), for a script instead of a module
- [Add an MCP server](https://haarness.ai/docs/cli/mcp-servers.md)
- [Trust boundaries](https://haarness.ai/docs/security/trust-boundaries.md)
