---
title: "Plugins"
description: "Extend the agent's capabilities with a three-file plugin bundle."
---

Plugins give Bi new tool capabilities through external programs. Each plugin is a directory under `.bi/plugins/<name>/`, scanned and loaded on startup (and on each conversation loop).

## The three-file bundle

A plugin directory holds three files:

| File | Role |
| --- | --- |
| `plugin.json` | The manifest: name, version, description, command template, schema |
| executable | The program named by `entry` — the plugin actually runs it |
| `SKILL.md` | Usage instructions for the agent (one line injected into the system prompt, full text fetched with `read` when needed) |

## plugin.json fields

```json
{
  "name": "websearch",
  "version": "1.0.0",
  "description": "Query an external search API and return web results",
  "when_to_use": "When you need live information or web search",
  "entry": "websearch.exe",
  "command": "{entry} search bing \"{query}\" --limit 5 --format markdown",
  "defaults": { "limit": "5" },
  "toggle": "search",
  "enabled": true,
  "schema": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "description": "Search terms" }
    },
    "required": ["query"]
  }
}
```

- **`name`** — The tool name, registered for the model to call. Must match `[a-z][a-z0-9_]{1,30}` and must not collide with built-in tool names (`read`, `write`, `exec`, `search`, `list`, `spawn_agent`).
- **`entry`** — The executable's file name inside the plugin directory. Must be a plain file name; `../` and absolute paths are rejected.
- **`command`** — The command template. `{entry}` becomes the executable's absolute path (auto-quoted), `{dir}` the plugin directory, and `{key}` is filled from argument → `defaults` → empty string.
- **`schema`** — The tool argument schema; must be `object`. The model builds arguments from it.
- **`toggle`** — Which front-end switch governs it. `"search"` ties it to the smart-search toggle: when that is off, the plugin is **not even mounted** (the model cannot discover it). Empty string = always available.
- **`enabled`** — Absent (null) = enabled; explicit `false` = disabled (not loaded, not in the tool set, no prompt injection).
- **`retry`** — Failure-retry policy: `on_error` / `on_empty` pick the trigger, `max_attempts` caps total attempts, `param_fallbacks` gives alternate values tried in turn.

## Execution and authorization

Plugins run through the `exec` tool's process pipeline (same timeouts, process-tree kill, GBK decoding), so:

- **Authorization goes through the existing permission system**: plugin calls raise permission prompts and need your approval by default.
- **No shell escaping is done up front**: trust is the same as the `exec` tool (the model can already run arbitrary commands); quoting is the template author's job.

## Health and failure

A broken plugin is skipped and logged — it **never breaks the conversation**. Common load failures:

- No `plugin.json` (the directory is ignored; it is not a plugin)
- Invalid manifest (`name` / `command` / `schema` violating the constraints above)
- `entry` is not a plain file name, or the executable is missing

The plugin directory is rescanned on startup; a manifest change takes effect after a restart.

## Notes

- **Plan mode mounts no plugins.** Planning is read-only analysis and does not run external programs.
- A plugin executes an arbitrary program on your machine, exactly as if you ran it yourself. Inspect third-party plugins before installing them.
- A `toggle: "search"` plugin is completely invisible when smart search is off. That is "existence follows the switch", not "disabled but installed".
