# DreamLake — Full documentation
> Dockit is the DreamLake documentation shell — a Vike + React + Tailwind v4 component library and site framework with sidebar/TOC/search, MDX authoring conventions, and a versioned Netlify deploy pipeline.
Generated from https://dockit.dreamlake.ai. 23 pages.
---
Source: https://dockit.dreamlake.ai
# Dockit
Dockit is DreamLake’s documentation shell for Vike, React, Tailwind v4,
and MDX. Write pages with frontmatter; Dockit builds the sidebar,
breadcrumbs, table of contents, search, and Markdown copies for agents.
## Start building
Follow the [Quickstart](/get-started/quickstart.md) to install the package
and wire a working site. If you already have a DreamLake docs site,
use the [migration guide](/get-started/migration.md).
## Three places to work
| Tab | What belongs here |
| --- | --- |
| **Dockit** | Setup, authoring, customization, search, and publishing. |
| **[Reference](/reference/config.md)** | Configuration fields, exports, and component APIs. |
| **[Python Autodoc](/python-autodoc.md)** | Generate Python API pages and include them in a Dockit site. |
Dockit and Reference share the Dockit package version. Python Autodoc
shows its own pinned source revision. See [versioning](/guides/releases.md)
for historical docs builds and version selectors.
## Build and publish
| Task | Guide |
| --- | --- |
| Configure branding, tabs, and sidebar sections | [Site config](/guides/site-config.md) |
| Write MDX and organize pages | [Authoring](/guides/authoring.md) |
| Customize colors and appearance | [Theming](/guides/theming.md) |
| Add full-text search | [Search](/guides/search.md) |
| Publish Markdown and an agent skill | [AI-readable docs and skills](/guides/llms.md) |
| Preserve builds and configure version switching | [Versioning](/guides/releases.md) |
| Review package changes | [Release notes](/get-started/release-notes.md) |
## Look up an API
Start with [configuration](/reference/config.md) or the [export index](/reference/exports.md).
The [shell reference](/reference/components/shell.md) covers Layout, Sidebar,
and TOC; [Topbar](/reference/components/topbar.md) covers tabs and version chips.
For MDX content, see [Callout](/reference/components/callout.md),
[CodeBlock](/reference/components/code-block.md), [Preview](/reference/components/preview.md),
[StatusTable](/reference/components/status-table.md), and [Chip](/reference/components/chip.md).
---
Source: https://dockit.dreamlake.ai/get-started/quickstart
# Quickstart
Install Dockit, wire its renderer and page discovery, then build a static documentation site. Dockit packages the MDX compiler, Tailwind plugin, and syntax highlighting; React and Vike are installed alongside it as peers.
## Requirements
- **Node 20+** (Vite 7 requires 20.19 or 22.12+)
- **pnpm** (any recent version; the DreamLake workspaces pin `pnpm@10.33.0`)
## Install
```bash
pnpm add @dreamlake/dockit
pnpm add react@latest react-dom@latest tailwindcss vike@^0.4.260 vike-react @mdx-js/react
pnpm add -D vite typescript pagefind @types/react@latest @types/react-dom@latest
```
Peer versions dockit expects (org convention: sites track `react@latest`;
the peer ranges are floors, not pins):
| Peer | Range |
| --- | --- |
| `react` / `react-dom` | `>=19.0.0` — use `latest` |
| `tailwindcss` | `^4.0.0` — **install it directly** (`pnpm add tailwindcss`); peer auto-install does not happen in Netlify's CI pnpm setup (verified empirically) |
| `vike` | `^0.4.210` declared — **use `^0.4.260`**, see below |
| `vike-react` | `^0.5.0` |
| `@mdx-js/react` | `>=3.0.0` |
| `vite` | `>=6.0.0` (optional — only needed for the `/vite` plugin factory) |
> **Warning:** Dockit nests Vike's plugin inside the `dockit()` plugin array, and the
> `vike prerender` CLI could not detect a nested plugin before 0.4.260
> (verified: 0.4.259 fails, 0.4.260 passes). Dev and `vite build` work on
> older versions — the failure only shows up at prerender time, so pin the
> floor now rather than debugging it at deploy time.
Everything else — `@mdx-js/rollup`, `@tailwindcss/vite`,
`@vitejs/plugin-react`, shiki and the remark/rehype plugins — comes in
as dockit's own dependencies. You never install them directly, and the
`dockit()` plugin factory wires them all. (`tailwindcss` is declared as a
peer AND belongs in your own dependencies — strict CI installs, Netlify
included, do not auto-install peers, and the shell's classes need it
resolvable at your site root.) If you are porting a site off
the old template, those are exactly the deps you get to delete — see
[Migrate an existing site](/get-started/migration.md).
> **Note:** Inside a pnpm workspace, depend on the library with
> `"@dreamlake/dockit": "workspace:*"` — this site does exactly that.
> See the [Netlify monorepo setup](/guides/releases.md) for the deploy side.
## Verify installation
```bash
pnpm exec vite --version # ≥ 7
pnpm exec vike --version # ≥ 0.4.260
node -e "import('@dreamlake/dockit').then(m => console.log(Object.keys(m).length, 'exports'))"
```
## Site structure
Create the following files:
```text
my-docs/
vite.config.ts # plugins: [...dockit()]
site.config.ts # initDocs(...) — the one place you configure
renderer/
+config.ts # re-export dockit's Vike config
+onRenderHtml.tsx # thin wrapper over @dreamlake/dockit/server
+onRenderClient.tsx # thin wrapper over @dreamlake/dockit/client
styles/app.css # tailwind + dockit styles
pages/
index/+Page.mdx # your first page
```
Already have a docs site on the hand-rolled DreamLake template? Skip
this page and follow [Migrate an existing site](/get-started/migration.md)
instead — it maps every old file onto the structure below.
## 1. Vite config
The `dockit()` factory returns the entire plugin stack — Tailwind v4,
MDX with frontmatter + GFM + shiki dual-theme highlighting, the
`?raw`-MDX loader, React, and Vike:
```ts file="vite.config.ts"
export default defineConfig({
plugins: [...dockit()],
server: { port: 3020 },
})
```
## 2. Site config
`initDocs` populates the shell's singletons: branding, the page list
(from an eager glob), the raw sources for search, sidebar section
order, and topbar tabs. See [SiteConfig](/reference/config.md) for every field,
and the [site config guide](/guides/site-config.md) for how the pieces
fit together.
```ts file="site.config.ts"
initDocs({
site: {
brand: 'MyProject',
subtitle: 'docs',
repoUrl: 'https://github.com/me/my-project',
docsRepoUrl: 'https://github.com/me/my-docs',
docsBranch: 'main',
breadcrumbRoot: 'MyProject',
url: 'https://docs.my-project.dev',
docsPagesPath: 'pages',
},
pageMetadata: import.meta.glob('./pages/**/+Page.mdx', { eager: true, query: '?frontmatter', import: 'default' }),
rawPages: import.meta.env.DEV ? import.meta.glob('./pages/**/+Page.mdx', {
eager: true, query: '?raw', import: 'default',
}) : undefined,
sectionOrder: ['Getting started', 'Guides', 'Reference'],
tabs: [], // or a TabDef[] — see /components/topbar
})
```
## 3. Renderer wrappers
Vike discovers hooks by their `+`-prefixed filenames, which cannot live
inside a published package — so your site carries three one-liners:
```ts file="renderer/+config.ts"
export { default } from '@dreamlake/dockit/vike'
```
```tsx file="renderer/+onRenderHtml.tsx"
// site.config MUST come first — it runs initDocs before anything renders.
```
```tsx file="renderer/+onRenderClient.tsx"
```
> **Warning:** The `site.config` import must be the first import in both renderer
> entries. It runs `initDocs` as a side effect; if the shell renders
> first, the sidebar and search see empty data.
## 4. Styles
```css file="styles/app.css"
@import "tailwindcss";
@import "@dreamlake/dockit/styles.css";
/* Point Tailwind at your own class usage: */
@source "../pages";
@source "../renderer";
```
Dockit's stylesheet carries the theme tokens, dark-mode overrides, and
its own `@source` directive so Tailwind also scans the library's
compiled components. Details in [Theming](/guides/theming.md).
## 5. First page
```mdx file="pages/index/+Page.mdx"
---
title: Introduction
section: Getting started
order: 0
---
# Hello
Welcome to the docs.
```
## Run it
```bash
pnpm exec vite # dev server
pnpm exec vite build && pnpm exec vike prerender
pnpm exec pagefind --site dist/client # build the search index
```
That is the whole site. Next, read the
[authoring guide](/guides/authoring.md) that make the sidebar build
itself.
## Deploying your site
The build is fully static, so any static host works: after
`pnpm build`, publish the `docs/dist/client` directory (or your docs
package's `dist/client`). On Netlify, point the site's publish
directory there and enable branch deploys — every pushed branch then
serves a snapshot at `--.netlify.app`, which is what
powers versioned docs URLs.
For versioned releases, the package ships a copy-in release kit at
`node_modules/@dreamlake/dockit/templates/` — `set-version.mjs`,
`version-branch.sh`, `versions.example.json`, and
`netlify.example.toml`. Copy them in, fill the marked `EDIT ME` block
with your Netlify site name, and follow
[Releases & versioning](/guides/releases.md) for the full flow.
## Orient your agents
Use the [agent setup fragment](/guides/llms.md#orient-your-agents) to describe your docs layout, authoring conventions, and generated skill to coding agents.
---
Source: https://dockit.dreamlake.ai/get-started/migration
# Migrate an existing site
The DreamLake docs sites started life as copies of one template — each
carrying its own `components/`, `lib/`, and renderer. Migrating one to
`@dreamlake/dockit` means deleting the vendored shell and keeping only
what is genuinely site-owned: pages, branding, and deploy config.
This playbook comes from a real migration —
[lakeshore-workspace PR #36](https://github.com/dreamlake-ai/lakeshore-workspace/pull/36),
which removed **5,910 lines and added 119**, with the prerendered HTML
byte-identical to the pre-migration baseline (modulo hashed asset
filenames). Your site should land in the same shape.
## Prerequisites
- Read the [Quickstart](/get-started/quickstart.md) first — migration is
"make the site look like that," and every target file is shown there.
- **`vike >= 0.4.260`.** Dockit nests Vike's plugin inside the
`dockit()` plugin array, and earlier versions' `vike prerender` CLI
cannot see a nested plugin (verified: 0.4.259 fails, 0.4.260 passes).
Bump the range as part of the migration.
- A green pre-migration build. Record the baseline numbers — prerendered
page count and pagefind's page/word counts — so you can prove parity
afterwards.
## What to delete
Everything that was extracted into the library. In lakeshore's case
this was 5,371 lines across 24 files:
- `components/` — the entire vendored shell (Sidebar, Topbar, TOC,
TabStrip, SearchPalette, CodeBlock, Callout, Preview, StatusTable,
theming, …)
- `lib/` — navigation, tabs, search-index, pagefind-search, and the
hooks
- `renderer/Layout.tsx`
- The bulk of `styles/app.css` — theme tokens, dark-mode overrides, and
component styles all live in the library's stylesheet now
What stays, because it is site-owned: `pages/**`, `public/**`,
`scripts/gen-llms.mjs`, `versions.lock.json`, `netlify.toml`, and any
version/release scripts.
## Old → new mapping
| Old (vendored template) | New (dockit) |
| --- | --- |
| `site.config.ts` (plain config object) | A single `initDocs()` call. Branding fields carry over unchanged (`brand`, `subtitle`, `repoUrl`, `docsRepoUrl`, `docsBranch`, `breadcrumbRoot`, `url`, `skill`, `summary`); add `versionChips`, `gitHash`, and `docsPagesPath`. |
| `lib/tabs.ts` (`TABS` array) | The `tabs` option of `initDocs` — same `TabDef` shape, moved verbatim. |
| `lib/navigation.ts` (`SECTION_ORDER`) | The `sectionOrder` option of `initDocs`, moved verbatim. |
| `vite.config.ts` hand-rolled plugin stack (MDX + remark/rehype + shiki + Tailwind + React + Vike) | `plugins: [...dockit()]`. Keep any site-specific prelude — version reads, `define` blocks, `server` options — around it, verbatim. |
| `renderer/+config.ts`, `+onRenderHtml.tsx`, `+onRenderClient.tsx` (real implementations) | Three thin re-export wrappers over `@dreamlake/dockit/vike`, `/server`, and `/client`. `site.config` must be the **first** import so `initDocs` runs before render. |
| `styles/app.css` (hundreds of lines of tokens and overrides) | Three lines: `@import "tailwindcss"`, `@import "@dreamlake/dockit/styles.css"`, plus `@source` lines for `../pages` and `../renderer`. |
The wrappers, config call, and CSS are spelled out file by file in the
[Quickstart](/get-started/quickstart.md); the full `initDocs` surface is
in the [config reference](/reference/config.md).
## package.json changes
Add:
```json
"@dreamlake/dockit": "^0.1.0"
```
Bump:
```json
"vike": "^0.4.260"
```
Remove the docs-stack deps the `dockit()` factory now provides:
`@mdx-js/rollup`, the remark/rehype plugins, `shiki`,
`@tailwindcss/vite`, and `@vitejs/plugin-react`. Keep the peers
(`react`, `react-dom`, `tailwindcss`, `vike`, `vike-react`, `@mdx-js/react`) and the
tooling (`vite`, `typescript`, `pagefind`) — see
[Quickstart prerequisites](/get-started/quickstart.md#install) for the exact split. The
`build` script is unchanged:
`vite build && vike prerender && node scripts/gen-llms.mjs && pagefind --site dist/client`.
> **Warning:** A directory-form `file:` override of the package **falsely crashes
> `vike prerender`** with a duplicate-vike-plugin assert — the symlinked
> directory makes Vike's plugin register twice. It is an artifact of the
> override, not a bug in your migration. Run `npm pack` in the library
> and point the override at the tarball instead; that matches real npm
> resolution and prerenders cleanly. Revert the override before
> committing.
## Verification checklist
Run the same gauntlet lakeshore's migration did, and compare against
your pre-migration baseline:
1. **Full build** — `vite build && vike prerender && node
scripts/gen-llms.mjs && pagefind --site dist/client` completes
green.
2. **Prerender count parity** — the same number of HTML documents as
before (lakeshore: 101), and identical pagefind page/word counts.
For full confidence, diff the prerendered HTML against the baseline:
it should be byte-identical modulo hashed asset filenames.
3. **`check:llms`** — passes with the committed `skills//`
unchanged (pages untouched means generated surfaces untouched).
4. **`tsc --noEmit`** — clean. Deleted shell code means deleted types;
any residual import of `components/` or `lib/` surfaces here.
5. **Dev smoke** — `vite` dev server: load `/` plus one page per tab
and confirm titles, sidebar, and search all behave.
Check version-chip scope during migration: tabs inherit the global chips by default, and `TabDef.versionChips` can replace or hide them per tab. See [scoping chips per tab](/guides/site-config.md#scoping-chips-per-tab).
## Ship it
Once green, deploy as usual — Netlify needs no changes beyond the
lockfile: run `pnpm install` at the workspace root after the
dependency edits, and commit both `package.json` and `pnpm-lock.yaml`
together.
If your site predates versioned deploys (or its release scripts have
drifted), the package ships current copies at
`node_modules/@dreamlake/dockit/templates/` — see
[Releases & versioning](/guides/releases.md).
## Orient your agents
Use the shared [agent setup fragment](/guides/llms.md#orient-your-agents) after the migration. It records the page layout and regeneration checks without duplicating renderer implementation details.
---
Source: https://dockit.dreamlake.ai/guides/site-config
# Site config
A dockit site is wired by **one call** — `initDocs` — made from a
side-effect module (conventionally `site.config.ts`) that both
renderer entries import **first**, so the config lands before anything
renders, on the server and on the client. There is no nav config
anywhere: the sidebar, tabs, and search all derive from this call plus
page frontmatter.
## The full cookbook
A complete wiring example; adapt the routes and section names to your site:
```ts file="site.config.ts"
const pageMetadata = import.meta.glob('./pages/**/+Page.mdx', {
eager: true,
query: '?frontmatter', import: 'default',
})
// Pagefind indexes built HTML in production; keep full raw text in dev only.
const rawPages = import.meta.env.DEV
? import.meta.glob('./pages/**/+Page.mdx', { eager: true, query: '?raw', import: 'default' })
: undefined
initDocs({
site: {
brand: 'DreamLake',
subtitle: 'Dockit',
repoUrl: 'https://github.com/dreamlake-ai/dockit-workspace',
docsRepoUrl: 'https://github.com/dreamlake-ai/dockit-workspace',
docsBranch: 'main',
breadcrumbRoot: 'Dockit',
url: 'https://dockit.dreamlake.ai',
skill: 'dockit',
summary:
'Dockit is the DreamLake documentation shell — a Vike + React + Tailwind v4 component library and site framework with sidebar/TOC/search, MDX authoring conventions, and a versioned Netlify deploy pipeline.',
versionChips: [{ label: 'dockit', version: __DOCKIT_VERSION__,
dropdown: true, manifestUrl: '/dockit-versions.json' }],
docsPagesPath: 'docs/pages',
},
pageMetadata,
rawPages,
sectionOrder: ['Getting started', 'Build your site', 'Publishing', 'API', 'Shell', 'Content components', 'Python Autodoc'],
tabs: [
{ id: 'dockit', label: 'Dockit', numeral: 'I', landing: '/', urlPrefix: '/get-started' },
{ id: 'reference', label: 'Reference', numeral: 'II', landing: '/reference/config', urlPrefix: '/reference' },
{ id: 'python-autodoc', label: 'Python Autodoc', numeral: 'III',
landing: '/python-autodoc', urlPrefix: '/python-autodoc',
versionChips: [{ label: 'autodoc-py', version: __AUTODOC_REVISION__, prefix: '' }] },
],
})
```
The two globs matter: `pages` (module glob) feeds navigation from
frontmatter; `rawPages` (`?raw` glob) feeds the dev
[search](/guides/search.md) index and the palette's markdown preview.
`initDocs` fans out to `defineSiteConfig`, `initNavigation`,
`initSearchIndex`, and `initTabs` — all singletons mutated in place,
so components keep live references.
## Configuration reference
The [configuration reference](/reference/config.md) is the canonical field-by-field API. Start with branding (`brand`, `subtitle`, `repoUrl`), documentation ownership (`docsRepoUrl`, `docsBranch`, `docsPagesPath`), and the public `url`. An empty `repoUrl` hides the GitHub icon; an empty `breadcrumbRoot` hides the root crumb.
Set `skill`, `summary`, and `skillTriggers` when generating [AI-readable docs and skills](/guides/llms.md). The examples below cover the configuration choices that need coordination with Vite or the page layout.
## Version chips from Vite define
Chips render as `[ label | v ]`. Hardcoding the version would
drift, so this site injects it at build time from the real
`package.json`, along with the git hash:
```ts file="vite.config.ts"
const dockitPkg = JSON.parse(
readFileSync(new URL('../packages/dockit/package.json', import.meta.url), 'utf-8'),
) as { version?: string }
const DOCKIT_VERSION = dockitPkg.version ?? '0.0.0'
const GIT_HASH = (() => {
try {
return execSync('git rev-parse --short=6 HEAD', { encoding: 'utf-8' }).trim()
} catch {
return 'dev'
}
})()
export default defineConfig({
define: {
__DOCKIT_VERSION__: JSON.stringify(DOCKIT_VERSION),
__GIT_HASH__: JSON.stringify(GIT_HASH),
},
plugins: [...dockit()],
})
```
TypeScript needs to know the globals exist:
```ts file="env.d.ts"
/** Injected via Vite `define` in vite.config.ts. */
declare const __DOCKIT_VERSION__: string
declare const __GIT_HASH__: string
```
Then `site.config.ts` just references `__DOCKIT_VERSION__` and
`__GIT_HASH__` — single source of truth, no lockfile parsing. A chip
with `dropdown: true` opens a popover listing past deploys from
`/versions.json` by default. Set `manifestUrl` for an independent product
manifest; this site uses `/dockit-versions.json`. Set `prefix: ''` for
source revisions such as `main · 247f6ba`, supplied here by the build-time
`__AUTODOC_REVISION__` constant. See [Versioning](/guides/releases.md).
### Scoping chips per tab
By default the same chips show on every tab. A tab can override them
with its own `versionChips`, so a multi-surface site shows only the
relevant version on each tab:
```ts
tabs: [
// cli-only chip on the CLI tab
{ id: 'cli', label: 'CLI', numeral: 'I', landing: '/cli',
urlPrefix: '/cli', versionChips: [{ label: 'cli', version: __CLI_VERSION__ }] },
// no chip on the design tab
{ id: 'python-design', label: 'Design', numeral: 'II', landing: '/design',
urlPrefix: '/design', versionChips: [] },
// omit the field → inherits site.versionChips
{ id: 'guides', label: 'Guides', numeral: 'III', landing: '/guides',
urlPrefix: '/guides' },
],
```
Omit `versionChips` to inherit the global list, set `[]` to hide chips
on that tab, or pass an array to replace them for that tab only. See the
[Configuration reference](/reference/config.md#per-tab-version-chips).
## Tabs
Tabs group pages by URL prefix. Give each tab an `id`, visible `label` and `numeral`, a `landing` page, and a `urlPrefix` matching its routes. The [TabDef reference](/reference/config.md) lists the complete shape; the [Topbar](/reference/components/topbar.md#tabstrip) documents the rendered control.
Filtering is by **URL prefix, not frontmatter**: `/guides/theming`
belongs to the tab whose `urlPrefix` is `/guides`, full stop. The site
root `/` and any unknown prefix resolve to the first tab, so orphan
pages never leave the sidebar empty. Omit `tabs` (or pass `[]`) for a
tabless site — the strip disappears and the sidebar shows every
section.
## Section order
`sectionOrder` is the authored ordering of sidebar section groups.
Sections are minted by frontmatter (`section: Guides` just works);
any section not listed here falls to the end. Within a section, pages
sort by their frontmatter `order` — see
[Authoring pages](/guides/authoring.md).
## Skill triggers
`skillTriggers` feeds the generated agent skill's "Use when" clause.
The [LLM generator](/guides/llms.md) writes `skills//SKILL.md`
with a description an agent matches against before deciding to load
the skill — good triggers name concrete tasks, not topics:
```ts
skillTriggers: [
'building or restyling a DreamLake docs site',
'writing +Page.mdx pages with frontmatter',
'configuring initDocs, tabs, or version chips',
],
```
Keep them short, verb-first, and distinct; they are concatenated into
the skill description alongside `summary`.
---
Source: https://dockit.dreamlake.ai/guides/authoring
# Authoring pages
A page is a folder: `pages//+Page.mdx` renders at `/`
(nested folders nest the URL). Every page starts with a YAML block,
and those fields are the whole authoring contract — URL, sidebar,
search, and the LLM artifacts all derive from them. There is no nav
config to edit. The parsed shape is exported as
[`PageMeta`](/reference/config.md).
## Directory layout = URL
Every page is a `+Page.mdx` inside a folder; the folder path is the
URL:
```text
pages/
index/+Page.mdx → /
get-started/quickstart/+Page.mdx → /get-started/quickstart
api/config/+Page.mdx → /api/config
```
`index` is special — it maps to the site root `/`.
## Frontmatter fields
| Field | Type | Default | Effect |
| --- | --- | --- | --- |
| `title` | `string` | folder name | Sidebar label, ``, breadcrumbs, search result title. |
| `section` | `string` | `''` | Sidebar group. New section strings just work — order them via `sectionOrder` in [Site config](/guides/site-config.md). |
| `order` | `number` | `99` | Global sort key: sidebar position within the section AND the prev/next sequence. |
| `description` | `string` | — | ``, search result blurb, llms.txt link blurb. |
| `draft` | `boolean` | `false` | "Awaiting review" chip in the sidebar; page stays visible. |
| `hidden` | `boolean` | `false` | Out of sidebar/search/prev-next until dev mode (**Cmd+Shift+D**). Still reachable by URL. |
| `noindex` | `boolean` | `false` | Emits `noindex, nofollow` robots meta; excluded from pagefind and every [LLM surface](/guides/llms.md). |
| `dev` | `boolean` | `false` | Shorthand for `hidden: true` + `noindex: true` — an internal developer note in one flag (studio's convention). |
| `tocLevel` | `2 \| 3` | `3` | `2` limits the right rail to H2 headings. |
| `fullscreen` | `boolean` | `false` | Full-viewport page: no content column, TOC, or footer. |
A standard page:
```mdx
---
title: Installation
section: Getting started
order: 1
description: Install the package and its peers.
---
```
An internal note, invisible to readers, robots, and agents:
```mdx
---
title: Release runbook
section: Dev
order: 90
hidden: true
noindex: true
---
```
### Conventions for `order`
Leave gaps (0, 1, 2 … 10, 11 … 20, 21) so pages can slot in without
renumbering a whole section. This site numbers sections in tens.
> **Warning:** Keep values plain strings — the generator that builds the LLM
> artifacts parses frontmatter with a simple flat `key: value` reader.
> Nested YAML structures will not survive the trip.
## Sidebar auto-discovery
The rules, in full:
1. Pages group by their `section` string. Sections render in the
`sectionOrder` you pass to `initDocs`; sections not in that list
fall to the end, alphabetically — a new section shows up without
any config change.
2. Within a section, pages sort by `order` (missing `order` = 99).
Leave gaps between sections' order ranges (this site uses 0–4,
10–13, 20–23, …) so inserting a page never renumbers its neighbors.
3. If the site declares [tabs](/reference/components/topbar.md), the sidebar shows
only pages whose URL falls under the active tab's `urlPrefix`.
4. `hidden: true` pages stay out of the sidebar (and prev/next) until
the reader toggles dev mode with **Cmd+Shift+D**.
> **Note:** Adding a page is: create the folder, write frontmatter, done. Moving a
> page is: move the folder. Renaming a section is: change the string in
> the pages that use it (and `sectionOrder` if you pinned it).
## Naming conventions
- Folder names are kebab-case; they become URL segments.
- Keep `section` strings short — they render as uppercase mono labels.
- One H1 per page, matching (or elaborating) the frontmatter title.
The H1 drives the topbar's brand-to-breadcrumb crossfade.
- `##` headings feed the right-rail TOC; keep them scannable and
front-loaded (they are also the anchors search results deep-link to
— see the [search guide](/guides/search.md)).
## Markdown & MDX
Pages are MDX: GitHub-flavored markdown, plus imports and JSX where
prose is not enough. The MDX component map restyles every primitive
(headings, links, tables, code) to the shell's design — write plain
markdown and it comes out right.
### Headings and links
- Headings get stable slug ids (rehype-slug); hover a heading to grab
its anchor. H2/H3 feed the [TOC](/reference/components/shell.md#table-of-contents) in the right rail
(`tocLevel: 2` drops the H3s).
- Internal links are root-relative (`/guides/search`) — the client
router intercepts them; the LLM generator rewrites them to `.md`
twins in the exported artifacts.
### Code fences
Fences are highlighted by shiki with dual light/dark themes. The meta
string takes a `file="…"` chip:
````mdx
```bash file="terminal"
pnpm add @dreamlake/dockit
```
````
```bash file="terminal"
pnpm add @dreamlake/dockit
```
- The language chip comes from the fence language.
- The `:set nu` button toggles line numbers **site-wide** — flip it on
one block and every block follows.
- Copy grabs the raw text.
### Callouts
`> **Note:** ` is in scope without an import (as are ``,
> ``, and ``):
>
> ```mdx
>
> Markdown works inside callouts.
```
See the [Callout page](/reference/components/callout.md) for variants.
### Tables
GFM tables render with the template's hairline borders:
```mdx
| Flag | Effect |
| --- | --- |
| `hidden` | Hidden until Cmd+Shift+D |
```
### Live examples
For component demos, follow the [Preview](/reference/components/preview.md)
convention: a real component in `examples/`, imported twice — once as
a module to render, once with `?raw` to show its own source:
```mdx
```
### Images and assets
Files in `public/` serve from the site root (`/diagram.png`). Prefer
SVG; both themes should read well — test with the theme toggle (see
[Theming & CSS](/guides/theming.md)).
---
Source: https://dockit.dreamlake.ai/guides/theming
# Theming & CSS
Every color, radius, and font in the shell resolves through prefixed
CSS custom properties declared in `@dreamlake/dockit/styles.css`. The
`--doc-template-` prefix isolates the shell from the consuming app's
own tokens; restyling the shell is overriding variables — no component
edits.
## The consumer stylesheet
A dockit site owns exactly one CSS file. This site's is the whole
recipe:
```css file="styles/app.css"
@import "tailwindcss";
@import "@dreamlake/dockit/styles.css";
/* Tell Tailwind where this site's own utility-class usage lives (the
library's dist is covered by the @source inside its styles.css). */
@source "../pages";
@source "../examples";
@source "../renderer";
```
Line by line:
- `@import "tailwindcss"` boots Tailwind v4 — no `tailwind.config.js`,
everything is CSS-first.
- `@import "@dreamlake/dockit/styles.css"` pulls in the shell's
`@theme` token block, dark-mode overrides, and component styles.
Order matters: the library must come **after** tailwindcss and
**before** your own overrides.
- Your `@source` lines point Tailwind at the directories where *your*
markup uses utility classes, so those utilities get generated.
- The library's stylesheet carries its own `@source "./"` at the top.
Because `@source` resolves relative to the file it appears in, and
the file ships as `dist/styles.css`, that line makes Tailwind scan
the package's compiled JS in `dist/` — classes used only inside
dockit components are always emitted, without you listing the
package yourself.
## Color tokens
Declared in an `@theme` block, so each also mints Tailwind utilities
(`bg-doc-template-bg`, `text-doc-template-ink`, …):
| Token | Light | Role |
| --- | --- | --- |
| `--color-doc-template-bg` | `#fffefa` | Page background |
| `--color-doc-template-panel` | `#fcfbf7` | Cards, footer panels |
| `--color-doc-template-rail` | `#fcfbf7` | Sidebar / rail background |
| `--color-doc-template-code` | `#faf8f1` | Code block surface |
| `--color-doc-template-ink` | `#1a1a1a` | Primary text |
| `--color-doc-template-muted` | `#6b6b6b` | Secondary text |
| `--color-doc-template-faint` | `rgb(0 0 0 / 0.08)` | Hairline borders |
| `--color-doc-template-faint-strong` | `rgb(0 0 0 / 0.16)` | Stronger borders |
| `--color-doc-template-chip` | `rgb(0 0 0 / 0.04)` | Chip fills |
| `--color-doc-template-search` | `#f5f4f0` | Search field fill |
| `--color-doc-template-selected` | `#d9e6f7` | Active sidebar link |
| `--color-doc-template-accent` | `#23aaff` | Links, active TOC, highlights |
| `--color-doc-template-accent-soft` | `rgb(35 170 255 / 0.09)` | Accent washes |
| `--color-doc-template-warn` | `#d68b3a` | Warnings, dev-mode dot |
| `--color-doc-template-warn-soft` | `rgb(214 139 58 / 0.10)` | Warning washes |
| `--color-doc-template-rail-stroke` | `#d8d4c8` | TOC rail stroke |
Radii: `--radius-doc-template` (10px) and `--radius-doc-template-sm`
(6px).
## Dark mode
A `[data-theme='dark']` block re-declares the same custom properties —
every utility and inline style swaps instantly, with zero re-render.
The attribute is stamped on `` by:
1. the FOUC-safe inline script in the server-rendered head (first
paint), and
2. `ThemeProvider` afterwards (user choice, `system` tracking,
cross-tab sync) — see [ThemeToggle](#themetoggle) below.
A `dark:` Tailwind variant is wired to the same attribute for your own
pages. Shiki code colors are dual-theme (`github-light` /
`github-dark`) via CSS variables, so code follows along.
## Fonts
| Token | Stack | Used for |
| --- | --- | --- |
| `--font-doc-template-ui` | Inter Tight, ui-sans-serif, … | Body, headings, links |
| `--font-doc-template-mono` | Fira Code, ui-monospace, … | Code, chips, section labels, breadcrumbs |
The server renderer emits a single Google Fonts `` loading Inter
Tight + **Fira Code** (the org-wide mono font).
## Re-branding walkthrough
Restyling the shell is a stanza in your `app.css`, **after** the
library import. Override the light values on `:root` and the dark
values on `[data-theme='dark']`:
```css file="styles/app.css"
@import "tailwindcss";
@import "@dreamlake/dockit/styles.css";
@source "../pages";
@source "../renderer";
/* Brand: violet accent, tighter radii, your own type. */
:root {
--color-doc-template-accent: #7c5cff;
--color-doc-template-accent-soft: rgb(124 92 255 / 0.09);
--color-doc-template-selected: #e6dffb;
--radius-doc-template: 6px;
--font-doc-template-ui: "Instrument Sans", ui-sans-serif, sans-serif;
}
[data-theme='dark'] {
--color-doc-template-accent: #a78bff;
--color-doc-template-selected: #423a5c;
}
```
Every component — sidebar selection, TOC highlight, links,
[chips](/reference/components/chip.md) — re-resolves through the variables; there
is nothing else to touch. If
you swap a font stack, remember to also load the webfont (the
renderer's default `` only fetches Inter Tight and Fira Code).
## ThemeToggle
The theme control comes in two variants, chosen by the `themeToggle`
field in [Site config](/guides/site-config.md):
- **`'cycle'`** (default) — a single button that steps
**light → system → dark**, with a small spring animation on the
icon swap.
- **`'segmented'`** — the three-button slider from the uikit/dreamlake
docs: every theme visible at once, a pill indicator sliding under
the active one, inactive icons leaning ±18°.
```ts file="site.config.ts"
initDocs({
site: { themeToggle: 'segmented' /* or 'cycle' */ },
// …
})
```
This site is configured with `'segmented'`, so that is what the topbar
shows. Here is another toggle, live — both stay in sync because they
share the same `ThemeProvider` state:
`` takes no props — the variant is site-level config,
not a per-instance choice. It must render inside the shell (or any
`ThemeProvider`) — on its own it falls back to inert context defaults.
### How theme state flows
1. `ThemeProvider` (mounted by the [Layout](/reference/components/shell.md)) keeps
the choice in localStorage under `doc:theme`, synced across tabs
and across every consumer of the hook.
2. The provider stamps `data-theme="light" | "dark"` on ``;
every color token above re-resolves instantly.
3. On first paint, a tiny inline script in the server-rendered
`` reads the same key **before** hydration, so a dark-mode
reader never sees a light flash (FOUC-safe).
### Reading the theme yourself
```tsx
function MyWidget() {
const { theme, setTheme } = useTheme() // 'light' | 'dark' | 'system'
return
}
```
---
Source: https://dockit.dreamlake.ai/guides/search
# Search
Dockit search has two engines behind one UI, `SearchPalette`. Press **⌘K** or **/**, or click the topbar search field. Results update as you type; **↑↓** selects a result, **Enter** opens it, and **Esc** closes the overlay. The right pane previews the selected page as rendered Markdown.
This page explains what gets indexed when, how the shell scopes the
index, and how authoring choices affect findability.
## Production: pagefind
The build's final step indexes the prerendered HTML:
```bash
pagefind --site dist/client
```
Pagefind ships a WASM index the browser loads on demand — sub-word
matching, excerpts with `` highlights, and it scales with page
count.
The shell emits the scoping markers itself; there is nothing to add to
your pages:
| Marker | Where the shell puts it | Effect |
| --- | --- | --- |
| `data-pagefind-body` | `main.doc-content` — except on `noindex` pages | Only page content is indexed, never chrome (sidebar, topbar, rails). |
| `data-pagefind-ignore` | Breadcrumbs, prev/next footer | Excluded even inside the body. |
| `data-pagefind-meta="hidden:true"` | Pages with `hidden: true` | Indexed but filtered from results unless dev mode (**Cmd+Shift+D**) is on. |
Pages with `noindex: true` are skipped entirely — the shell omits
`data-pagefind-body` on them, and pagefind indexes nothing on a page
without that marker, so they never enter the pagefind index.
## Dev: the fallback index
`vite dev` has no prerendered HTML, so `initSearchIndex` builds an
in-memory index from the raw MDX you pass to `initDocs` (the `?raw`
glob — see [Site config](/guides/site-config.md)) — frontmatter stripped,
code fences dropped, headings captured for higher-weight ranking. Rank
order: title match → heading match → description → section → body
occurrences → fuzzy title subsequence.
The engine switch is automatic — `searchPages()` tries pagefind and
falls back. The palette also uses the raw markdown for its preview
pane in both modes.
## Writing searchable pages
- **Titles carry the most weight** — name pages what readers will
type.
- **`description` doubles as the result blurb**; a missing one falls
back to body context around the match.
- **Headings are the second-strongest signal** — real H2/H3 structure
beats bold paragraphs.
- Code fences are excluded from the dev index — put key terms in prose
too, not only in code.
> **Note:** If a result surprises you in dev but not production (or vice versa),
> remember the engines differ: pagefind matches sub-words against
> rendered HTML; the fallback matches whole substrings against stripped
> markdown.
## Wiring
The [Layout](/reference/components/shell.md) owns the open state and query, renders
the [Topbar](/reference/components/topbar.md) search field, and mounts the palette:
```tsx
setSearchOpen(false)} query={query} />
```
## Props
| Prop | Type | Description |
| --- | --- | --- |
| `open` | `boolean` | Whether the palette is showing. |
| `onClose` | `() => void` | Called on Esc / backdrop click. |
| `query` | `string` | The live query (the input lives in the Topbar, not the palette). |
## Behavior notes
- `hidden: true` pages are excluded from results unless dev mode
(**Cmd+Shift+D**) is on; `noindex` pages never enter the pagefind
index at all.
- The panel is resizable (drag the bottom edge); split position and
height persist in localStorage.
- Below 640px the palette collapses to a single column and drops the
preview pane.
---
Source: https://dockit.dreamlake.ai/guides/llms
# AI-readable docs and skills
One generator, `scripts/gen-llms.mjs`, reads `pages/**/+Page.mdx` —
the same single source of truth the site renders — and derives every
LLM consumption surface. Run it after documentation changes and check the committed output in CI to keep the site and artifacts in sync.
## The surfaces
| Surface | Output | Purpose |
| --- | --- | --- |
| Per-page markdown | `/.md` (this page: `/guides/llms.md`) | Agents fetch exactly one page as clean markdown. |
| Index | [`/llms.txt`](/llms.txt) | The [llmstxt.org](https://llmstxt.org) map: brand, summary, every page with a blurb. |
| Full corpus | [`/llms-full.txt`](/llms-full.txt) | Whole docs in one file for context stuffing. |
| Importable skill | `skills//{SKILL.md,reference/*.md}` at the repo root (committed) | Drop into a Claude skills directory. |
| Skill download | `/skills/.zip` | Same skill, fetchable from the site. |
The shell links the surfaces automatically: each page's `` gets
`` and the TOC rail gets a
"View as Markdown" link.
## What the generator does
- Strips frontmatter and imports; degrades MDX components to plain
markdown (`> **Note:** ` → blockquote, `` → its inner code).
> - Rewrites internal links per surface — to `.md` twins on the web, to
> `reference/*.md` inside the skill.
> - Excludes `noindex` pages from every artifact.
> - Reads `brand`, `url`, `summary`, `skill`, and
> [`skillTriggers`](/reference/config.md) (the curated "Use when" phrases in the
> skill's trigger list) from `site.config.ts`; on Netlify the deploy's
> `URL` env var overrides the origin, so previews generate
> self-consistent absolute links.
>
> ## Wiring
>
> The generator runs between prerender and pagefind (see the build
> steps in the [Quickstart](/get-started/quickstart.md)), plus two
> scripts:
>
> ```bash
> pnpm gen:llms # regenerate everything
> pnpm check:llms # exit 1 if the committed skill drifted from pages/
> ```
>
> The committed `skills//` directory is generated output — run
> `pnpm gen:llms` after editing pages, and let `check:llms` guard the
> repo in CI.
>
>
> `public/_headers` sets `text/markdown` on the twins and `text/plain`
> on the indexes; `public/_redirects` exact-matches them ahead of the
> SPA fallback so `curl https://…/guides/llms.md` returns markdown, not
> the app shell.
## Install the Dockit skill
The generated skill supplies a `SKILL.md` entry point and a `reference/*.md` file for each public page. Install it to let an agent consult Dockit setup, authoring, theming, and API guidance locally.
**Direct download** — grab [`/skills/dockit.zip`](/skills/dockit.zip)
and unzip it into your Claude Code skills directory:
```bash
curl -LO https://dockit.dreamlake.ai/skills/dockit.zip
unzip dockit.zip -d .claude/skills/dockit/
```
**Pebble marketplace** — DreamLake distributes its skills org-wide
through [dreamlake-ai/pebble](https://github.com/dreamlake-ai/pebble),
the canonical Claude Code skills marketplace for the org. If you are
inside DreamLake, install from pebble to pick up updates alongside
every other org skill.
## Orient your agents
Paste this fragment into your repo's `CLAUDE.md` so coding agents know
how the docs work without rediscovering it every session:
```markdown
## Docs (dockit)
- Doc pages live at `docs/pages//+Page.mdx` (Vike file routing —
nested folders nest URLs).
- Frontmatter: `{ title, section, order, description, draft?, hidden?,
noindex?, tocLevel?, fullscreen? }`.
- The sidebar auto-derives from frontmatter. Never edit a nav config —
there isn't one.
- MDX extras: ``, ``,
and code fences with `file="…"` for a filename chip.
- Site config (brand, tabs, section order) is the `initDocs(...)` call
in `docs/site.config.ts`.
- The docs build generates agent surfaces: `/llms.txt`, a `.md` twin
per page, and a skill at `skills//` in the repo root — import
that skill for deep dockit reference. Browsable at
https://dockit.dreamlake.ai/guides/llms.
- Run `check:llms` before committing page changes, and commit the
regenerated `skills//` with them.
```
## What's inside — SKILL.md
The committed entry point, verbatim:
{skillMd}
---
Source: https://dockit.dreamlake.ai/guides/releases
# Releases & versioning
A dockit site can keep every released version of its docs online, each
at its own URL, with an in-site switcher in the topbar. This guide is
the consumer-facing playbook: the pieces you need, the scripts that
drive them, and the deploy mechanics — using this workspace as the
worked example throughout.
The library ships a copy-in release kit with all of the pieces below —
see [Ship it with your own site](#ship-it-with-your-own-site).
## Two independent version axes
Do not conflate these; they move on their own schedules:
1. **Your product/library semver** — the thing the docs document
(here: `@dreamlake/dockit`, published to npm). Its version lives in
the package's own `package.json` and shows in the topbar's
[version chips](/reference/components/topbar.md). A product can have
its own dropdown and manifest.
2. **The docs-deploy version** — a version stamp for the docs *site*
itself, so readers can pin "the docs as of 0.2.0". It lives in two
files: the workspace root `package.json` and the manifest at
`docs/public/versions.json`.
A docs release can ship without a library release (a big guide lands)
and vice versa (a patch release with no doc changes worth freezing).
On this site, the **Dockit `v0.2.15`** badge selects
`/dockit-versions.json`. That product manifest currently contains only
`0.2.15`, linked to the current site. `/versions.json` preserves the
separate historical docs-build sequence; it must not relabel the Dockit
package badge. The **Python Autodoc** tab displays `main` plus the source
revision with `prefix: ''` and no dropdown, because no package release
is implied by this documentation integration.
```ts
versionChips: [{
label: 'dockit', version: __DOCKIT_VERSION__, dropdown: true,
manifestUrl: '/dockit-versions.json',
}]
// Python Autodoc tab override
versionChips: [{ label: 'autodoc-py', version: __AUTODOC_REVISION__, prefix: '' }]
```
`prefix` changes the displayed prefix (default `v`). `manifestUrl`
selects a path or an absolute manifest URL; it defaults to `/versions.json`.
These settings are documented in the [VersionChip reference](/reference/config.md#versionchip).
## versions.json — the manifest
The default docs-build manifest is served at `/versions.json`. A chip
with `dropdown: true` consumes this file unless `manifestUrl` selects
a product-specific manifest. Both manifests use the same schema:
```json file="docs/public/versions.json"
{
"current": "0.2.1",
"stable": "0.1.0",
"aliases": {
"latest": "https://dockit.dreamlake.ai",
"stable": "https://stable.dockit.dreamlake.ai"
},
"versions": [
{ "version": "0.2.1", "url": "https://v0-2-1--dockit-docs.netlify.app", "date": "2026-07-20" },
{ "version": "0.2.0", "url": "https://v0-2-0--dockit-docs.netlify.app", "date": "2026-07-20" },
{ "version": "0.1.0", "url": "https://v0-1-0--dockit-docs.netlify.app" }
]
}
```
- **`current`** — the newest release; what the topbar chip labels
itself when the hostname gives no better answer.
- **`stable`** — the version the `stable` alias points at (may trail
`current`).
- **`aliases`** — stable URLs that always point somewhere sensible;
`latest` is your production domain.
- **`versions[]`** — newest first; each entry's `url` is the documentation
destination for that version. Only describe it as frozen when its
deployment is actually retained unchanged. `date` is optional but useful in the
popover.
The switcher fetches this manifest at runtime, so a reader on an *old*
frozen deploy still sees the full, current version list — the manifest
on your production domain is the source of truth. That fetch is
cross-origin from a frozen `v/*` deploy, so production must serve
the selected manifest with a CORS header (`/versions.json` is already in the
`netlify.example.toml` template):
```toml file="netlify.toml"
[[headers]]
for = "/versions.json"
[headers.values]
Access-Control-Allow-Origin = "*"
```
Use the same header for `/dockit-versions.json` when a product chip
selects that path. Changing one manifest does not change the other.
## set-version.mjs — the bump
One script updates both files atomically. This is the actual script
this workspace runs (embedded from `scripts/set-version.mjs`, not a
copy):
{setVersionSrc}
```bash
pnpm set-version 0.2.1
```
Idempotent — re-running refreshes the existing entry's url/date
instead of duplicating it. Note the URL it writes: the Netlify
branch-deploy address, not a pretty subdomain — see
[the URL scheme](#netlify-branch-deploys--the-url-scheme) below for
why.
## version-branch.sh — the frozen deploy
Each release is frozen by pushing HEAD to a `v` branch. Again
the actual script, embedded from `scripts/version-branch.sh`:
{versionBranchSrc}
With branch deploys enabled, Netlify builds that branch at its version URL. Keep the branch and deployed artifact unchanged to preserve that release snapshot.
## Netlify branch deploys — the URL scheme
Enable branch deploys on your Netlify site (Site settings → Build &
deploy → Branches and deploy contexts → "Deploy all branches", plus
empty `[context.branch-deploy]` / `[context.deploy-preview]` blocks in
`netlify.toml`). Then every pushed branch serves at:
```text
https://--.netlify.app
```
with non-alphanumeric characters in the branch name dashed — so branch
`v0.2.1` on site `dockit-docs` serves at
`v0-2-1--dockit-docs.netlify.app`. **These URLs use Netlify's branch-deploy domain** and need no custom DNS once the corresponding deployment exists. They are what
`set-version.mjs` writes into the manifest.
A CLI `netlify deploy --alias` creates a named **draft deploy**, not a
branch deploy. Netlify advises against reusing a deployed branch name
as an alias. The existing `prod` script still includes that legacy
alias step; its predictable URL is not evidence of branch-deploy
retention. Create real branch deploys through a connected repository
with branch deployment enabled. See the
[Netlify CLI reference](https://cli.netlify.com/commands/deploy/).
Netlify exempts the latest successful deploy of each branch from
automatic deploy deletion. Older deploys and draft aliases can be
removed under the site's retention policy. Keep each release branch
unchanged, verify its successful branch deploy, and retain a separate
build archive with its source revision and checksum. A Git branch alone
does not save the rendered output. See
[Netlify deploy retention](https://docs.netlify.com/deploy/manage-deploys/manage-deploys-overview/#automatic-deploy-deletion).
> **Note:** You *can* have `v0-2-1.your-domain.com` instead, but only if your DNS
> is on Netlify and you **manually add each branch subdomain** in the
> Netlify domain-management UI, once per release — the special
> `NETLIFY`-type DNS records this creates cannot be set up via the API,
> so it cannot be scripted. Unless you have a strong cosmetic reason,
> skip this: the `v--.netlify.app` form avoids that per-version DNS setup.
## The promotion flow — prod and staging
Merging to `main` does not change production here. Production and
staging are **promoted from the CLI**, each ending in a force-push to
a record branch so the Netlify dashboard reflects what is actually
live:
```bash
pnpm prod # version-branch → build → netlify deploy --prod → force-push netlify-production
pnpm staging # build → netlify deploy --prod (staging site) → force-push netlify-staging
```
Both deploy the prebuilt `docs/dist/client` with `--no-build` to a
pinned `--site` id. The typical release, end to end:
```bash
pnpm set-version 0.2.1
git commit -am "release: docs 0.2.1"
pnpm prod
```
`pnpm staging` is the same promotion aimed at a second Netlify site,
with no version bookkeeping — use it to preview a release first.
> **Warning:** ">
> In a pnpm workspace, a bare `netlify deploy` cannot tell which project
> it belongs to and hangs on an interactive project picker. Pin it with
> `--filter ` (this workspace passes `--filter docs`)
> — keep the flag if you invoke the CLI by hand.
## The other axis: releasing the library itself
Publishing the documented package to npm is deliberately separate from
all of the above. This workspace wires it as the `release` pane in
`mprocs.yaml`: build the library, then `pnpm publish` with a fresh
OTP fetched at publish time. Docs releases never publish npm packages,
and npm releases never touch `versions.json`.
## Ship it with your own site
`@dreamlake/dockit` ships all four pieces as templates:
```bash
ls node_modules/@dreamlake/dockit/templates/
# set-version.mjs version-branch.sh versions.example.json netlify.example.toml
```
Copy them in, then edit the marked `EDIT ME` block (your Netlify site
name) at the top of each script:
```bash
cp node_modules/@dreamlake/dockit/templates/set-version.mjs scripts/
cp node_modules/@dreamlake/dockit/templates/version-branch.sh scripts/
cp node_modules/@dreamlake/dockit/templates/versions.example.json docs/public/versions.json
cp node_modules/@dreamlake/dockit/templates/netlify.example.toml netlify.toml
```
Wire the scripts into your root `package.json`:
```json
"scripts": {
"set-version": "node scripts/set-version.mjs",
"version-branch": "bash scripts/version-branch.sh"
}
```
The templates assume the same layout as this workspace — root
`package.json` holds the docs-deploy version, the manifest lives at
`docs/public/versions.json` — and resolve paths from the directory you
invoke them in.
---
Source: https://dockit.dreamlake.ai/get-started/release-notes
# Release notes
## 0.2.15 — 2026-09-08 (library)
- Fix early client navigation by allowing React hydration to be superseded and avoiding hydration of stale server markup.
- Add metadata-only MDX imports for navigation and avoid loading raw page bodies for production search.
- Fetch search previews only while the palette is open, and cancel stale requests.
- Make both navigation rails configurable with wider 280px defaults, and stabilize sidebar labels while scrolling.
- Support independent product version manifests.
## 0.2.7 — 2026-08-02 (library)
- **Per-tab version chips**: new [`TabDef.versionChips`](/reference/config.md)
field scopes the topbar version chips to a top-level tab. A tab omitting
the field inherits the global [`versionChips`](/reference/config.md); `[]`
shows none on that tab; a non-empty array replaces them for that tab only.
Lets a site show cli-only chips on the CLI tab, py-only on the Python
tab, and none on design/other tabs.
## 0.2.6 — 2026-07-20 (library)
- **Dependency layout**: `react`/`react-dom` peers widened to `>=19`
(org convention: sites track `react@latest`); `tailwindcss` moved
from a dependency to a `^4` peer so it resolves at the consuming
site's root under strict CI installs.
## 0.2.5 — 2026-07-20 (library)
- **Chip component**: the canonical badge idiom is now a first-class
export — [``](/reference/components/chip.md) with `muted` / `accent` /
`warn` variants, clickable (`onClick` renders a real button), and
`className`/`style` passthrough for one-off colors. Registered in
the MDX component map, so `` works in any page without an
import.
- The topbar **DEV badge**, the gallery status chips, and the
`TestStatus` badge now render through `` — no visual change,
the idiom is just defined once.
## 0.2.4 — 2026-07-20 (library)
- **Search-engine opt-in**: new [`indexable`](/reference/config.md) field —
sites are `noindex, nofollow` by default per org policy; set
`indexable: true` on the sites meant to be publicly discoverable.
In-site search and the llms/skill surfaces are unaffected.
## 0.2.3 — 2026-07-20 (library)
- **DEV badge**: the dev-mode indicator in the topbar is now a labeled
warn-colored `DEV` chip (was a small orange dot); clicking it still
turns the hidden-pages toggle off.
- **`headScripts`** `SiteConfig` field: external script URLs injected
into every page head at SSR time — restores integrations like the
Studio design-picker bridge for migrating sites.
## 0.2.2 — 2026-07-20 (library)
- **All-hidden tabs hide**: a tab whose pages are all `hidden` (e.g. an
internal `/dev` tab) no longer renders in the topbar unless the
hidden-pages toggle is on or you are already inside it.
## 0.2.0 — 2026-07-20 (library)
Fleet features upstreamed from the newest DreamLake docs sites, ahead
of the org-wide migration onto dockit:
- **Segmented ThemeToggle** (from uikit/dreamlake): new
[`themeToggle`](/reference/config.md) `SiteConfig` field — `'cycle'` (default,
the existing single cycling button) or `'segmented'` (the
three-button slider with a sliding indicator). See
[Theming](/guides/theming.md#themetoggle). This site runs `'segmented'`.
- **Preview fullscreen** (from uikit): an expand button in the
[Preview](/reference/components/preview.md) header grows the frame to a
full-viewport overlay for wide demos; Esc exits. Icons are inlined
SVGs — no new dependency.
- **Trailing-slash-tolerant path matching** (from studio): new
`normalizePath` / `findPage` exports, used everywhere active-page
matching happens (sidebar `aria-current`, breadcrumbs, ``
sync, prev/next, TOC md/edit links) so prerender and client routing
agree. See [Sidebar](/reference/components/shell.md#sidebar).
- **`dev:` frontmatter alias** (from studio): `dev: true` now implies
`hidden: true` + `noindex: true`, so studio content migrates
unchanged. See [Authoring](/guides/authoring.md).
- **`VersionBadge` exported** standalone (donor: uikit), with the
version-switcher manifest now fetched production-origin-first so
frozen deploys list current releases (needs the `/versions.json`
CORS header — in `netlify.example.toml` and
[Releases & versioning](/guides/releases.md)).
- CodeBlock header controls (language / `:set nu` / copy) are now
hover-gated, keeping prose-adjacent code blocks quiet (#8).
## 0.2.1 — 2026-07-20 (docs)
- New [Releases & versioning](/guides/releases.md) guide — the versioned
docs-deploy flow as consumer-facing docs: the two version axes, the
`versions.json` manifest, the actual `set-version.mjs` /
`version-branch.sh` scripts embedded from source, Netlify
branch-deploy URLs, and the prod/staging promotion flow. The hidden
[Versioning](/guides/releases.md) dev page slims down to
workspace-internal details.
- The library now ships a copy-in release kit at
`templates/` — `set-version.mjs`, `version-branch.sh`,
`versions.example.json`, `netlify.example.toml` — referenced from
the [Quickstart](/get-started/quickstart.md) and
[migration guide](/get-started/migration.md).
- `versions.json` URL-scheme fix: per-version entries now point at the
canonical Netlify branch-deploy addresses
(`v--dockit-docs.netlify.app`), which resolve without any
DNS setup, instead of pretty subdomains that required a manual
Netlify domain-management step per release.
## 0.2.0 — 2026-07-20 (docs)
- Docs reorganized into the five-tab tree — Get Started, Guides,
Components, Skills, Reference — with 301 redirects covering the old
URLs (see [Netlify](/guides/releases.md)). Deploy internals (Netlify,
versioning) moved into the hidden Dev cluster; the
[dockit skill](/guides/llms.md) got its own page.
- New [migration guide](/get-started/migration.md) for moving an existing
docs site onto dockit.
- Component gallery added under the hidden Dev section.
- Skill-generation upgrades in `gen-llms.mjs`: curated "Use when"
triggers via the [`skillTriggers`](/reference/config.md) config field (ships
in library 0.1.1 below), quickstart + routing guidance in the
generated `SKILL.md`, and a bundled `api-types.md` type reference.
- "Orient your agents" CLAUDE.md fragment for consuming repos, in the
[Quickstart](/get-started/quickstart.md) and
[migration guide](/get-started/migration.md).
## 0.1.1 — 2026-07-20 (library)
- `noindex: true` pages are now excluded from the pagefind index: the
Layout omits `data-pagefind-body` on them, matching what the docs
always said (see [Search](/guides/search.md)). Previously the marker
was stamped on every page, so noindex pages still got indexed.
- The [`skillTriggers`](/reference/config.md) `SiteConfig` field ships — the
curated "Use when" phrases consumed by skill generation.
- The package ships the `templates/` release kit — `set-version.mjs`,
`version-branch.sh`, `versions.example.json`, and
`netlify.example.toml`, ready to copy from
`node_modules/@dreamlake/dockit/templates/` (see
[Releases & versioning](/guides/releases.md)).
## 0.1.0 — 2026-07-19
- Initial release. The docs shell extracted from `lakeshore-workspace`
into the `@dreamlake/dockit` package: components, the
navigation/search/tabs singletons plus `initDocs`, the Vike renderer
entries, the `dockit()` Vite plugin factory, and `styles.css` with
its `@source` directive.
- Published as pure ESM, without sourcemaps — see
[Package exports](/reference/exports.md).
- dockit.dreamlake.ai live, built with the library itself.
---
Source: https://dockit.dreamlake.ai/reference/config
# Configuration
Everything configurable in dockit flows through one call — `initDocs`
— made from your `site.config.ts` before the shell renders.
## initDocs(options)
```ts
initDocs({
site: { /* Partial */ },
pageMetadata: import.meta.glob('./pages/**/+Page.mdx', { eager: true, query: '?frontmatter', import: 'default' }),
rawPages: import.meta.env.DEV ? import.meta.glob('./pages/**/+Page.mdx', {
eager: true, query: '?raw', import: 'default',
}) : undefined,
sectionOrder: ['Getting started', 'Reference'],
tabs: [],
})
```
| Option | Type | Required | Purpose |
| --- | --- | --- | --- |
| `site` | `Partial` | yes | Branding, URLs, chips — merged over neutral defaults. |
| `pageMetadata` | eager `?frontmatter` glob | one of these | Metadata-only loader keeps page bodies out of startup JavaScript. |
| `pages` | eager glob of `+Page.mdx` | one of these | Legacy module map; use either `pages` or `pageMetadata`. |
| `rawPages` | eager `?raw` glob | no | Feeds fallback full-text search. Prefer dev-only; production Pagefind searches built HTML. |
| `sectionOrder` | `string[]` | no | Sidebar section order; unknown sections fall to the end. |
| `tabs` | `TabEntry[]` | no | Topbar tab lenses and external links; omit for a tabless site. |
| `search` | `SearchConfig` | no | Runtime search options; overrides `site.search` when both are provided. |
## SiteConfig
| Field | Type | Effect |
| --- | --- | --- |
| `brand` | `string` | Top-left brand; llms.txt heading. |
| `subtitle` | `string` | Muted label after the brand. |
| `repoUrl` | `string` | Topbar GitHub icon (empty hides it). |
| `docsRepoUrl` | `string` | Base for Edit/issue links in the TOC rail. |
| `docsBranch` | `string` | Branch in the edit link (default `main`). |
| `breadcrumbRoot` | `string` | Leftmost crumb (empty omits it). |
| `url` | `string` | Public origin — absolute URLs in LLM artifacts. |
| `skill` | `string` | Agent-skill name (`skills//`, `.zip`). |
| `summary` | `string` | One-liner: llms.txt blockquote + skill description. |
| `skillTriggers` | `string[]?` | Curated task phrases for the generated skill's "Use when:" trigger list; unset falls back to the site's section names. |
| `versionChips` | `VersionChip[]?` | Topbar chips (see below). Individual tabs can override this via [`TabDef.versionChips`](#tabdef). |
| `gitHash` | `string?` | Git-hash chip (empty hides it). |
| `docsPagesPath` | `string?` | Repo-relative pages dir for edit links (default `docs/pages`). |
| `themeToggle` | `'cycle' \| 'segmented'?` | Topbar theme control: single cycling button (default) or the three-button slider — see [Theming](/guides/theming.md#themetoggle). |
| `mdxComponents` | `Record?` | Site-specific MDX tags merged over the library's provider map — pages use them without per-page imports. |
| `headScripts` | `string[]?` | External script URLs injected as `