## Usage

```bash
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](https://zudo-doc.takazudomodular.com/docs/getting-started/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`:

```bash
# Creates ./sub/ref-doc, package name "ref-doc"
pnpm create zudo-doc sub/ref-doc --yes
```

Only 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` | `my-docs` |
| `sub/ref-doc` | `./sub/ref-doc` | `ref-doc` |
| `./sub/ref-doc/` | `./sub/ref-doc` | `ref-doc` |
| `../ref-doc` | `../ref-doc` | `ref-doc` |
| `/tmp/scratch/ref-doc` | `/tmp/scratch/ref-doc` | `ref-doc` |

Upward traversal (`../ref-doc`) 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:

```text
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:

```text
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:

```bash
# 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](https://zudo-doc.takazudomodular.com/docs/getting-started/installation#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/config/settings.ts` — the one config file is the whole configuration surface. See [Configuration](https://zudo-doc.takazudomodular.com/docs/guides/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 first `zudo-doc eject`, so an un-ejected project never carries it.
- **No `check:html` / HTML-validation** step and **no `gen:z-index` / `check:z-index`** codegen — 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](https://zudo-doc.takazudomodular.com/docs/reference/customizing#rung-9-%E2%80%94-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.

[Dynamic content unavailable in text export]

`@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](https://zudo-doc.takazudomodular.com/docs/reference/design-token-panel#implementation-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/zdtp/styles.css";` to `src/styles/global.css`.



## 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](https://zudo-doc.takazudomodular.com/docs/reference/color#adding-a-custom-color-scheme) — "Adding a Custom Color Scheme"). Preview the result live in the [Design Token Panel](https://zudo-doc.takazudomodular.com/docs/reference/design-token-panel#ai-workflow)'s Palette tab (see [Color Scheme Preview](https://zudo-doc.takazudomodular.com/docs/guides/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](https://zudo-doc.takazudomodular.com/docs/reference/theme-packs) — 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` |

Because `--respect-system-preference` defaults to `true`, a first visit without a saved choice selects System and follows the device. `defaultMode` remains the light/dark fallback when system following is disabled; see the [Color reference](https://zudo-doc.takazudomodular.com/docs/reference/color) for persistence and the appearance menu.

### Theme Pack

| Flag | Description | Default |
|------|-------------|---------|
| `--theme-pack <slug>` | Theme pack applied to the generated project — any slug from the [Theme Gallery](https://zudo-doc.takazudomodular.com/docs/reference/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-]agent-export` | Publish the versioned static agent-readable corpus | off |
| `--[no-]mcp` | Add read-only MCP `search` and `fetch` tools | off |
| `--mcp-deploy cloudflare` | Cloudflare Workers deployment preset for MCP; requires MCP | — |
| `--[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](https://zudo-doc.takazudomodular.com/docs/getting-started/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.

### Agent export and MCP choices

`agentExport` and `mcp` are feature keys in JSON presets and the programmatic API. `mcpDeploy` is the generator-only top-level property; its sole supported value is `"cloudflare"`. It is not a `zudoDoc` package setting. The same choices are available in the interactive prompts and CLI flags. MCP with omitted export enables it automatically, and MCP with omitted target selects Cloudflare. Generated config makes both choices visible; `--yes`, barebone, and legacy convenience presets leave both features off unless requested. `llmsTxt` remains on by default in the initializer.

```json
{
  "features": ["agentExport", "mcp"],
  "mcpDeploy": "cloudflare"
}
```

```bash
pnpm create zudo-doc my-docs --mcp --mcp-deploy cloudflare --yes
```

The programmatic `createZudoDoc` options accept `features: ["agentExport", "mcp"]` and `mcpDeploy: "cloudflare"` with the same validation. Explicitly disabling export while enabling MCP is rejected before files are written. A deploy target without MCP is rejected, and unsupported targets are rejected even when MCP is disabled. The errors are:

```text
MCP requires agentExport: true. Remove the explicit agent export disable or disable MCP.
Unsupported mcpDeploy value. Supported value: cloudflare.
mcpDeploy requires mcp: true. Enable MCP or remove mcpDeploy.
```

See [Agent-readable export](https://zudo-doc.takazudomodular.com/docs/guides/agent-export) and [MCP server](https://zudo-doc.takazudomodular.com/docs/guides/mcp-server) for build output, deployment, and an existing-project recipe.

### 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 (`/docs/...`). Pass any number of additional locale codes with `--additional-langs`, for example `--lang en --additional-langs ja,de`; each creates a `src/content/docs-<code>/` tree and a `/<code>/docs/...` 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

```bash
pnpm create zudo-doc
```

### Non-interactive with all defaults

```bash
pnpm create zudo-doc my-docs --yes
```

### Scaffolding into a subdirectory

```bash
pnpm create zudo-doc sub/ref-doc --yes
```

Creates `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

```bash
pnpm create zudo-doc my-docs --lang ja --scheme "Default Dark" --no-i18n --pm pnpm --install
```

### Light/dark mode with an explicit default mode

```bash
pnpm create zudo-doc my-docs \
  --color-scheme-mode light-dark \
  --default-mode light \
  --no-respect-system-preference \
  --yes
```

### Using a preset file

Generate a preset JSON from the [Setup Preset Generator](https://zudo-doc.takazudomodular.com/docs/getting-started/setup-preset-generator), save it to a file, then pass it to the CLI:

```bash
pnpm create zudo-doc --preset setup.json --install
```

Or pipe JSON directly via stdin:

```bash
cat setup.json | pnpm create zudo-doc --preset - --install
```

### CI/automation usage

```bash
pnpm create zudo-doc my-docs \
  --lang en \
  --scheme "Default Dark" \
  --no-i18n \
  --search \
  --no-claude-resources \
  --no-codex-resources \
  --pm pnpm \
  --install \
  --yes
```

## Programmatic 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.

```ts
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](https://zudo-doc.takazudomodular.com/docs/guides/header-right-items)) and `metaTags` (see [Configuration](https://zudo-doc.takazudomodular.com/docs/guides/configuration#identity-and-urls-metatags)) 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.