Full reference for every sdocs command and flag.
Commands
| Command | Description |
|---|---|
npx sdocs init | Scaffold a config file in the current directory |
npx sdocs dev | Start the dev server with live reload |
npx sdocs run | Same as dev — works without installing sdocs (see below) |
npx sdocs build | Build a static documentation site to dist/ |
npx sdocs preview | Preview the built site locally |
npx sdocs check | Compile every doc stage, validate the site structure, report what breaks |
npx sdocs coverage | Report which components have a [COMPONENT] preview |
npx sdocs mcp | Serve 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
| Flag | Commands | Description |
|---|---|---|
--version, -v | any | Print the package version |
--help, -h | any | Print the help message |
--port <n> | dev, run, preview | Serve on this port instead of the configured one |
--open / --no-open | dev, run, preview | Open a browser on start, or don't |
--base <path> | build | Public base path (see base) |
--out-dir <dir> | build | Where 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:
.sdocfiles matchinginclude- Each doc's
meta.componentfile
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 runnpm 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
homethat resolves to nothing. These are the same checkssdocs buildrefuses 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 checkerror 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 coverageUndocumented (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.sdoctext and return the diagnostics (message, code, 1-based line/column) plus the entities found.scaffold_component_doc— extract a.sveltecomponent's props and return a starter.sdocwith 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 thesdocs://authoring-guideresource, and on the web as /llms.txt). It runs to about 40k characters, so asectionnarrows 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 asinceversion 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.sdocfile the config'sincludeglobs 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'ssynonyms, an example title, an example'stags, or the text of any[NOTES]. Matching is a case-insensitive substring —buttfindsButton. Atypesweeps 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 toresolve_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
includeglobs don't already match. They exist because an agent asked to "mark Button deprecated" will edit that.sdocone 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 assdocs check. Takes an optionalfileto 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 assdocs 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, andclass/…restforwarding — 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 captured | Pixels | ≈ image tokens |
|---|---|---|
| The Explorer page | 1934×1162 | ~1970 |
| The stage | 1934×64 | ~108 |
| The component | 42×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:
| Thing | Where |
|---|---|
| Ready marker | <html data-sdocs-stage-ready> — set after mount, webfonts, and image decode |
| Failed stage | <html data-sdocs-stage-error="render | script | timeout"> |
| Identity | window.__sdocs.stage → { id, kind, name, component } |
| Capture rect | window.__sdocs.captureRect(selector?, { padding }) |
| Ink overflow | window.__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 mcpThe 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
- Embedded in Vite / SvelteKit — run sdocs inside an existing app
- Configuration reference