Skip to content

AI agents

Wire your agent to the library's knowledge base, manifest, markup check, MCP server and ESLint plugin.

On this page

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 an attribute.

bitboss-ui ships four things instead:

  • a knowledge base written for agents
  • a manifest of every component's real surface
  • a check that validates your markup and stylesheets against that manifest
  • 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 checkboxes, radios, switches, sliders, ratings, avatars, icons and spinners. Nothing throws; the attribute lands on the DOM node and does nothing. The same goes for names borrowed from elsewhere: toast.success(), v-model:open on a dialog, variant="danger".

Stale API. Training data is full of v2 and of earlier 3.0 betas. showClose, allowWriting, noDataText 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:

bash
npx bitboss-ui ai-init

It does four 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:

  • AGENTS.md, for Cursor, Codex and most other agents. The command adds a marked fragment and leaves the rest of the file alone.
  • .cursor/rules/bitboss-ui.mdc, for Cursor.
  • .github/copilot-instructions.md, for GitHub Copilot, again as a marked fragment.
  • .claude/skills/bitboss-ui/SKILL.md, for Claude Code.
  • .windsurf/rules/bitboss-ui.md, for Windsurf.

It sets vueCompilerOptions.checkUnknownComponents: true in your tsconfig, so a mistyped or removed component is a type error (in Nuxt it tells you where to set it instead).

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. Some starters (Laravel's vue starter kit) git-ignore AGENTS.md, CLAUDE.md, .claude, .cursor and .mcp.json; un-ignore them, or your teammates never get the pointers. Re-run it after every upgrade, so the pointers name the version you have. --update is an alias that reads better in a script:

bash
npx bitboss-ui ai-init --update

To write the pointers only, with no MCP config and no install, opt out:

bash
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 a hop map, not one large document. The agent opens the router, then one contract or recipe, and loads a few kilobytes instead of the whole catalogue.

The route an agent takes:

  • 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.
  • guides/component-picker.md: which component fits a need, and the markup that means one already exists.

One contract per thing:

  • <Component>.md: one per component, with props, events, slots, v-model and pt parts.
  • composables/<name>.md: one per composable, such as useToast, useConfirm or useBbFormField.
  • source/<Component>.md: the component's full implementation (template, types, CSS). Only for rebuilding chrome the library does not ship.

Data for scripts and tools:

  • components.json: the machine-readable API surface of every component, plus the public types.
  • design-tokens.json: the --bb-* tokens as data, covering colours, radius, type and spacing.
  • changelog.json: every breaking change since v2, with the version that shipped it.

Playbooks and the rest:

  • guides/*.md: cross-cutting playbooks on coherence, options and items, forms, passthrough.
  • recipes/{vue,nuxt,inertia}/: whole-page shapes, one file per platform.
  • guides/migration/: the v2 upgrade, the class renames between 3.0 betas, and v3-beta-tooling.md for scripts that parse these files.
  • index.md: the full catalogue. A last resort, not a first stop.

If the agent can only fetch URLs, the same knowledge base is hosted. Give it one of these:

  • https://llms-bitboss-ui.bitboss.it/dist/llms-medium.txt: about 260 KB, the rules, setup, component picker, design language and catalogue in one request. Fetch this one if the agent takes only one.
  • https://llms-bitboss-ui.bitboss.it/llms.txt: a 27 KB index of every document.
  • https://llms-bitboss-ui.bitboss.it/dist/llms-full.txt: everything concatenated, about 6 MB, for bulk ingestion only.

Installed, the three files resolve as bitboss-ui/llms.txt, bitboss-ui/llms-medium.txt and bitboss-ui/llms-full.txt.

components.json is not a side artifact. Every API table on this site is generated from it. The guides around the tables are written by hand, but the surface you read here comes from the file an agent reads.

Checking the markup

The check 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:

bash
# every .vue and .md below this directory
npx bitboss-ui check
# one directory; prefer it to a quoted glob
npx bitboss-ui check src
# only the files git reports changed: the fast loop after an edit
npx bitboss-ui check --changed
# findings as JSON, for a CI annotation step
npx bitboss-ui check --json
# also list what the app still builds by hand (report-only)
npx bitboss-ui check --idioms

A finding names the file, the line and the fix:

text
[bitboss-ui] check FAILED — 2 finding(s) across 1 file(s):

  src/CustomerForm.vue
    ✗ line 6: prop `color` is not in BbButton's API
    ✗ line 7: prop `show-close` was removed from BbDialog; use `hideClose`
      hint: ai/guides/migration/components/bb-dialog.md

It exits non-zero on findings, which makes it a CI step. It also exits non-zero when an explicit path matches nothing, so a typo in a CI path cannot validate zero files and pass. What it reports, grouped:

AreaFindings
Markupunknown or removed props, v-model targets, events and slots; a variant from another library (unknown-variant: danger on BbAlert); href or method on a component that ignores them
Accessibilityan icon-only BbButton or BbBadge, or a BbProgress, with no accessible name (nameless-control)
Itemsobject items with neither a label nor a text key and no item-text (object-items-without-text); an item-text / item-value that restates the default (redundant-item-accessor, a warning); a dropdown, tab or breadcrumb item still spelled key / text (renamed-item-field); a dropdown row in a selectable group with no value (missing-value) or a selectable group with no id (missing-id); a BbTable column keyed like one of its own slots (reserved-key)
Formsv-model on a BbForm (form-v-model: it takes :model); two fields on one path, a row in a v-for with no name, rules a schema will ignore, a string rule nothing registers
Integrationa Bb* tag the file never imports, which renders empty (unimported-component); a trigger in a BbDropdown's default slot, which opens nothing (dropdown-default-slot); a BbCollapsible toggle with no aria-expanded (collapsible-trigger-aria); a v-model on a reactive() const (reactive-v-model); a portal name nothing declares (unknown-portal); a v-bb-dialog / v-bb-off-canvas or context id no dialog declares (unknown-dialog)
Your componentsa wrapper that declares Bb*Props and never passes some of them on (wrapper-drops-props): a caller's disabled or pt goes nowhere; Preset components shows the fix
Stylesheetsa selector on a .bb-* class the library no longer renders (unknown-class, renamed-class), a token or local nothing reads (inert-token, inert-local), a hand-imported styles.css
Importsthe retired bitboss-ui/validated entrypoint, an import from inside dist/, a Pt* type the package does not export

npx bitboss-ui check --fix applies the automatic migrations to your .vue files first (renamed props, slots and pt keys, inverted booleans, retired imports), then reports what is left for you. It needs eslint and vue-eslint-parser installed. The check respects eslint-disable comments, so a finding you silenced on purpose does not fail CI.

Around an upgrade, judge your code against the new version before you install it, then list what broke since the version you were on:

bash
# before installing: which of your files the new version breaks
npm pack bitboss-ui@beta && tar -xzf bitboss-ui-*.tgz
npx bitboss-ui check --manifest package/dist/ai/components.json

# after installing: every break since the version you had
# (the one npm ls bitboss-ui printed before the upgrade)
npx bitboss-ui changelog --since <old-version>

Do not name your own components Bb…; use your app's prefix. If you already have one, the check leaves it alone when it can see it is yours (imported from a local file, or a .vue in your components/ directories) and prints a single local-bb-component warning. allowComponents in package.json is only for a component registered globally, where no import shows:

package.json
{
    "bitboss-ui": { "allowComponents": ["BbRichEditor"] }
}

The MCP server

The MCP server answers the same questions as the files in dist/ai/, as tool calls: an agent asks for one component or one list of changes instead of opening files.

ToolAnswers
search_docs"How do I…": the guide or component section that answers it, old names included
search_components, get_componentThe catalogue, then one component: every prop, event, slot and pt part. Also resolves type names and renamed v2 or beta names
get_guide, list_guides, get_composableA playbook or a composable's contract
list_recipes, get_recipeWhole-page shapes for Vue, Nuxt and Inertia
list_tokensThe design tokens and their values
list_changesThe breaking changes between two versions, class renames included
validateThe markup check, on a snippet

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:

FileHarness
.mcp.jsonClaude Code
.cursor/mcp.jsonCursor
.vscode/mcp.jsonVS 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"]
        }
    }
}

Three things to know:

  • Windsurf is not registered: it reads one global config in your home directory, and a project command should not edit that. Add the entry to ~/.codeium/windsurf/mcp_config.json yourself, with the absolute path to this project's node_modules/bitboss-ui/bin/bitboss-ui.mjs. ai-init still writes the .windsurf/rules pointer.
  • The two dependencies are optional peers. @modelcontextprotocol/sdk and zod weigh about 12 MB, so installing bitboss-ui never pulls them in. ai-init installs them; if that fails, it prints the command and writes the config files anyway.
  • You can skip the server and lose no knowledge. It only reads node_modules/bitboss-ui/dist/ai/, 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 Installation for the option.

vite.config.ts
bitbossUi({ mcp: true });

Catching it in the editor

The library ships an ESLint plugin, so the same manifest checks run while typing rather than at review. The recommended preset is an array: spread it. It parses <script setup lang="ts"> once @typescript-eslint/parser is installed.

bash
npm i -D @typescript-eslint/parser
eslint.config.js
import vue from 'eslint-plugin-vue';
import tsParser from '@typescript-eslint/parser';
import bitbossUi from 'bitboss-ui/eslint-plugin';

export default [
    ...vue.configs['flat/recommended'],
    { files: ['**/*.ts'], languageOptions: { parser: tsParser } },
    {
        files: ['**/*.vue'],
        languageOptions: { parserOptions: { parser: tsParser } },
    },
    ...bitbossUi.configs.recommended,
];

Without the TypeScript parser, every .vue file with a TS script block fails to parse, and no rule runs on it at all. eslint --fix applies the registered v2 renames and polarity flips; a "did you mean" hint is never applied for you.

Beyond unknown props, slots and events, recommended flags the mistakes that render without complaint:

  • an icon-only button with no accessible name (require-accessible-name)
  • method on a BbButton with no href (require-partner-prop)
  • a string rule in rules that nothing registers (no-unregistered-rule)
  • a v-model on a BbForm (form-model)
  • a trigger in a BbDropdown's default slot (dropdown-default-slot)
  • a Bb* tag the file never imports (no-unimported-component)
  • a BbCollapsible toggle with no aria-expanded (collapsible-trigger-aria)
  • a v-model on a reactive() const (no-reactive-v-model)
  • a portal name, or a dialog id, nothing declares (portal-names)
  • an import from bitboss-ui/validated (no-retired-entrypoint)
  • a var(--bb-…) token the library does not declare (no-unknown-token, a warning)
  • a v2 :reverse="false" (no-reverse-false)
  • a dropdown, tab or breadcrumb item still spelled key / text (no-renamed-item-field, which rewrites it)
  • an item-text / item-value that restates the default (no-redundant-item-accessor, a warning it fixes)

Keep explicit imports. With checkUnknownComponents (ai-init sets it), a mistyped or removed component becomes 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.