# Extensions

> Add tools to the bitsrun agent with MCP servers, run your own checks with hooks, save reusable prompts as custom commands and rebind any key.

Source: https://bitsrun.com/docs/agent/extensions/
Updated: 2026-11-09

Extensions are set up in a `settings.json` file. There are two places for it:

| File | Applies to | Notes |
|---|---|---|
| `settings.json` in your config folder (`~/.config/bitsrun/` on macOS and Linux, `%APPDATA%\bitsrun\` on Windows) | Every project, only you | Always used |
| `.bitsrun/settings.json` in a project | That project, everyone who clones it | Used only after you trust the project (see [Project trust](https://bitsrun.com/docs/agent/modes-and-approvals/#project-trust)) |

A full example with every extension type:

```json
{
  "mcpServers": {
    "github": { "url": "https://api.example.com/mcp", "headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" } },
    "db": { "command": "npx", "args": ["my-db-mcp"], "env": { "DB_URL": "${DB_URL}" } }
  },
  "hooks": {
    "beforeTool": [{ "match": "shell", "command": "./scripts/check-command.sh", "timeout": 30 }],
    "afterTool": [{ "match": "edit|write", "command": "npx prettier --check . >&2 || exit 2" }]
  },
  "permissions": { "allow": ["mcp(db)"], "deny": ["mcp(github__delete_repo)"] }
}
```

If an entry is malformed, bitsrun skips it and tells you why when the session starts.

## MCP servers

**MCP** (Model Context Protocol) is an open standard for giving AI agents extra tools, such as a database, an issue tracker or a browser. Many tools ship an MCP server you can connect.

Add servers under `mcpServers`. Each one has a name (letters, digits, `-` and `_`, up to 32 characters) and either:

- **A local program** (stdio): `command`, with optional `args` and `env`. bitsrun starts it and talks to it over its input and output. It gets only basic environment variables plus the ones you list in `env`.
- **A remote server** (Streamable HTTP): `url`, with optional `headers`. The URL must use `https` (plain `http` only for `localhost`). Put credentials in `headers`, never in the URL.

`${VAR}` in a value is replaced by that variable from your shell, so secrets stay out of the file.

Each server's tools appear to the agent as `mcp__<server>__<tool>` and go through the same approvals as every other tool. A tool its server marks as read-only runs without asking, like a read-only command; any other tool is treated like a command. Allow or deny a whole server with `mcp(<server>)` or one tool with `mcp(<server>__<tool>)`.

Type `/mcp` to see each server, whether it started, and its tools.

> [!NOTE]
> Signing in to a remote MCP server through the browser (OAuth) is not supported yet. Use a token in `headers`.

## Hooks

A **hook** is your own command that runs automatically before or after the agent uses a tool. Use one to block risky commands your way, run a formatter or linter after each edit, or log what the agent does.

| Field | What it does |
|---|---|
| `match` | A pattern over the tool name, such as `shell`, `edit\|write` or `mcp__db__.*`. Leave it out (or use `*`) for every tool. |
| `command` | The command to run, in the project folder. |
| `timeout` | Seconds before it is stopped. Default 60, at most 600. |

Hooks go in two lists: `beforeTool` and `afterTool`. Each hook receives the tool call as JSON on its standard input:

```json
{ "event": "beforeTool", "tool": "shell", "cwd": "/Users/you/project", "input": { "command": "npm test" } }
```

After a tool, the JSON also has `"output"`.

What the exit code means:

| Exit code | Before a tool | After a tool |
|---|---|---|
| `0` | The call goes ahead. | Nothing more happens. |
| `2` | The call is blocked. What the hook wrote to standard error is the reason the model sees. | What the hook wrote to standard error goes to the model as feedback, for example lint errors to fix. |
| Anything else | A warning is shown and the call goes ahead. | A warning is shown. |

A small `beforeTool` hook that blocks `rm -rf`:

```bash
#!/usr/bin/env bash
# scripts/check-command.sh: reads the tool call as JSON and blocks rm -rf
if jq -r '.input.command // ""' | grep -q 'rm -rf'; then
  echo "Do not use rm -rf in this project; delete files one by one." >&2
  exit 2
fi
```

> [!WARNING]
> Hooks run programs on your computer with your permissions. A project's hooks only run after you trust the project, and bitsrun shows the exact commands when it asks.

## Custom commands

Save a prompt you use often as a Markdown file, and run it as a slash command.

- **Yours, in every project:** `commands/<name>.md` in your config folder.
- **Shared with a project:** `.bitsrun/commands/<name>.md` (used once you trust the project).

The file's text becomes the prompt. `$ARGUMENTS` is replaced by whatever you type after the command; if the file does not use it, your words are added at the end. An optional front matter line `description:` is shown in the `/` menu.

```markdown
---
description: Review changes in a folder for bugs and missing tests
---
Review the code in $ARGUMENTS. List real bugs first, then missing tests. Do not change any files.
```

Saved as `.bitsrun/commands/review.md`, run it with:

```text
> /review src/billing
```

Type `/commands` to list your custom commands. They also work in headless runs: `bitsrun -p "/review src/billing"`.

## Keybindings

Change any key in `keybindings.json` in your config folder. Map a key to an action, or to `null` to turn it off:

```json
{ "ctrl+p": "mode", "ctrl+t": null }
```

Key names are modifiers (`ctrl`, `alt`, `shift`) joined with `+` before the key: a letter, `enter`, `tab`, `escape`, `up`, `down`, `left`, `right`, `home`, `end`, `pageup`, `pagedown`, `backspace`, `delete`, `insert` or `f1` to `f12`. Run `bitsrun code keytest` to see the exact name of any key you press.

| Action | Default key |
|---|---|
| `send` | <kbd>Enter</kbd> |
| `newline` | <kbd>Alt</kbd>+<kbd>Enter</kbd> |
| `mode` | <kbd>Shift</kbd>+<kbd>Tab</kbd> |
| `interrupt` | <kbd>Esc</kbd> |
| `cancel` | <kbd>Ctrl</kbd>+<kbd>C</kbd> |
| `exit` | <kbd>Ctrl</kbd>+<kbd>D</kbd> |
| `history-back` | <kbd>Up</kbd> |
| `history-forward` | <kbd>Down</kbd> |
| `history-search` | <kbd>Ctrl</kbd>+<kbd>R</kbd> |
| `clear-screen` | <kbd>Ctrl</kbd>+<kbd>L</kbd> |
| `todos` | <kbd>Ctrl</kbd>+<kbd>T</kbd> |
| `editor` | <kbd>Ctrl</kbd>+<kbd>G</kbd> |
| `paste-image` | <kbd>Ctrl</kbd>+<kbd>V</kbd> |
| `transcript` | <kbd>Ctrl</kbd>+<kbd>O</kbd> |
| `complete` | <kbd>Tab</kbd> |
| `line-start` | <kbd>Ctrl</kbd>+<kbd>A</kbd> |
| `line-end` | <kbd>Ctrl</kbd>+<kbd>E</kbd> |
| `word-left` | <kbd>Alt</kbd>+<kbd>B</kbd> |
| `word-right` | <kbd>Alt</kbd>+<kbd>F</kbd> |
| `delete-word` | <kbd>Ctrl</kbd>+<kbd>W</kbd> |
| `delete-to-start` | <kbd>Ctrl</kbd>+<kbd>U</kbd> |
| `delete-to-end` | <kbd>Ctrl</kbd>+<kbd>K</kbd> |

A key you bind acts exactly like the action's default key. If a line in the file is not valid, bitsrun says which one when the session starts and ignores it.

## Other settings

These go in `settings.json` in your config folder:

| Setting | What it does |
|---|---|
| `"keepAwake": "30m"` | How long a BitsRun endpoint stays awake after your last activity, `1m` to `8h`, or `"off"`. Default 15 minutes. |
| `"fullScreen": false` | Use the classic view with your terminal's own scrollback. |
| `"notifications": false` | No bell or desktop notification when a slow endpoint start finishes. |
| `"remoteOffer": false` | Stop offering remote control while an endpoint wakes. |
| `"remotePairing": "ask"` | Ask before a new device of your account follows a session for the first time. |
