create-zudo-doc CLI
Complete CLI reference for the create-zudo-doc project scaffolder.
Usage
create-zudo-doc [destination] [options]When run without flags, the CLI launches an interactive wizard. All options can be specified via flags for non-interactive (CI/agent) usage.
You can also use the Setup Preset Generator to interactively build a configuration and copy it as a JSON preset or CLI command.
Destination and project name
The first positional argument is the destination — the directory to scaffold into. It may be a path, and its last segment becomes the project name written to the generated package.json:
# Creates ./sub/ref-doc, package name "ref-doc"
pnpm create zudo-doc sub/ref-doc --yesOnly that last segment goes through the project-name grammar (starts with a lowercase letter or digit; lowercase letters, digits, dots, underscores, and hyphens only; 214 characters max). The directories leading up to it are just a path, so Scratch-Dir/ref-doc is accepted.
| Destination | Directory created | Project name |
|---|---|---|
my-docs | . | my-docs |
sub/ref-doc | . | ref-doc |
. | . | ref-doc |
. | . | ref-doc |
/ | / | ref-doc |
Upward traversal (.) and absolute destinations are both accepted. What is rejected is ., .., and a filesystem root (/) — they name no last segment to derive the project name from:
Destination "." has no final path segment to name the project. Pass a destination whose last segment names the project, e.g. "sub/my-docs"When the last segment is a legal directory name but not a legal package name, the error points at that segment:
Invalid project name "My-Docs" — the last segment of destination "sub/My-Docs" is used as the package name. Project name must start with a lowercase letter or digit and contain only lowercase letters, digits, dots, underscores, and hyphens--name overrides the derived name while the positional argument still supplies the directory — that is how you scaffold into a directory whose name is not a valid package name:
# Creates ./sub/My-Docs, package name "ref-doc"
pnpm create zudo-doc sub/My-Docs --name ref-doc --yes--name itself remains a bare package name: a path passed to it is still rejected. And a destination with no last segment stays rejected even when --name is present.
What the CLI generates
The scaffold is minimal — roughly a dozen files (see Project Structure). The layout, chrome, and schema all ship from @takazudo/zudo-doc and are consumed from node_modules, so the generated project holds only what is genuinely its own.
Your feature choices are written into a single zfb.config.ts as a zudoDoc({ … }) call containing only the fields that differ from the defaults (siteName is always emitted). There is no separate src/ — the one config file is the whole configuration surface. See Configuration for every field.
A few things a fresh scaffold intentionally does not include:
No
.zudo-doc.json— the eject provenance file is lazy-created on your firstzudo-doc eject, so an un-ejected project never carries it.No
check:html/ HTML-validation step and nogen:z-index/check:z-indexcodegen — both were pruned from generated projects. The default z-index tiers ship from the package; HTML validation and pre-push suites are opt-in add-backs (see Customizing → Restoring pre-push and HTML validation).No deploy adapter or
wrangler.toml— the default build is a pure static export. Deploying (or enabling SSR features like the AI assistant) is an explicit extend step.
Note
@takazudo/zdtp is added only when you enable designTokenPanel. It is an optional peer of @takazudo/zudo-doc, so a project that leaves the panel off never installs it. The package's chrome still imports the panel bootstrap module at module scope (so zfb's island scanner can find it), but that module reaches @takazudo/zdtp solely through a rejection-handled dynamic import() on first use (see Lazy loading) — an edge the bundler tolerates when the package is absent, so a panel-less project builds without it. If you turn designTokenPanel on in a project that was scaffolded without it, install @takazudo/zdtp yourself and add @import "@takazudo/ to src/.
Color Schemes
zudo-doc ships exactly two color schemes — Default Light and Default Dark — sharing one set of OKLCH ramps. There is no bundled catalog of community or terminal presets to pick a --scheme value from.
Customization happens one level deeper, through the colorSchemes escape-hatch field in zfb.config.ts: pass your own { ramps, map } palette map to zudoDoc({ colorSchemes: { … } }) (see Color — "Adding a Custom Color Scheme"). Preview the result live in the Design Token Panel's Palette tab (see Color Scheme Preview) before committing it to source.
Theme Packs
Independently of the color scheme, the scaffold can start a project on any bundled theme pack — a prebuilt design bundle layered on top of the scheme system. Pass --theme-pack <slug>, or answer the interactive "Theme pack:" prompt (asked between the color-scheme questions and the feature multiselect). The chosen slug is written to themePack in the generated zfb.config.ts (only when it differs from default, per the diff-from-defaults rule). The on-page switcher UI is a separate feature toggle, --theme-pack-switcher.
Options
Project
| Flag | Description | Default |
|---|---|---|
[destination] | Directory to scaffold into (first positional arg); may be a path whose last segment becomes the project name | my-docs |
--name <name> | Project name written to the generated package.json; overrides the name derived from the destination | destination's last segment |
--lang <code> | Default language code | en |
--additional-langs <a,b> | Ordered additional locale codes; implies i18n and replaces a preset list | — |
--changelog-packages <a,b> | Generate a nested changelog landing page and one package index per comma-separated slug | — |
--github-url <url> | GitHub repository URL (drives header link + source link) | — |
--pm <manager> | Package manager: pnpm, npm, yarn, bun | pnpm |
--[no-]install | Install dependencies after scaffolding | prompt |
--[no-]git | Initialize a git repository + initial commit (enables doc-history metadata) | on |
--changelog-packages core,cli implies --changelog and scaffolds a multi-package changelog layout.
Color Scheme
| Flag | Description | Default |
|---|---|---|
--color-scheme-mode <mode> | single or light-dark | light-dark |
--scheme <name> | Color scheme (single mode) | Default Dark |
--light-scheme <name> | Light scheme (light-dark mode) | Default Light |
--dark-scheme <name> | Dark scheme (light-dark mode) | Default Dark |
--default-mode <mode> | light or dark (light-dark mode) | dark |
--[no-]respect-system-preference | Respect OS color scheme preference | true |
Theme Pack
| Flag | Description | Default |
|---|---|---|
--theme-pack <slug> | Theme pack applied to the generated project — any slug from the Theme Gallery | default |
Features
| Flag | Description | Default |
|---|---|---|
--[no-]i18n | Legacy multi-language toggle; without a list, infers one additional locale | off |
--[no-]search | Built-in full-text/word-match search over a generated search-index.json | on |
--[no-]sidebar-filter | Real-time sidebar filtering | on |
--[no-]claude-resources | Claude Code docs generation | off |
--[no-]codex-resources | Codex docs generation | off |
--[no-]claude-skills | Ship zudo-doc-* Claude Code skills (design-system, translate, version-bump) | off |
--[no-]claude-skills-writing | Ship the zudo-doc-writing skill (doc-writing + navigation-structure guide for AI-assisted authoring) | off |
--[no-]design-token-panel | Interactive tabbed panel for tweaking spacing, font, size, and color tokens | off |
--[no-]theme-pack-switcher | Bottom-right flyout (and browse-all dialog) to switch between installed theme packs | off |
--[no-]sidebar-resizer | Draggable sidebar width | on |
--[no-]sidebar-toggle | Show/hide desktop sidebar | on |
--[no-]toc-toggle | Show/hide the desktop table of contents (edge chevron, xl screens) | on |
--[no-]versioning | Multi-version documentation support | off |
--[no-]doc-history | Document edit history | on |
--[no-]body-foot-util | Right-aligned strip below each doc: doc history trigger + View source on GitHub link | off |
--[no-]llms-txt | Generate llms.txt for LLM consumption | on |
--[no-]skill-symlinker | Symlink documentation skills into Claude Code or Codex | off |
--[no-]tauri | Tauri desktop app (Mode 1) — macOS offline reader with in-page search | off |
--[no-]tauri-dev | Tauri dev wrapper (Mode 2) — configurable desktop dev wrapper for any project | off |
--[no-]footer-nav-group | Navigation links in the footer | off |
--[no-]image-enlarge | Click-to-enlarge for oversized markdown images | on |
--[no-]asset-viewer | Viewer pages for files under public/assets | on |
--[no-]dynamic-page-transition | SPA-style page transition with history handling | on |
--[no-]footer-copyright | Copyright notice in the footer | on |
--[no-]changelog | Changelog page | off |
--[no-]tag-governance | Vocabulary-aware tag audit + suggest scripts | off |
--[no-]doc-tags | Per-tag and tag-index browsing routes (docs/tags/...) | off |
--[no-]footer-taglist | Grouped tag index in the footer (requires tagGovernance) | off |
--[no-]noindex | Avoid robots indexing — noindex meta + robots.txt | off |
Preset
| Flag | Description |
|---|---|
--preset <path> | Load settings from a JSON preset file (use "-" for stdin) |
The --preset flag accepts the JSON output from the Setup Preset Generator. When a preset is loaded, all prompts are skipped (same as --yes). Individual CLI flags override preset values. In particular, --additional-langs ja,de replaces (rather than appends to) a preset's additionalLangs list. A non-empty explicit list enables i18n even if the preset or CLI also contains --no-i18n; the CLI prints a warning when it overrides that explicit disable.
General
| Flag | Description |
|---|---|
-y, --yes | Use defaults for unspecified options, skip all prompts |
-h, --help | Show help message |
Supported Languages
The --lang flag accepts any of the following language codes:
| Code | Language |
|---|---|
en | English |
ja | Japanese |
zh-cn | Chinese (Simplified) |
zh-tw | Chinese (Traditional) |
ko | Korean |
es | Spanish |
fr | French |
de | German |
pt | Portuguese |
--lang selects the primary locale used for root pages (/). Pass any number of additional locale codes with --additional-langs, for example --lang en --additional-langs ja,de; each creates a src/ tree and a / route. The order is preserved in generated config and in the language switcher, whose labels come from the configured locale map rather than hard-coded JP/JA values.
Omitting --additional-langs, passing a blank interactive value, or omitting additionalLangs in a preset creates a single-locale project. A legacy preset or API call that supplies only i18n: true retains compatibility inference: ja is inferred for primary en, and en for any other primary code. Explicit locale codes are lowercased and validated for safe path/URL use; invalid codes, separators, traversal segments, duplicates, and the primary code are rejected before files are written.
The ja tree receives Japanese starter prose. Every other arbitrary additional locale receives English placeholder starter prose that should be translated before publishing. Built-in UI translations resolve as requested locale → configured default locale → package English → raw UI-string key.
Examples
Interactive mode
pnpm create zudo-docNon-interactive with all defaults
pnpm create zudo-doc my-docs --yesScaffolding into a subdirectory
pnpm create zudo-doc sub/ref-doc --yesCreates sub/ref-doc/ with the package name ref-doc. Useful for generating several projects side by side under one scratch directory — for example to diff two template versions against each other.
Japanese site, single dark scheme
pnpm create zudo-doc my-docs --lang ja --scheme "Default Dark" --no-i18n --pm pnpm --installLight/dark mode with an explicit default mode
pnpm create zudo-doc my-docs \
--color-scheme-mode light-dark \
--default-mode light \
--no-respect-system-preference \
--yesUsing a preset file
Generate a preset JSON from the Setup Preset Generator, save it to a file, then pass it to the CLI:
pnpm create zudo-doc --preset setup.json --installOr pipe JSON directly via stdin:
cat setup.json | pnpm create zudo-doc --preset - --installCI/automation usage
pnpm create zudo-doc my-docs \
--lang en \
--scheme "Default Dark" \
--no-i18n \
--search \
--no-claude-resources \
--no-codex-resources \
--pm pnpm \
--install \
--yesProgrammatic API
The package also exports a programmatic API. The options object accepts the same fields as the JSON preset, plus install and git options. The programmatic API defaults both to false. There is no destination option — the destination path is a CLI-level concept, so here projectName doubles as the directory name, resolved against the current working directory.
import { createZudoDoc } from "create-zudo-doc";
await createZudoDoc({
projectName: "my-docs",
defaultLang: "en",
colorSchemeMode: "light-dark",
lightScheme: "Default Light",
darkScheme: "Default Dark",
defaultMode: "dark",
respectPrefersColorScheme: true,
themePack: "foundry",
features: [
"search",
"sidebarFilter",
"sidebarResizer",
"sidebarToggle",
"tocToggle",
"docHistory",
"footerCopyright",
],
cjkFriendly: false,
minifyHtml: true,
headerRightItems: [
{ type: "component", component: "theme-toggle" },
{ type: "component", component: "github-link" },
],
metaTags: {
description: true,
ogImage: "/img/ogp.png",
},
packageManager: "pnpm",
install: true,
git: true,
});headerRightItems (see the Header Right Items guide) and metaTags (see Configuration) accept the same shapes as the JSON preset fields of the same name, and are validated with the same rules — an unknown headerRightItems component/trigger name or an invalid metaTags sub-field type throws before scaffolding starts.