👋 Start here
npx burgee init my-cli && cd my-cli && npm install
init writes this file as cli.mjs, and a package.json that runs it. Nothing else.
Power your agent
คำสั่งของผู้เผยแพร่เอง ไม่ใช่เอนด์พอยต์ของ PlugMCP
Host a copy with our keys and logs.
npx -y [email protected]Claude Code ไม่มีลิงก์ติดตั้งสำหรับคำสั่งแบบโลคัล ให้คัดลอกคำสั่งด้านล่างแล้วรันในเทอร์มินัล
claude mcp add burgee -- npx -y burgee@2.1.2รันในเทอร์มินัล
{ "mcpServers": { "burgee": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}claude_desktop_config.json
URL แบบรีโมตหรือคำสั่งบนเครื่องของคุณ? การติดตั้งสองแบบต่างกันอย่างไร
รันบน PlugMCP
A new server you create. It is not this listing's official endpoint. Use the publisher install when you want their URL and their credentials.
เปิดจากผู้เผยแพร่
npx burgee init my-cli && cd my-cli && npm install
init writes this file as cli.mjs, and a package.json that runs it. Nothing else.
A CLI framework built on one declaration: help, --json, --schema, MCP, completions and types are projected from it, with exit codes and fix: lines an agent can act on. No dependency outside the burgee family. Drop-in paths for commander, yargs and meow.
#!/usr/bin/env node
// 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' } },
effects: 'read_only', // what running it does to the world; required, and what --mcp reads
run: ({ options }) => ({ greeting: `hello, ${options.name}` }),
}));
$ node cli.mjs --name ada
greeting: hello, ada
$ node cli.mjs --name ada --json
{"ok":true,"data":{"greeting":"hello, ada"},"meta":{"provenance":{"name":{"source":"flag","location":"--name"}}}}
$ node cli.mjs # exit 2, not 1
error: missing required option --name
hint: pass --name <value>
usage: greet [options]
options:
--name <value> who to greet (required)
That is the whole thing: one file, one declaration, and a CLI that already speaks to a person, to a script and to an agent.
A burgee is the small swallowtail flag a boat flies to say which club it belongs to — a flag of identity, not of instruction. That is what a command does here: declares itself once, and every surface is that declaration read by a different reader.
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
Surfaces cannot drift, because there is nothing to keep in sync. Adding the next one is an emitter, not a feature.
The same command, asked for its own definition. No wrapper, no sidecar file, no scraping
--help:
$ node cli.mjs --schema # trimmed; arguments and examples also come back
{
"options": {
"name": { "type": "string", "required": true, "description": "who to greet" }
},
"inputSchema": { "type": "object", "properties": { "name": { "type": "string" } } }
}
$ node cli.mjs --mcp # the same command, served as an MCP server over stdio
Every --schema document validates against burgee/program-schema.json, the JSON Schema the
package publishes, so a project can pin its CLI's surface in CI without writing its own idea of
the shape.
Six issues across nine years of the commander and yargs trackers ask for machine-readable
command structure, and the state of the art today is a regex over --help
(tracker-gap-analysis.md). A manifest is not a
feature bolted on for agents — it is the thing help was rendered from in the first place.
What that is worth needs no model to measure. Ten tasks per variant, one spawn each, non-TTY with stdin closed — the only environment an agent gets — running the same demo program on each engine:
Exit code is the one that decides an agent's next move: 2 means rewrite the command, any
other non-zero means the command was fine and the world was not. This measures legibility,
not tokens. The token and turn halves of B1 run a model against the same program on every push
to main. What an agent sees quotes
those sessions and lists every run, including the ones where the claim in Measured
misses.
Every released package in the family takes plugins, and all nine 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 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 rest, so one object can extend every layer at once: brand colours, a spinner, a terminal quirk, a config source, where the company's tools live, what to flush on exit, a prompt of its own, and a command every one of its CLIs gets.
Where an incumbent has an extension point — commander's .hook(), yargs middleware,
cosmiconfig's loaders, inquirer's createPrompt — it lives in one program or one call. A
plugin here is written once and shared: across programs, across layers, and across commander,
yargs and native syntax alike. The plugins page has the
whole nine-layer example, which every released package's check accepts in CI, each incumbent's own
extension point beside ours, and what a plugin cannot do yet.
npx burgee migrate --dry-run # what it would change, and nothing written
npx burgee migrate
burgee has drop-in paths for commander and yargs, and the family has them for chalk, ora,
string-width, cross-spawn, signal-exit and the other packages graded level with their own
suites. burgee migrate rewrites the import specifiers and nothing else, then
prints the install command to run next (Migrate). For
one commander program, that is one line:
- import { Command } from 'commander';
+ import { Command } from 'burgee/commander';
Your code and your tests are unchanged. Compatibility is not asserted here, it is graded — each host's own suite, vendored unmodified apart from the import specifier, pointed at burgee and run in CI against a control that runs the real host:
Measured 2026-09-09 (yargs 2026-09-30, at 18.2.0); 38 more hosts are in
the full table, generated by
npm run compat:page and never hand-edited. Rates are measured against the control's total
rather than against registered tests, because a file that fails to import registers as one
test instead of its twenty and would flatter a partial implementation.
What changes after the switch is what the program can do. It answers --json, --schema and
--mcp, and it takes plugins. commander has no plugin API: its RFC
(#2505) was closed for inactivity on
2026-10-09 without one. yargs offers middleware on one program, not a plugin shared across
programs. A plugin contributes to
the manifest, and the manifest never records which façade filled it, so one plugin works on
commander syntax, yargs syntax and native alike.
oclif has every capability on this page and does 10.9M downloads a week against
commander's 508M. The difference is not features, it is shape. So the shape is locked
first, ahead of every other requirement, and Z1 is a test: it installs the published
tarball into a temp directory, writes exactly one file, and runs it. The day that needs a
second file, a config or a build step, CI goes red.
Everything beyond that first rung — precomputed manifests, plugins, the dev loop, scaffolding — is additive and removable.
2026-10-08 (ba8a89c), a GitHub Actions runner (AMD EPYC 7763, 4 cores), linux/x64, Node 24, 52 interleaved spawns per variant. † is a
published figure taken on another machine, not reproduced here (measured).
The speed comes from node:util.parseArgs being in the standard library, not from a faster
language: burgee is TypeScript, like both incumbents.
Milliseconds are a property of the machine that produced them, so nothing gates on them. What is gated is the ratio between two spawns interleaved in the same run, which cancels the machine out. Ten of those gates are stated in public — all ten are met, three of them as downward-only ratchets rather than the bar they started with, and the two agent claims as the median of a named window of CI runs rather than any one run (measured):
The two agent claims changed measure on 2026-10-09 (D-20261009-b1-totals-and-explain). They compared pooled medians until then, and the median ratio was decided by commander's luck: burgee holds at 3 turns, while commander's median lands at 4 or 6 from run to run, so the same build read 0.5 or 0.75. They now compare the tokens and turns each CLI spends, summed over all 25 task-runs.
And since 2026-10-25 they are stated as a series (D-20261025-cli-benchmarks-design-accepted).
One run is not a verdict: two runs of the same commit have read 0.49 and 0.995. Each row is
the median and the range over the CI runs in the window it names, and how many of them met the
bar, written by npm run agent-cost:row from benchmarks/results/agent-cli-bench/ and checked
against that window by scripts/claim-table-lock.test.ts. Until then the token row said
0.699×, from one run (e6cff20), and not met (measured).
burgee is 24,442 bundled bytes and cac is 10,452, so the bare row reads 2.338× and it
stays on this page. It is also not the choice anyone makes. A program that picks cac and
then wants its config file read, its shutdown bounded on every path out, and its cursor handed
back on Ctrl-C installs three more packages — and that is what one import of burgee competes
with (measured):
The additions are cosmiconfig (find and load a config file), exit-hook (run cleanup on
every path out, including a signal) and restore-cursor (hand the terminal back), bundled
together so a module two of them share is paid for once — which is what a real bundler does.
The rule that stops this being a rigged denominator: a package may only enter a stack where
this repository publishes a graded drop-in for it — a compat-oracle row whose pass rate
comes from that package's own test suite. seniority/cosmiconfig, closeout/exit-hook and
closeout/restore-cursor each have one, which is evidence we do the job rather than our word
for it, and parity.test.ts fails if an addition names a package
with no active row. It is self-limiting on purpose: we cannot pad a stack with packages we
merely resemble.
And the capabilities with nothing to add against — --schema, --mcp, the { ok, data }
envelope on every command, agent detection, option relations and Standard Schema — are priced
at zero. They are the part of the premium that is real and unpriced, and saying so is worth
more than finding a package to charge for them.
cold-start-at-or-below-cac and the two bare weight rows began as ≤ 1 and have a
measured floor above it, and it is worth saying plainly rather than leaving as a to-do.
cac is 10,452 bytes of parser and help renderer; burgee's 24,442 is that plus coercion,
choices, relations, Standard Schema, configuration precedence, signal-bound shutdown, terminal
restore and agent detection.
Our commander/command.js is 33,487 bundled against commander's 27,226, and the front-end also
carries a cross-platform spawn that cannot go lazy without giving up parse()'s synchronous
contract and the 1360 / 1360 compat row that rests on it. And import 'cac' is one file in
4.2 ms where import 'burgee' is twenty-one in 20 ms. Closing them means deleting the product,
not optimising it: the analysis is D-102, and the shrink that moved every
non-default path behind await import() is D-148 (measured).
So a bar we will never meet is no longer what these rows publish. Since D-157 each is a downward-only ratchet: a ceiling just above today's measurement, enforced on every benchmark run, that may be lowered by anyone and raised only by a new decision (measured).
The ceilings live in claim-ratchets.json with their
history, and claim-ratchets-lock.test.ts refuses a
step up that does not cite a newer decision. npm run ratchets:propose prints the lower
ceiling each can move to from the latest measurement. The size comparison to lead with is still
the at-parity rows above; the bare rows stay on the page because a suite that only showed the
comparisons we win would be lying by selection.
The agent rows are a different gap. B1 has run once, locally (D-147), and neither row becomes ✅ until the weekly CI job measures it, which waits on a credential only the owner can mint (D-150).
Installed size is our largest number and it is larger than commander's. It buys no dependency
outside the burgee family and six drop-in front ends, and it stays on the page either way: not met and
unmeasured are different outcomes and neither collapses into the other. Every bundle figure
in this section, including the ones that go against us, is written by npm run readme:gates
from a fresh bundle of the build, and a push whose build measures anything else is refused
(readme-gates-lock.test.ts). The millisecond and
installed-size figures come from the measurement published in
benchmarks.mdx and pinned in
comparison.mdx.
npm i burgee installs six packages, all of them from this repository, and installing any
family package runs no install script
(install-graph-lock). Every release is published
through npm trusted publishing with SLSA provenance and no npm token
(trusted-publishing-lock). Everything is MIT, and
each incumbent's own test suite is vendored in packages/compat-oracle,
so a fork keeps the conformance tests that tell it whether it still behaves the same.
Supply chain and continuity has the install
graph for each package and the check behind every statement.
Why it's built this way gives the reasoning behind
the family, and what it does not claim.
burgee declares; the output stack is what a CLI shows; the foundation is what it stands on. Each package is an independent product with its own README, installs on its own, and declares no dependency outside the burgee family.
Ten packages, one repository, one release pipeline and one supply chain to audit, with a
single schema byte-identical in every tarball. Six leaves depend on nothing, and every other
dependency points one way, down the layers;
the locks that hold each rule are named there. Releases are published through npm trusted
publishing, with SLSA provenance and no npm token (trusted-publishing-lock). The case for one
codebase is the number of things a user has to trust, not convenience.
All ten are released on npm at 1.x, with their public API under semver
(SECURITY.md says which releases are supported). Where an incumbent's own test suite has been vendored, the
compat oracle grades the drop-in path against it and publishes the rate — including the ones
not yet at 100% — on the compatibility page.
Released is not the same as accepted: the four
foundation packages began as 0.0.1 name reservations, were built out in waves F1–F4, and
their intents under .sdlc/intents/cli-foundation-stack/
are still at draft — the human gate on the design has not run. The bellpull intent carries a kill gate, because a zero-dependency
rival already holds the weight pitch in that layer, and its spec says plainly that the package
was built before that gate was evaluated. The measurements behind the layers are in
candidate-layers.md and
replacement-map.md.
Every claim in the design traces to one of these, and each records what it could not determine as well as what it found.
competitor-landscape.md — the measured map:
downloads, cold start, the compatibility bill, and why we implement rather than wrap.tracker-gap-analysis.md — every open item in
both trackers. Commander has 8; yargs has 211, 86% predating 2023. Six issues over nine
years ask for machine-readable command structure, and the state of the art is
regex-scraping --help.agent-requirements.md — what agents need, and
three widely-quoted claims that do not survive verification.cli-market-requirements.md — ten production
CLIs taken apart, including what the security market requires and where both leading
scanners get it wrong.architecture.md — the diagrams.lineage.md — the six projects we follow, each reduced to a
commitment.Four locks — shape, process-reference, weight per entry point, and the adoption ladder — are
each proven to fail before they passed. A compat façade does not reach 1.0 until its host's
own suite passes 100% (C7): both do today, which clears that gate and not the rest —
burgee's 1.0 waits on the floor, 114 requirements of
which the surfaces, the env/config/schema families and both façades are built. Until then the
rate is published rather than the word "compatible" claimed. linegauge and flagstaff have
already met every written 1.0 criterion and are 1.0: every requirement in each spec is built
(13 of 13 and 12 of 12), and each drop-in path passes its incumbent's own suite in full
(D-170).
npm install
npm test # every lock and unit test, exits non-zero on failure
npm run dev # docs on http://localhost:3100
npm run compat # grade burgee against commander's and yargs' own suites
npm run brand # regenerate every brand surface from one declaration
npm run brand:check # …and fail if any of them was hand-edited since
This repo runs 12 Interlace ESLint plugins with every rule on at error and zero
warnings allowed:
The rule list is computed from each plugin's own table, so a rule shipped in a plugin release
is on here the day it lands — browser-security alone brings 41. Every exception is named in
eslint.config.mjs with its reason.
The three scoped to apps/ are scoped for a reason: the engine never runs in a browser, so
storage, postMessage and DOM-sink rules have nothing to say about it — but the docs app is
a real browser application, and that is exactly the surface they grade.
It earns its keep. During this project those rules caught a prototype-pollution vector in
our own option parsing, a barrel import that cost ~5ms of startup, and a façade reaching for
process behind the runtime seam.
The most useful thing anyone can send is an adopter we did not write: a real CLI ported over, and a report of what broke. That is the only compatibility evidence that counts, and every failure becomes a case in the conformance suite.
CONTRIBUTING.md has the loop, how a change is shaped before it is written, and what the checks will hold you to. SECURITY.md is the private reporting path — please do not open a public issue for a vulnerability.
MIT © Ofri Peretz — see LICENSE. Every published package ships the licence text in its tarball.
A CLI framework built on one declaration: help, --json, --schema, MCP, completions and types are projected from it, with exit codes and fix: lines an agent can act on. No dependency outside the burgee
{ "mcpServers": { "burgee": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}ภาพรวม
A CLI framework built on one declaration: help, --json, --schema, MCP, completions and types are projected from it, with exit codes and fix: lines an agent can act on. No dependency outside the burgee family. Drop-in paths for commander, yargs and meow.
เครื่องมือ
ยังไม่มีรายการเครื่องมือ เซิร์ฟเวอร์แบบรีโมตจะได้รายการหลังการตรวจสอบสถานะครั้งแรก
FAQ
คัดลอกคอนฟิก stdio สำหรับ Cursor, Claude Desktop, Claude Code หรือ VS Code ได้ในหน้านี้ คอนฟิกนี้ใช้การติดตั้งของผู้เผยแพร่ ไม่ใช่พร็อกซีของ PlugMCP
ระเบียนนี้ไม่ได้ระบุตัวแปรสภาพแวดล้อมที่จำเป็น
Burgee ทำงานแบบโลคัลผ่าน stdio
ตรวจสอบล่าสุดเมื่อ 2026-11-14 A CLI framework built on one declaration: help, --json, --schema, MCP, completions and types are projected from it, with exit codes and fix: lines an agent can act on. No dependency outside the burgee family. Drop-in paths for commander, yargs and meow.