CLI

@xds/cliv0.0.13
Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.

@xds/cli

The XDS CLI is the primary interface for working with the XDS design system — for humans and machines alike. It provides component documentation, design tokens, page templates, theming tools, and upgrade codemods, all accessible via terminal commands, a typed JSON API, or programmatic imports. AI agents and build tools use the same API that powers the CLI, enabling end-to-end frontend development loops.

bash
npx xds --help
npx xds component Button
npx xds docs tokens
npx xds template --list

Commands

CommandDescription
initInitialize XDS in your project — installs packages, sets up theming, adds AI agent docs
componentList components or print detailed docs, props, usage examples, and source
docsPrint reference documentation (tokens, theme, color, typography, spacing, etc.)
templateInject page or block templates into your project
hookList hooks and print hook documentation
swizzleCopy component source into your project for deep customization
upgradeRun codemods to migrate between XDS versions
theme buildCompile a defineTheme file to production CSS and JS
discoverDiscover external XDS packages and components
gap-reportReport a gap when a component doesn't meet your needs

Global options

These flags work with any command:

  • --json — Output as typed JSON envelope: { type, data }
  • --detail <level> — Detail level: full, compact, or brief
  • --zh — Output docs in Chinese Simplified
  • --dense — Compressed format (token-efficient, useful for AI agents)
  • --lang <locale> — Language/format shorthand (en, zh, dense)

JSON API

Every command supports --json for machine-readable output. Responses are typed envelopes:

json
{"type": "component.detail", "data": {"name": "Button", ...}}

Errors:

json
{
"error": "No component named \"Buttn\"",
"suggestions": [{"name": "Button", "reason": "similar name"}]
}

Programmatic API

The same logic that powers xds --json is available as importable, type-safe functions:

typescript
import {component, docs, discover, template, XDSError} from '@xds/cli/api';
// Same result as: xds --json component Button
const btn = await component('Button');
btn.type; // 'component.detail'
btn.data.name; // 'Button' (typed as ComponentDoc)
// Same result as: xds --json component --list
const list = await component(undefined, {list: true});
list.data; // Record<string, string[]>
// Same result as: xds --json docs principles
const principles = await docs('principles');
principles.data.title; // 'XDS Principles'
// Errors throw XDSError with optional .suggestions
try {
await component('Buttn');
} catch (e) {
e.message; // 'No component named "Buttn"'
e.suggestions; // [{ name: 'Button', reason: 'similar name' }]
}

The CLI command handlers are thin wrappers around these functions — they parse args, call the API, then format the output (JSON or text). This guarantees that @xds/cli/api and xds --json always return identical data.

Consumer utilities

If you're spawning the CLI as a subprocess rather than importing the API directly:

typescript
import {parseResponse, isError, assertResponse} from '@xds/cli/json';
import type {ComponentDetailResponse, CLIResult} from '@xds/cli/json';
const result = parseResponse(stdout);
if (isError(result)) {
console.error(result.error);
} else {
switch (result.type) {
case 'component.detail':
result.data.name; // TypeScript: ComponentDoc
break;
}
}
// Or assert directly (throws on error/mismatch):
const detail = assertResponse(stdout, 'component.detail');
detail.data.name; // already narrowed

Type discriminators

Every response has a type string that uniquely identifies it:

CommandTypeResponse
xds --json component [--list]component.listComponentListResponse
xds --json component --detail briefcomponent.briefComponentBriefResponse
xds --json component <name>component.detailComponentDetailResponse
xds --json component <name> --propscomponent.detail.propsComponentDetailPropsResponse
xds --json component <name> --sourcecomponent.detail.sourceComponentDetailSourceResponse
xds --json component <name> --showcasecomponent.detail.showcaseComponentDetailShowcaseResponse
xds --json component <name> --blockscomponent.detail.blocksComponentDetailBlocksResponse
xds --json discoverdiscover.listDiscoverListResponse
xds --json discover @scope/namediscover.detailDiscoverDetailResponse
xds --json discover @scope/name/Compdiscover.detail.docDiscoverDetailDocResponse
xds --json discover <search>discover.searchDiscoverSearchResponse
xds --json docsdocs.listDocsListResponse
xds --json docs <topic>docs.detailDocsDetailResponse
xds --json docs <topic> <section>docs.detail.sectionDocsDetailSectionResponse
xds --json template [--list]template.listTemplateListResponse
xds --json template <name>template.showTemplateShowResponse
xds --json template <name> --skeletontemplate.skeletonTemplateSkeletonResponse
xds --json template <name> [path]template.copyTemplateCopyResponse
xds --json hook [--list]hook.listHookListResponse
xds --json hook <name>hook.detailHookDetailResponse
xds --json swizzle [--list]swizzle.listSwizzleListResponse
xds --json swizzle <component>swizzle.copySwizzleCopyResponse
xds --json theme build <file>theme.buildThemeBuildResponse
xds --json upgrade --listupgrade.listUpgradeListResponse
xds --json upgrade [--apply]upgrade.runUpgradeRunResponse
xds --json gap-report --list-categoriesgap-report.categoriesGapReportCategoriesResponse
xds --json gap-report --component X ...gap-report.fileGapReportFileResponse
any errorCLIError
unsupported commandCLIUnsupportedError

Configuration

The CLI reads from an optional xds.config.mjs in your project root:

javascript
export default {
templates: {
get: async id => fetchTemplateFromAPI(id),
},
gapReport: {
url: 'https://your-api.com/gaps',
},
};