Skip to content
sdocs

Commands

Full reference for every sdocs command and flag.

Commands

CommandDescription
npx sdocs initScaffold a config file in the current directory
npx sdocs devStart the dev server with live reload
npx sdocs runSame as dev — works without installing sdocs (see below)
npx sdocs buildBuild a static documentation site to dist/
npx sdocs previewPreview the built site locally
npx sdocs checkCompile every doc stage, validate the site structure, report what breaks
npx sdocs coverageReport which components have a [COMPONENT] preview
npx sdocs mcpServe the sdocs MCP server on stdio — authoring tools for agents

All commands read sdocs.config.js (or sdocs.config.ts / sdocs.config.mjs) from the current directory.

Flags

FlagCommandsDescription
--version, -vanyPrint the package version
--help, -hanyPrint the help message
--port <n>dev, run, previewServe on this port instead of the configured one
--open / --no-opendev, run, previewOpen a browser on start, or don't
--base <path>buildPublic base path (see base)
--out-dir <dir>buildWhere to write (see outDir)

--help and --version work anywhere in the arguments and never run the command: sdocs build --help prints this help and writes nothing.

Every other flag is an error. A command that reads no options rejects all of them, and one that does names what it accepts:

$ npx sdocs build --bse "/my-repo/"
[sdocs] Unknown option for `sdocs build`: --bse
[sdocs] It accepts --base, --out-dir.

A --port you asked for is taken literally — if it is occupied the server says so and stops, rather than quietly serving somewhere you aren't looking. Without the flag, the configured port still falls forward to the next free one unless port is set in the config.

sdocs init

Creates a starter config with every option commented out (the defaults work without any of them):

/** @type {import('sdocs').SdocsConfig} */
export default {
  // include: ['./src/**/*.sdoc'],
  // port: 3000,
  // open: false,
  // css: './src/styles/global.css',
  // title: 'sdocs',
  // logo: 'sdocs',
  // axes: [{ id: 'scheme', label: 'Theme', values: ['light', 'dark'] }],
  // sections: [{ slug: 'guides', title: 'Guides' }],
  // home: 'guides/getting-started',
};

The file is sdocs.config.js in a project whose package.json says "type": "module", and sdocs.config.mjs otherwise — the config is an ES module, and Node reads a bare .js as a CommonJS script.

No-op if a config file already exists.

sdocs dev

Starts a Vite dev server on the configured port (default 3000). Watches:

  • .sdoc files matching include
  • Each doc's meta.component file

Any change triggers a full reload. The config file itself is read once at startup — restart the server after editing it. See configuration for options like open, css, and title.

sdocs run — no install needed

Try sdocs in any project without adding it as a dependency:

npx sdocs run

npm fetches sdocs (and its tooling) into the npx cache and starts the dev server against the .sdoc files in the current project. Your components' dependencies — Tailwind, three.js, anything in the project's node_modules — resolve from the project as usual, and when the project has its own svelte, previews use it rather than the cached copy.

You still need .sdoc files for it to have something to show; see getting started.

sdocs build

Builds a static site to dist/.

Important

build empties its output directory first. If dist/ already holds files sdocs did not put there — a component library's own bundle, most often — the build stops and tells you, rather than deleting them. Point sdocs somewhere of its own with outDir:

export default { outDir: 'docs-dist' };

build runs sdocs check's work first, so anything that command reports as an error fails the build with a non-zero exit and a broken site can't deploy: site-structure errors (an unknown @section, two entities on one route, an unresolvable home), grammar errors, a component={…} reference that resolves to no component file, and a stage that doesn't compile.

Compiling up front is also what makes the message readable. Vite compiles the stages too and would catch the same errors, but it knows each one only as a virtual module, so what it prints is a base64 id and a line number from generated code:

/@sdocs/iframe/c3JjL0J1dHRvbi5zZG9j…/button.svelte (81:2)

Checked first, the same mistake reads:

error  src/Button.sdoc:14 › Forms / Button › Button
  Expected 'if', 'each', 'await', 'key' or 'snippet'

The dev server only warns about an unresolved component={…}, so a doc can be fixed while it runs. A stage that fails to compile in dev still shows Vite's own overlay, virtual id and all — run sdocs check to get the .sdoc line.

Every route is prerendered: its index.html contains the page's real HTML (sidebar, prose, a per-route <title>, the showcase description as its meta description), and the app hydrates on load — crawlers and no-JS readers get full pages, deep links work with no rewrite rules, and after hydration it behaves as the same single-page app the dev server runs. Live previews stage in their own pre-built iframe page per snippet; a 404.html fallback boots the app for unknown paths. A route whose server render fails falls back to client rendering with a build warning. Deploy anywhere that serves static files (GitHub Pages, Netlify, Vercel, S3).

Pass --base <path> when the site is served under a sub-path (a GitHub project Pages site lives at /<repo>/); it overrides the base config, which lets CI derive it from the repo name:

npx sdocs build --base "/my-repo/"

Because sdocs run/build need no local install, a docs site can deploy from a project that doesn't depend on sdocs at all — a CI job runs npx --yes sdocs build and publishes dist/.

sdocs preview

Serves the contents of dist/ locally. Requires sdocs build to have run first.

sdocs check

Compiles every documentation stage — each [COMPONENT] preview, each [EXAMPLE], and every [PAGE]/[LAYOUT]/[DOC] body — exactly the way the dev server does, and reports what breaks:

  • Svelte compile errors inside a stage (an unclosed tag, a malformed block) that the grammar check can't see,
  • relative imports that resolve to no file on disk (the specifier is read the same way the import rewriter reads it, so an import-shaped string inside a code sample is never mistaken for one),
  • grammar diagnostics from the parser,
  • component={…} references that resolve to no component file — the preview still renders, but its API tables and controls silently don't, so it's an error here and a build failure too,
  • site-structure errors — a title claiming a section the config never declared, two entities landing on one route, a home that resolves to nothing. These are the same checks sdocs build refuses to deploy past, run without building.

Each problem prints its file (with a line where it maps back cleanly), the entity, and the stage:

npx sdocs check
error  src/lib/Button.sdoc › Forms / Button › Disabled
  Unexpected block closing tag

[sdocs] 1 error(s), 0 warning(s) — checked 166 stage(s) in 35 file(s).

It exits 1 when anything errors, so CI can gate on it — no server, no build output. It doesn't type-check, and it can't see failures that only happen at runtime: a stage whose <script> throws compiles cleanly, and the throw shows up in the preview frame when someone opens the page. The MCP server's check_docs tool runs the same check.

sdocs coverage

Reports which components have a [COMPONENT] preview and which don't, measuring the components globs against every [COMPONENT] in the project:

npx sdocs coverage
Undocumented (1):
  src/lib/components/Toast/Toaster.svelte

[sdocs] 41/42 components documented (98%) — matched src/**/*.svelte.

References resolve through the same resolver the Explorer uses, so a compound family is measured per sub-component: component={NavTree} and component={NavTree.Item} land on different files and each counts on its own. Several previews of one component within a single .sdoc is a supported pattern (tabs) and is never reported as a duplicate — only a component documented from more than one file is.

It also reports [COMPONENT] references with no component source behind them, and documented components that fall outside the globs (usually a sign the globs are too narrow). It's a report, not a gate: it always exits 0. The MCP server's check_coverage tool returns the same data.

sdocs mcp

Serves the sdocs MCP server on stdio, so agent tooling can work against the real parser instead of guessing at the format — and read the current project's components and docs through the same extraction the Explorer uses:

  • validate_sdoc — parse .sdoc text and return the diagnostics (message, code, 1-based line/column) plus the entities found.

  • scaffold_component_doc — extract a .svelte component's props and return a starter .sdoc with control defaults derived from them, plus the suggested file path. It never writes files — the client does.

  • get_authoring_guide — the full authoring guide (also served as the sdocs://authoring-guide resource, and on the web as /llms.txt). It runs to about 40k characters, so a section narrows it to one chapter: section: 'prose' matches a case-insensitive substring of the heading, and a section that matches nothing comes back as the list of headings.

  • get_changelog — this install's changelog. With a since version the reply leads with every breaking change released after it, then the full entries. This is the migration path: an agent whose knowledge of the format predates the installed version calls it before writing anything, and there is no separate migration tool because the changelog's breaking sections are what one would say.

  • list_docs — map the project's documentation: every .sdoc file the config's include globs match, each with its entities, the route each one serves at (plus a route per example), and the components its previews document. Routes come from the Explorer's own router, so they match the live site exactly.

  • search_docs — find documentation by any name it goes under: the entity title, a component it previews, that component's synonyms, an example title, an example's tags, or the text of any [NOTES]. Matching is a case-insensitive substringbutt finds Button. A type sweeps by note status instead: type: 'bug' lists everything marked bug with no query at all. Every hit says which names matched, the notes it carries, and the route it serves at, ready to hand to resolve_visual_target.

  • set_notes, set_status, set_todos, toggle_todo — the four tools that write. They replace a [NOTES] block, set a [COMPONENT]'s status, replace a [TODO] checklist, or tick one item.

    Each rewrites the smallest span that will do — a block's own span, or a single attribute — so formatting and every other byte survive, and each refuses any path the project's include globs don't already match. They exist because an agent asked to "mark Button deprecated" will edit that .sdoc one way or another; a tool that splices the one attribute can't produce a file that doesn't parse.

  • check_docs — compile every stage and report Svelte errors, missing relative imports, and grammar diagnostics; the same check as sdocs check. Takes an optional file to check one document.

  • check_coverage — which components have a [COMPONENT] preview and which don't, plus duplicates, unresolved references, and components outside the globs; the same data as sdocs coverage.

  • resolve_visual_target — resolve a stage (a [COMPONENT] preview, an [EXAMPLE], a [LAYOUT]) to a preview-only route, the selectors an automation client waits on, and the files behind it. See visual inspection.

  • get_component_api — a component's full extracted API: props (types, defaults, descriptions), events, snippets, methods, states, CSS custom properties, and class/…rest forwarding — see prop extraction.

Visual inspection

Every stage is also its own page — open /@sdocs/preview/… directly and you get that one component, with the project's css and its declared args, and no Explorer around it. That matters when an agent is looking at your components through a browser: photographing the whole Explorer to inspect one button costs hundreds of times more image tokens than photographing the button.

What gets capturedPixels≈ image tokens
The Explorer page1934×1162~1970
The stage1934×64~108
The component42×36~2

resolve_visual_target takes the name you'd say out loud — "Button / Sizes", a route from list_docs (an entity route resolves to that entity's own stage, a stage route to that stage), or the id shown under a stage — and returns the preview route, source.component (the .svelte file to edit), source.doc with a line, the declared args, and the resolved stage layout. So what you see leads straight to what you change, without reproducing any slug rules.

Each stage page carries the pieces automation needs:

ThingWhere
Ready marker<html data-sdocs-stage-ready> — set after mount, webfonts, and image decode
Failed stage<html data-sdocs-stage-error="render | script | timeout">
Identitywindow.__sdocs.stage{ id, kind, name, component }
Capture rectwindow.__sdocs.captureRect(selector?, { padding })
Ink overflowwindow.__sdocs.inkBleed(selector?)

A stage always ends up marked ready, even when it fails — a client waiting on the marker gets an answer instead of a timeout.

captureRect exists for a specific trap: a screenshot cropped to an element's bounding box clips its shadow. A glow, a focus ring, or a filter: drop-shadow paints outside the border box, and that's usually the very thing under review. The helper reads the computed styles and grows the rect by the ink each element actually casts, then reports bleeds (the component paints outside its box) and clipped (the halo runs past the viewport — widen it, or give the stage more padding). The stage's own padding is the author's answer to the same question, which is why capturing #sdocs-preview is the safe default for a component with a halo.

A direct visit can also ask for a variant: ?theme=dark sets data-sdocs-theme on the stage document (for css keyed off the attribute — prefers-color-scheme is the browser's to emulate), and ?css=<name> picks between the stylesheets configured under css.

In dev, each stage shows its id on hover — click it to copy. That's the handle to hand an agent: "look at sdocs:k3f9a". The full procedure, with worked Playwright examples, is the sdocs://visual-testing-guide resource. sdocs takes no screenshots itself and depends on no browser.

Register it as a stdio server in any MCP client — for example:

claude mcp add sdocs -- npx -y sdocs mcp

The VS Code extension registers the same server with the editor automatically, and while sdocs dev runs, it's also served over HTTP at http://localhost:3000/mcp (stateless streamable HTTP — point a local MCP client at that URL). Built sites are static files and carry no MCP endpoint.

See also