# sdocs — full reference
> sdocs is a documentation tool for Svelte 5 components. It renders `.sdoc`
> files into a documentation site: a `.sdoc` file is a documentation format that
> *contains* Svelte — the file's structure is sdoc, and Svelte lives inside
> designated blocks. This is a complete, self-contained reference — setup,
> configuration, the CLI/build, and the full `.sdoc` authoring format — for
> developers and coding assistants. Live docs: https://gabilungu.github.io/sdocs/
## Requirements
- **Node 22 or newer** (what the package declares and CI verifies). A `.ts`
config additionally needs a Node with native type stripping.
- Svelte 5
- Vite with `@sveltejs/vite-plugin-svelte`
Install `@sveltejs/vite-plugin-svelte` in the project even when running via
`npx`. sdocs takes the compiler from the project's plugin and pins the browser
runtime to the project's `svelte`, so both halves come from ONE copy. Without
the plugin, sdocs must compile with its own bundled svelte while your components
run against yours; mismatched versions then break generated-code contracts (blank
pages, `is not a function` from svelte internals). sdocs warns when it detects
that split.
## Setup
Install into a Svelte 5 project:
```bash
npm install sdocs
```
Or skip installing entirely — with `.sdoc` files present, `npx sdocs run`
fetches sdocs into the npx cache and serves them, resolving your components'
dependencies (and your project's own `svelte`) from the project.
Scaffold a config (optional — the defaults work with zero config):
```bash
npx sdocs init
```
This writes a config with every option present but commented out. The file is
`sdocs.config.js` when the project's 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.
Write a first doc next to a component (`src/lib/Button.svelte` →
`src/lib/Button.sdoc`):
```sdoc
[SHOWCASE title="Components / Button" description="A flexible button."]
[COMPONENT component={Button} args={{ label: 'Click me', disabled: false }}]
[/COMPONENT]
[/SHOWCASE]
```
Run it:
```bash
npx sdocs dev # dev server at http://localhost:3000
```
## CLI / building
| Command | Description |
|---|---|
| `npx sdocs init` | Scaffold a config file (no-op if one exists) |
| `npx sdocs dev` | Dev server with live reload (default port 3000) |
| `npx sdocs run` | Same as `dev`, but works without installing sdocs |
| `npx sdocs build` | Build a static site to `dist/` |
| `npx sdocs preview` | Serve the built `dist/` locally |
| `npx sdocs check` | Compile every doc stage, validate the site structure, report what breaks (exits 1 on error) |
| `npx sdocs coverage` | Report which components have a `[COMPONENT]` preview |
| `npx sdocs mcp` | Serve the sdocs MCP server on stdio (authoring tools for agents) |
Global flags: `--version`/`-v`, `--help`/`-h` — recognised anywhere in the
arguments, and they never run the command (`sdocs build --help` prints help
and writes nothing).
Per-command options:
| Flag | Commands | Meaning |
|---|---|---|
| `--port ` | `dev`, `run`, `preview` | Serve on this port instead of the configured one. Taken literally: an occupied port stops the server rather than moving to another. |
| `--open` / `--no-open` | `dev`, `run`, `preview` | Open a browser on start, or don't |
| `--base ` | `build` | Public base path (see `base`) |
| `--out-dir ` | `build` | Where to write (see `outDir`) |
Anything else is an error naming the offending option and what that command
accepts — a misspelled flag is never accepted in silence.
All commands read
`sdocs.config.js` (or `.ts`/`.mjs`) from the current directory; the config is
read once at startup, so **restart the dev server after editing it**.
`sdocs dev` watches the `.sdoc` files matching `include` and each documented
component's source, reloading on change.
`sdocs build` prerenders every route to a real `index.html` (with a per-route
`` and meta description) that hydrates on load, plus a `404.html`
fallback — deep links work with no rewrite rules on any static host (GitHub
Pages, Netlify, Vercel, S3). `build` runs `check`'s work first, so everything
that command calls an error fails the build: site-structure errors (unknown
`@section`, two entities on one route, unresolvable `home`), grammar errors, an
unresolved `component={…}`, and a stage that does not compile. Checking first is
also what makes the message readable — Vite would report a stage error against
the virtual module (`/@sdocs/iframe//x.svelte (81:2)`), while this path
names the `.sdoc` file and line. A stage error in `dev` still shows Vite's
overlay with the virtual id; run `sdocs check` for the mapped location. Pass `--base` when
serving under a sub-path (a GitHub *project* Pages site lives at `//`):
```bash
npx sdocs build --base "/my-repo/"
```
`sdocs check` compiles every stage and validates the site structure without
starting a server or writing a build, printing each problem with its file,
entity, and stage, and exiting 1 when anything errors — the CI gate for "do all
the docs still work?". The MCP `check_docs` tool runs the same check.
`check` and `build` both fail on site-structure errors (unknown `@section`, two
entities on one route, an unresolvable `home`) and on a `component={…}`
reference that resolves to no component file — one map, read the same way, so
`check` never passes a site `build` would refuse. The dev server only warns
about the latter, so the doc can be fixed while it runs.
Because `run`/`build` need no local install, CI can build a docs site from a
project that doesn't even depend on sdocs: `npx --yes sdocs build` then publish
`dist/`.
**Embedding** — instead of the standalone server, mount sdocs as a route in an
existing Vite/SvelteKit app via its Vite plugin (`sdocsPlugin()`); options
passed there override the config file, and `routing` defaults to `'hash'` when
embedded.
## MCP server
sdocs ships an MCP server with authoring tools, so an agent can validate and
scaffold `.sdoc` files against the real parser instead of guessing — and read
the current project's components and docs through the same extraction the
Explorer uses:
- `validate_sdoc { source }` — parse `.sdoc` text and return diagnostics
(message, code, 1-based line/column), the entities found, and each entity's
resolved `route`. Check the route before committing to a title: slugs
lowercase each segment whole, so `IconButton` serves at `/iconbutton`.
- `scaffold_component_doc { componentPath, title? }` — extract a `.svelte`
component's props and return a starter `.sdoc` (control defaults derived
from the props) plus the suggested file path; it never writes files.
- `get_authoring_guide { section? }` — this guide. It runs to about 40k
characters, so pass `section` when you only need one part of it:
`section: 'prose'` returns the `[PROSE]` chapter alone, matching a
case-insensitive substring of the heading. A section that matches nothing
comes back as the list of headings. Also exposed as the
`sdocs://authoring-guide` resource.
- `get_changelog { since? }` — this install's `CHANGELOG.md`. With `since`, the
reply leads with every **breaking** change released after that version, then
the full entries.
**Call it whenever the project's installed sdocs is newer than the version
this guide describes.** `list_docs` reports the running version; a `.sdoc`
written against an older format may not parse. This is the migration path —
there is no separate migration tool, because the breaking sections of the
changelog are what a migration would say.
- `list_docs {}` — map the project's documentation: every `.sdoc` file the
config's `include` globs match, each with its entities (kind, title), the
**route** each one serves at (plus a route per example), the components its
previews document, and everything the entity carries — its `notes`, its
`[TODO]` tree, its `[GLOSSARY]` terms, and each component's `status`. The routes come from the Explorer's own router, so
they're exactly what the site serves — drive a browser over them to smoke
test every page.
- `search_docs { query?, type?, limit? }` — 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`, a `[GLOSSARY]` term or its
definition, a `[TODO]` line, or the text of any `notes` on either. Matching is a case-insensitive **substring**, so `butt` finds
`Button` and `menu` finds every example tagged "user menu". `type` sweeps by
note status instead — `type: 'bug'` lists everything marked bug with no query
at all, and `'none'` finds notes written without one; give both
and a result has to satisfy both. Each hit says which names matched, the
notes it carries, and the route it serves at — pass that route to
`resolve_visual_target` to screenshot it. Reach for it before reading files.
- `set_notes { file, entity, example?, notes }` — replace a `[NOTES]` block's
contents. Pass the whole list you want; an empty one removes the block. Each
note is `{ note, type? }` with type `bug`/`a11y`/`warning`/`perf`/`tip`/`info`.
- `set_status { file, entity, component, status }` — set a `[COMPONENT]`'s
status, or `null` to remove it. Name the component by its `component={…}`
identifier, or by its `title="…"` when one entity previews the same component
twice.
- `set_todos { file, entity, example?, todos }` — replace a `[TODO]` checklist.
Items are `{ text, done?, children? }`, nesting to any depth.
- `toggle_todo { file, entity, example?, path, done }` — tick one item by its
position at each level (`[1, 0]` is the first child of the second root item,
as `list_docs` reports the tree). Rewrites one character; prefer it to
`set_todos` when you are only ticking something off.
**The four writes above edit the project's `.sdoc` files.** Each rewrites the
smallest span that will do — a block's own span, or a single attribute — so
formatting, comments and every other byte survive. Reach for them rather than
editing `.sdoc` text yourself: they cannot produce a file that does not
parse. Each refuses any path the project's `include` globs do not already
match.
- `check_docs { file? }` — **compile** every stage (previews, examples, page
and layout bodies) the way the dev server does and report what breaks:
Svelte compile errors, relative imports that resolve to no file, and grammar
diagnostics — with the file, entity, stage, and a `.sdoc` line where it maps
cleanly — plus site-structure errors when checking the whole project.
`validate_sdoc` only checks the grammar; this catches what otherwise appears
only when the route is opened. Omit `file` to check the whole project. It
does not type-check and cannot see runtime-only failures: a stage whose
`
```
`sdocs/ui` resolves even in standalone projects (the CLI provides its own copy).
## `[LAYOUT]` — a full-page composition
Body is full Svelte, rendered full-width in an **isolated frame**: the host app's
styles don't leak in — only `config.css` plus the file's own `