# Plugins

> Every layer takes plugins the same way — a plain object, validated against one published schema, checked by the package's own command before it ships. One object can extend all nine.

Source: https://burgee.interlace.tools/docs/plugins

Generated by `npm run plugins:page` from the packages themselves. Do not edit by hand.

Every package in the family takes plugins, and all 9 take them the same way. A plugin
is a plain object. Each package validates it against **one published schema** — the same
`schema.json` ships in every package — and each package has a `check` command that shows what
a plugin contributes, or refuses it with a code and the fix, before it ships.

Each package reads its own key and ignores the others, so **one object can extend any subset
of the family that is installed**, including all of it.

## One object, 9 layers

A company's CLI conventions, in one file: brand colours, a spinner, a terminal quirk, a
terminal capability, a config source, where its tools live, what to flush on exit, a prompt
of its own, and a command every one of its CLIs gets.

```js title="examples/plugins/acme.mjs"
// One plugin object, nine layers. A company's CLI conventions in a single file: brand
// colours, a spinner, a terminal quirk, a config source, where its tools live, what to
// flush on exit, a prompt of its own, a terminal capability and a command every CLI
// gets. Each package reads its own key and ignores the rest, so the same object
// registers into any subset of the family that is installed.
//
// Check it against any layer: `npx roundel check examples/plugins/acme.mjs`, and the
// same for flagstaff, linegauge, paratext, seniority, bellpull, closeout, caique and
// `npx burgee check`. `scripts/plugin-example-lock.test.ts` runs all nine.
export default {
  name: 'acme',
  contract: 1,

  // roundel — the brand, as semantic tokens every styled line reads.
  tokens: { ok: '#1a7f37', error: '#cf222e', hint: '#0969da' },

  // flagstaff — a spinner, with the line a pipe or an agent prints instead.
  spinners: { acme: { frames: ['◐', '◓', '◑', '◒'], interval: 100, static: '◐' } },

  // linegauge — the Nerd Font glyphs this company's prompt draws two columns wide.
  widths: { powerline: { ranges: [[0xe0a0, 0xe0a3], [0xe0b0, 0xe0b3]], columns: 2, why: 'Nerd Font powerline glyphs render wide in the company terminal profile' } },

  // paratext — a terminal capability, with what prints when the terminal lacks it.
  capabilities: { beep: { name: 'beep', osc: 'BEL', when: { tty: true }, encode: '\u0007', fallback: '' } },

  // seniority — a config layer between the flag (0) and the declared default (40).
  sources: { vault: { rank: 25, read: () => undefined, location: 'vault://acme/cli' } },

  // bellpull — where the company's pinned toolchain lives, searched before PATH.
  resolvers: { asdf: { rank: -10, paths: ['{ASDF_DATA_DIR}/shims'], when: { envAny: ['ASDF_DATA_DIR'] } } },

  // closeout — flush telemetry before the process exits, whatever ended it.
  handlers: [{ name: 'flush-telemetry', phase: 'flush', run() {} }],

  // caique — a prompt kind of the company's own, with its non-interactive projection.
  widgets: { rating: { static: () => 'rate 1-5', sample: { running: {}, done: {} } } },

  // burgee — a command every company CLI gets, declared exactly as a program's own.
  commands: [{ path: ['doctor'], description: 'Check this machine against the company toolchain', options: {}, effects: 'read_only', run: () => ({ ok: true }) }],
};
```

This is a committed file, not an illustration: `scripts/plugin-example-lock.test.ts` runs all
9 `check` commands against it, and the published schema over it, on every CI run.

## What each layer takes

| Package | Key | What a plugin contributes | Check it | What the incumbent offers |
| :--- | :--- | :--- | :--- | :--- |
| **bellpull** | `resolvers` | bellpull resolvers by name: extra directories searched for an executable, before PATH (negative rank) or after it (positive). Two resolvers with one name shadow; two names both apply, in rank order. | `npx bellpull check ./plugin.mjs` | **cross-spawn** — None |
| **burgee** | `commands` | burgee commands this plugin contributes. Each is read by exactly the code a program's own command is, and a burgee plugin must declare `contract`. | `npx burgee check ./plugin.mjs` | **commander** — Lifecycle hooks on one program (`.hook('preAction')`); no plugin shareable across programs — the plugin RFC, [#2505](https://github.com/tj/commander.js/issues/2505), is open<br />**yargs** — Middleware on one program (`.middleware()`), and commands loaded from modules (`.commandDir()`)<br />**meow** — None<br />**cac** — Events on one program (`cli.on()`)<br />**citty** — `setup` and `cleanup` on each command |
|  | `hooks` | burgee lifecycle hooks. preRun opens around a command, and exactly one of postRun or onError closes. |  |  |
| **caique** | `widgets` | caique prompt widgets by kind. The six built-in kinds — text, confirm, select, multiselect, password, path — cannot be replaced: a plugin adds kinds of its own. | `npx caique check ./plugin.mjs` | **clack** — Custom prompts built on `@clack/core`<br />**inquirer-core** — Custom prompts built with `createPrompt` |
| **closeout** | `handlers` | closeout exit handlers. The phase decides the order they run in, not their position in this list. | `npx closeout check ./plugin.mjs` | **restore-cursor** — None<br />**exit-hook** — None — it is the hook<br />**signal-exit** — None — it is the hook |
| **flagstaff** | `tokens` | A roundel theme: semantic token name to a hex colour, contrast-checked when flown. | `npx flagstaff check ./plugin.mjs` | **ora** — A custom spinner object, per instance (`spinner: { frames, interval }`)<br />**log-update** — None<br />**boxen** — A custom border object, per call (`borderStyle`)<br />**cli-table3** — Custom border characters, per table (`chars`) |
|  | `glyphs` | Symbols by meaning: `ok`, `fail`, `warn`, `info`, `running`. A plugin that ships glyphs changes every built-in that draws one. |  |  |
|  | `spinners` | Spinner styles by name, in cli-spinners' shape plus the static projection. |  |  |
|  | `borders` | Border styles a box can be drawn with, by name. |  |  |
|  | `components` | Components by name: `static(state)` returns the text a pipe, an agent or a screen reader gets; `frame(t, state)` is the optional animated form. |  |  |
| **linegauge** | `widths` | linegauge width overrides by name — the measurement section of a plugin, read the way flagstaff reads `spinners`. | `npx linegauge check ./plugin.mjs` | **string-width** — An option per call (`ambiguousIsNarrow`); no per-code-point override<br />**strip-ansi** — None<br />**wrap-ansi** — Options per call<br />**slice-ansi** — None |
| **paratext** | `capabilities` | paratext capabilities by name — the OSC section of a plugin, read the way flagstaff reads `spinners`. | `npx paratext check ./plugin.mjs` | **ansi-escapes** — None<br />**terminal-link** — A `fallback` function, per call<br />**term-img** — A `fallback` function, per call |
| **roundel** | `tokens` | A roundel theme: semantic token name to a hex colour, contrast-checked when flown. | `npx roundel check ./plugin.mjs` | **chalk** — None — styles are code; there is no theme to register |
| **seniority** | `sources` | seniority configuration sources by name, ranked against the built-in layers: a flag is 0 and a declared default is 40, and a plugin source sits strictly between. | `npx seniority check ./plugin.mjs` | **rc** — A custom `parse` function, per call<br />**cosmiconfig** — Custom `loaders` per file extension and `searchPlaces`, per explorer<br />**lilconfig** — Custom `loaders` per file extension, per call<br />**dotenv** — None |

The schema for every key above ships as `<package>/schema.json`. An editor, a validator or a
model can read it without running anything.

## What a plugin cannot do yet

- **burgee's hooks cover the run of a command and nothing around it.** A plugin can act at
  `preRun`, `postRun`, `onError` — not before arguments are parsed, not inside
  help, not in config resolution, not at shutdown. Contributing commands has no such limit.
- **flagstaff's built-in components are not contributions.** A plugin adds spinners, borders
  and components of its own; it cannot replace `progress`, `box` or `table`.
- **The schema cannot say "function".** `static`, `run`, `read` and `handler` are required
  and described; that each is a function is checked by the package, not by the schema.
- **Whether a model writes a working plugin in one turn is unmeasured.** Each package has an
  eval case that asks exactly that, proven to tell a working plugin from a broken one; none
  has run against a model yet.
