Most component libraries leave a coding agent to guess. It reads a prop name off a blog post from two majors ago and writes markup that looks plausible. The mistake surfaces at runtime, or never: an unknown prop in Vue is just an attribute.
bitboss-ui ships four things instead. A knowledge base written for agents, a manifest of every component's real surface, a linter that validates your markup against it, and an MCP server your agent can query directly. One command sets up all of it.
Why this exists
Three failure modes cost the most, and each has a tool aimed at it.
Invented props. An agent writes color="primary" because every other library
has one. v3 removed color from nine components. Nothing throws; the attribute
lands on the DOM node and does nothing.
Stale API. Training data is full of v2. showClose, allowWriting,
thumbTranslate and type on BbIcon all read as current and are all wrong.
Right component, wrong situation. BbTag and a multiple BbSelect look
interchangeable until you notice one is for values the user invents.
Point your agent at it
Run one command in the app, after installing bitboss-ui:
npx bitboss-ui ai-init
It does three things. It writes a pointer to the knowledge base for every assistant the project might use, so an agent finds the rules without being told:
| File | Read by |
|---|---|
AGENTS.md (a marked fragment, the rest of the file is left alone) | Cursor, Codex, most other agents |
.cursor/rules/bitboss-ui.mdc | Cursor |
.github/copilot-instructions.md (a marked fragment) | GitHub Copilot |
.claude/skills/bitboss-ui/SKILL.md | Claude Code |
.windsurf/rules/bitboss-ui.md | Windsurf |
It registers the MCP server in .mcp.json, .cursor/mcp.json and
.vscode/mcp.json. And it installs the server's two dependencies,
@modelcontextprotocol/sdk and zod, as dev dependencies, using the package
manager your lockfile names.
Every write is idempotent and merges rather than overwrites: your own lines in
AGENTS.md and the other MCP servers you have configured survive. Re-run it
after every upgrade, so the pointers name the version you have. --update is an
alias that reads better in a script:
npx bitboss-ui ai-init --update
To write the pointers only, with no MCP config and no install, opt out:
npx bitboss-ui ai-init --no-mcp
What the agent reads
The knowledge base lives at node_modules/bitboss-ui/dist/ai/, exported as
bitboss-ui/ai. It is deliberately structured as a hop map rather than one large
document, so an agent loads a few kilobytes rather than the whole catalogue.
| File | What it is |
|---|---|
guides/ai-router.md | Start here. Which file to open next, in what order. |
guides/agent-contract.md | The hard rules, before any code is written. |
index.md | Full component catalogue, grouped, each linked to a typed contract. |
components.json | Machine-readable API surface of every component. |
<Component>.md | One contract per component: props, events, slots, v-model. |
guides/*.md | Cross-cutting playbooks: coherence, options and items, icons, forms. |
recipes/{vue,nuxt,inertia}/ | Whole-page shapes, one file per platform. |
If the agent can only fetch URLs, use the versioned package files under
dist/ai/ on your npm CDN. llms-medium.txt packs the router, contract, setup,
picker, design language and catalogue into one request. This is the package
knowledge base, not the locale-dependent documentation site.
That manifest is not a side artifact. The API reference tables are generated
from it. Every props table on this site renders components.json. The guides
around those tables are curated separately, but the component surface comes
from the same source an agent reads.
Checking the markup
The linter validates Bb* markup in your .vue and .md files against the
installed manifest, not against a copy of the rules. You are checked against the
version you actually have:
npx bitboss-ui check
It catches unknown and removed props, bad v-model targets, <template #slot>
names that do not exist, and href / to / method on a component that does not
declare them. It exits non-zero on findings, which makes it a CI step.
It also exits non-zero when an explicit glob matches nothing. A typo in a CI path that validates zero files silently is the failure this prevents.
If your app owns a component whose name happens to start with Bb, exempt it
rather than renaming:
// package.json
{
"bitboss-ui": { "allowComponents": ["BbRichEditor"] }
}
The MCP server
The MCP server lets an agent query the knowledge base instead of reading it blind. It can search the components, fetch one component's contract, look up a design token, read a guide or a recipe, list the breaking changes between two versions, and validate a snippet of markup, all without loading the catalogue into its context first.
The practical difference: an agent that can ask "what props does BbSelect take" answers from the installed version. An agent that cannot, guesses from training data, and training data is v2.
You never start the server yourself. ai-init registers it, and the harness
launches it on demand. Restart the harness once after the first run so it picks
the server up. Each harness gets an entry in its own format:
| File | Harness |
|---|---|
.mcp.json | Claude Code |
.cursor/mcp.json | Cursor |
.vscode/mcp.json | VS Code and Copilot |
The entry runs the installed binary, node node_modules/bitboss-ui/bin/bitboss-ui.mjs mcp,
not npx. That way it cannot fetch anything from the registry and always answers
from the version in your node_modules. The path is relative to the project, so
commit these files and the server works for your teammates too:
// .mcp.json
{
"mcpServers": {
"bitboss-ui": {
"command": "node",
"args": ["node_modules/bitboss-ui/bin/bitboss-ui.mjs", "mcp"]
}
}
}
Windsurf is not registered. It only reads one global config in your home
directory, and a project command should not edit that. If you use Windsurf, add
the entry to ~/.codeium/windsurf/mcp_config.json yourself. That file serves
every project, so give it the absolute path to this project's
node_modules/bitboss-ui/bin/bitboss-ui.mjs. ai-init still writes Windsurf's
.windsurf/rules pointer.
The two dependencies are optional peers. @modelcontextprotocol/sdk and
zod weigh about 12 MB together, more than every runtime dependency of the
library combined. Only the MCP server loads them, so installing bitboss-ui
never pulls them in. ai-init installs them for you. If that install fails, it
prints the command to run, and the config files are written anyway. The server
starts once the peers are there.
You can skip the server and lose no knowledge. The server only reads the
files in node_modules/bitboss-ui/dist/ai/. An agent that opens that directory
itself knows exactly as much, and npx bitboss-ui check runs without the peers.
If the project cannot take new dependencies, run ai-init --no-mcp and point
the agent at dist/ai/guides/ai-router.md.
In a Vite or Nuxt app, the plugin can register the server instead: pass
mcp: true and the dev server writes the same three files on boot. It never
installs anything, so run ai-init once for the peers. See
Nuxt for the option.
bitbossUi({ iconDir: './assets/icons', mcp: true });
Catching it in the editor
The library ships an ESLint plugin, so the same rules apply while typing rather than at review:
// eslint.config.mjs
import bitboss from 'bitboss-ui/eslint-plugin';
export default [bitboss.configs.recommended];
Pair it with vueCompilerOptions.checkUnknownComponents and explicit imports.
That combination turns a mistyped or removed component into a type error instead
of an empty space on the page.
The shortest reliable setup is ai-init, the recommended ESLint config and
npx bitboss-ui check in CI. Add MCP when the agent can use tools; keep the
file-based knowledge pointers either way, because they remain available to every
agent and in offline work.