burgee
Packages

burgee

An agent-native CLI framework, drop-in compatible with commander and yargs. One declaration; help, --json, --schema, --mcp and completions all projected from it.

A burgee is the small swallowtail flag a boat flies to say which club or fleet it belongs to — a flag of identity, not of instruction. That is what this framework does for a command-line program: a command declares itself once, and every surface is that declaration read by a different reader.

It replaces commander and yargs: burgee/commander and burgee/yargs are drop-in, graded by each one's own test suite. Change one import and the same program answers agents too — --json for results, --schema for the command tree, --mcp for an MCP server.

Start here

npm install burgee
// cli.mjs — the whole CLI
import { defineCommand, run } from 'burgee';

run(defineCommand({
  name: 'greet',
  description: 'Greet someone by name',
  options: { name: { type: 'string', required: true, description: 'who to greet' } },
  run: ({ options }) => ({ greeting: `hello, ${options.name}` }),
}));
$ node cli.mjs --name ada
greeting: hello, ada

$ node cli.mjs --json --name ada
{"ok":true,"data":{"greeting":"hello, ada"}}

$ node cli.mjs            # exit 2
error: missing required option --name
hint: pass --name <value>

One file. No build step, no config file, no directory convention. A test enforces that on every commit.

One declaration, every surface

defineCommand()  ──▶  manifest  ──┬──▶  human help
                                  ├──▶  --json      one stable envelope
                                  ├──▶  --schema    versioned, one document per surface
                                  ├──▶  --mcp       an MCP server, generated
                                  ├──▶  completions bash · zsh · fish · pwsh
                                  ├──▶  TypeScript types
                                  └──▶  docs + llms.txt

Nothing here needs keeping in sync, because nothing is written twice.

Already on commander?

Drop-in compatible with both incumbents, graded by their own test suites — 1,360 / 1,360 of commander's tests and 804 / 804 of yargs' on the compatibility page — with the pass rate published and ratcheting:

- import { Command } from 'commander';
+ import { Command } from 'burgee/commander';

Your code and your tests are unchanged. A façade is never called "compatible" until its host's own suite passes 100%; below that the rate is published instead of claimed.

What is in the box

ImportGives you
burgeedefineCommand(), run(), the exit-code contract and the JSON envelope.
burgee/commanderThe commander API, graded by commander's suite.
burgee/testingRun a command in-process and assert on its result — no spawning.
burgee/brandOne brand declaration → flag, favicon, OG card, cover, lockup. The logo above is its own output.
burgee/plugindefinePlugin(), validate(), CONTRACT and PluginError — the host, at the subpath every package in the family publishes its host at.

Writing a plugin

import { definePlugin } from 'burgee/plugin';

export default definePlugin({
  name: 'acme',
  commands: [{ path: ['audit'], description: 'Audit the tree', options: {}, effects: 'read_only', run: () => ({ findings: 0 }) }],
});

A plugin's command is read by exactly the code a first-party one is read by, so the same refusals apply: reserved option names, duplicate flags, a contributed path that is already declared — and effects, which every runnable command declares. definePlugin stamps the contract this burgee was compiled against; an object that reaches use() without one is refused rather than accepted on trust, because burgee's extension point shipped before it validated anything.

Status

burgee is published and working: the engine, the exit-code contract, the JSON envelope, help from the manifest, plugins with hook filters, and a burgee/commander façade that runs a real commander program. The dev loop, prompts, lazy commands and groups are not here yet.

Roadmap, architecture and the 114-requirement floor: https://github.com/ofri-peretz/burgee

FAQ

Is burgee a commander alternative?

Yes — and a yargs alternative. It is drop-in compatible with both: change import { Command } from 'commander' to import { Command } from 'burgee/commander' (or yargs to burgee/yargs) and your code and tests are unchanged. Compatibility is graded by each host's own test suite in CI, not asserted. Side by side: burgee vs commander and burgee vs yargs.

How do I make my CLI usable by an AI agent?

Declare it with defineCommand() — or keep it on commander or yargs syntax through the drop-in front ends. Every command then answers --json with one stable envelope, --schema with the whole command tree as data, and exits 2 when the command was wrong so an agent knows to rewrite it rather than retry. None of it is written by hand; it is the declaration read by a different reader. Your CLI is an agent tool has each surface.

How do I expose a CLI over MCP?

Run it with --mcp: the same manifest is served as MCP tools over stdio. A command becomes a tool only when it declares its effects (read_only, idempotent or non_idempotent), so nothing reaches an agent by accident. Register it with any stdio client:

{ "mcpServers": { "mytool": { "command": "npx", "args": ["mytool", "--mcp"] } } }

Does it have dependencies?

None outside the burgee family. burgee installs five packages from that family — bellpull, closeout, linegauge, roundel and seniority — and each of those takes nothing from outside it either: one repository, one release pipeline, one supply chain to audit.


Part of the burgee family: a CLI on burgee declares what it is, roundel carries its colours, flagstaff flies it, and caique answers back. Each is an independent package; none requires the others.

MIT © Ofri Peretz — see LICENSE.

Benchmarks

Every number here is produced by npm run bench and published at /docs/benchmarks.

Graded by the incumbent's own test suite:

suitepassing
commander1360 / 1360
meow132 / 148
yargs804 / 804

Where it sits

Plugins register under the commands and hooks keys, against the one schema the whole family shares.

Nothing in this family builds on it yet, and it builds on bellpull, closeout, linegauge, roundel, seniority.

On this page