CLI Reference

Every bxSites verb and its flags.

On this page

CLI Reference

bxSites <verb> [options]

box install bx-sites drops a standalone bxSites script on your PATH (via box.json's boxlang.executable), so every verb below can be run either that short way, or as boxlang bxSites <verb> - both run the exact same thing; use the longer form anywhere the PATH shim isn't set up (a CI runner, a module registered by hand):

boxlang bxSites <verb> [options]

Every verb accepts --projectRoot=<path> (or a bare positional path) to target a project other than the current directory, and the two global flags below can appear before any verb.

Every docs/ mentioned below applies equally to a project using src/ instead - see Getting Started for the docs/-or-src/ convention. new always scaffolds docs/.

Global options

FlagDescription
-h, --helpShow usage and exit
-v, --versionShow the module version and exit

new

Scaffold a docs project.

bxSites new [path] [--name=...] [--theme=bootstrap|material|tailwind] [--description=...] [--format=yaml|json]
  • --name - the site name written into the site config (defaults to the target directory's name)
  • --theme - defaults to bootstrap
  • --description - the site description written into the site config
  • --format - yaml (default, scaffolds bxsites.yaml) or json (scaffolds bxsites.json) - see Configuration

build

Render docs/**.md into a static site in site/. Also builds the search index (unless search is false in the site config, or searchProvider is set to a provider - like algolia/pagefind - that doesn't use it, see Search), runs the pagefind CLI against the finished site/ when searchProvider.provider is "pagefind", and copies theme + docs/assets/** into site/.

bxSites build

serve

Build and serve the site locally with live reload.

bxSites serve [--port=8080] [--host=127.0.0.1]

Runs in the foreground until interrupted (Ctrl+C).

search-index

Rebuild site/search-index.json standalone, without re-rendering pages or copying assets. build already runs this same step automatically - this verb exists for when you only need to refresh the index. Only ever covers the main docs/ tree, even on a project with docs/versions//docs/i18n/

  • a real build writes each tree's own scoped index instead (see Versioning).
bxSites search-index

clean

Remove site/ and any build cache, leaving docs/ and the site config alone.

bxSites clean

gh-deploy

Builds the site, then force-pushes it to a gh-pages-style branch - one commit per deploy, no accumulated history on that branch, matching mkdocs' own mkdocs gh-deploy convention. Requires the project to be a git repository with a configured remote; never touches your own current branch or working tree (it does the push from a throwaway git worktree).

bxSites gh-deploy [--branch=gh-pages] [--remote=origin] [--message="..."]
  • --branch - defaults to gh-pages
  • --remote - defaults to origin
  • --message - the branch's single commit message, defaults to "Deploy site via bxSites gh-deploy"

See Deployment for the full GitHub Pages setup (enabling Pages for the branch, baseURL, etc.).

migrate

Converts an existing docs project into this one - --from picks the source format, gitbook (the default) or mkdocs.

bxSites migrate --source=/path/to/gitbook-export
bxSites migrate --source=/path/to/mkdocs-project --from=mkdocs
  • --source (required) - path to the export/project's root directory (must contain SUMMARY.md for gitbook, mkdocs.yml for mkdocs)
  • --from - gitbook (default) or mkdocs

--from=gitbook (default)

A GitBook export - a SUMMARY.md table of contents plus its .md files, GitBook's own on-disk sync format - into this project's docs/ tree: SUMMARY.md becomes docs/nav.json, {% block %} syntax becomes its bx-sites equivalent (::: name directives, or the native === "Title" tabs / !!! type admonition syntax where a closer match already exists - see Content Blocks), README.md files become index.md, and .gitbook/assets/** is copied to docs/assets/gitbook/.

--from=mkdocs

An mkdocs project - mkdocs.yml plus its docs/ folder - into a complete bx-sites project: mkdocs.yml becomes bxsites.yaml + docs/nav.json, and every page is copied across largely unchanged, since mkdocs-material's own admonition/tabs/math/code-annotation syntax already is bx-sites' own native syntax - see Migrating from mkdocs. Non-.md assets (images commonly sitting next to the page that uses them, mkdocs has no single asset-folder convention) are relocated to docs/assets/mkdocs/ and their references rewritten.

Both

Prints a summary of pages (and, for mkdocs, assets) converted and, when anything couldn't be auto-converted, a list of exactly what needs a manual look - nothing is silently dropped. A destination file, bxsites.yaml, or docs/nav.json that already exists is overwritten (also reported), so review the migrated output before committing it.

check

A CI-grade content quality gate over an already-built site/ - run build first. Checks for:

  • Broken internal links/images - any <a href>/<img src> pointing at a page or asset that doesn't exist in site/. Fails the check.
  • Missing alt text - any <img> with no alt attribute at all. An empty alt="" (the correct markup for a purely decorative image) is not flagged. Fails the check.
  • Orphaned pages - pages that exist in site/ but aren't reachable by following links from any tree's own homepage (the main site's index.html, and each version's/locale's own). Informational only - never fails the check, since a page a project deliberately left out of its own nav (e.g. frontmatter hidden: true) is supposed to only be reachable by a direct link.
bxSites build
bxSites check

Exits 1 when there are any broken links/images or missing-alt images, 0 otherwise (orphaned pages never affect the exit code). Deliberately internal-links-only - it does not make HTTP requests to check external URLs, which belongs in a dedicated link-checking tool run as its own job.

stats

A read-only summary report of an already-built site/ - run build first. Reports:

  • Pages and words - total page count and a rough word count (tags stripped, same "good enough for an estimate" standard as the blog's own reading-time figure), plus a per-tree breakdown once there's more than one tree (a version, or a non-default locale).
  • Versions and locales - names of every docs/versions//non-default docs/i18n/ folder.
  • Blog - post/category/author/year-active counts, straight off site/blog/'s own folder shape (so it always matches what was actually published, drafts excluded) - none when there's no blog.
  • Tags - the number of distinct tags across the whole site.
  • Search index - entry count and file size of search-index.json, or none when search is off or a non-local provider is active.
  • Site output - total file count and on-disk size of the built site/.
bxSites build
bxSites stats

Always exits 0 - purely informational, nothing here is a pass/fail gate (that's check's job).

doctor

A one-shot environment/config health check - the "run this before filing a bug report" verb. Checks the JVM version, that docs/ exists, that bxsites.json/.yaml actually parses and validates, that the required BoxLang modules (bx-markdown, bx-esapi, bx-yaml, bx-image) are installed and activated, and - if a project-level theme/ override exists - that it satisfies the two-required-file layout.bxm/page.bxm contract.

bxSites doctor

Exits 1 if any check fails, 0 otherwise. Nothing here mutates a project - purely diagnostic.

post:new

Scaffold a new blog post at docs/blog/posts/<slug>.md.

bxSites post:new --title="My New Post" [--slug=...] [--date=...] [--authors=...] [--categories=...] [--tags=...] [--draft]
  • --title (required) - also becomes the post's frontmatter title
  • --slug - defaults to a slugified --title
  • --date - defaults to today (yyyy-MM-dd)
  • --authors, --categories, --tags - comma-separated
  • --draft - defaults to true (pass --!draft to publish immediately)

See Blog for the full frontmatter reference.

version:new

Snapshot the current docs/ tree into docs/versions/<name>/, excluding assets/, versions/, i18n/, and blog/ (each is its own separately loaded tree, not part of the snapshot).

bxSites version:new --name=1.0
  • --name (required) - the version folder/label, e.g. 1.0

See Configuration's "Versioning" section.

i18n:status

Reports per-locale translation coverage - for every configured locale, how many of the default tree's pages exist (at the same relative path) under docs/i18n/<code>/, and which ones are still missing.

bxSites i18n:status

Always exits 0 - purely informational.

i18n:new

Scaffold a new docs/i18n/<code>/ locale folder, seeding an index.md copied from the default locale's own index.md when one exists.

bxSites i18n:new --code=es
  • --code (required) - the locale code, e.g. es, fr, pt-BR

See Internationalization for wiring the new locale into bxsites.json's i18n.locales.

page:new

Scaffold a single docs page at an arbitrary path under docs/, with the requested frontmatter already filled in.

bxSites page:new --path=guides/setup.md [--title=...] [--description=...] [--icon=...] [--tags=...] [--order=...]
  • --path (required) - docs/-relative, must end in .md
  • --title, --description, --icon, --order - written into frontmatter
  • --tags - comma-separated

plugin:new

Scaffold a plugin module skeleton (box.json, ModuleConfig.bx, a models/BxSitesPlugin.bx with every hook stubbed out) mirroring examples/hello-plugin/.

bxSites plugin:new --name=my-analytics-plugin [--dest=...]
  • --name (required) - the plugin's module name/slug
  • --dest - defaults to <projectRoot>/<name>

See Plugins for the hook reference and how to wire the finished plugin into bxsites.json's plugins array.

theme:new

Eject one of the built-in themes (bootstrap, material, tailwind) into the project's own theme/ folder for customizing, matching mkdocs' --theme eject workflow.

bxSites theme:new --theme=material
  • --theme (required) - bootstrap, material, or tailwind

Fails rather than overwriting an existing theme/. See Themes for the override contract (layout.bxm + page.bxm).

page:rename

Move a docs page from one path to another, rewriting every relative Markdown link across docs/** that pointed at the old path - the same file-relative link-rot problem the built HTML side already solves (check), applied to raw Markdown source at rename time instead.

bxSites page:rename --from=guides/old-name.md --to=guides/new-name.md
  • --from (required) - the page's current docs/-relative path
  • --to (required) - its new docs/-relative path

Only bare [text](relative/path.md)-style links are rewritten - absolute URLs, mailto:, and pure in-page anchors are left alone. docs/assets/** is never scanned.

blog:drafts

Lists every blog post whose frontmatter sets draft: true - build always skips drafts, so this is the only place their existence is surfaced.

bxSites blog:drafts

Always exits 0.

blog:find

Filters blog posts by author/category/tag/date range, without running a full build.

bxSites blog:find [--author=...] [--category=...] [--tag=...] [--since=...] [--until=...] [--drafts]
  • --author, --category, --tag - case-insensitive exact match against any of the post's own values
  • --since, --until - a date; only posts on/after --since and/or on/before --until match
  • --drafts - include draft posts too (excluded by default)

Every filter is optional and independent - passing none lists every published post.

search:query

Runs a keyword query against an already-built site/search-index.json - run build or search-index first. Ranks results using the same relative field weighting the client-side search widget uses (title, then tags, then headings, then body), so you can sanity-check what a real visitor's search would surface without opening a browser.

bxSites search:query --query="getting started" [--limit=10]
  • --query (required) - space-separated search terms
  • --limit - maximum results to return, defaults to 10

lint

A pre-build content quality pass over raw docs/ Markdown source, distinct from check (which only inspects an already-built site/). Checks for:

  • Heading level skips - a page body jumping straight from ## to #### with no ### in between (confusing structure, and bad for accessibility). Lines inside a fenced code block are never mistaken for headings.
  • Blog post date issues - a docs/blog/posts/** post with a missing or invalid frontmatter date (build itself throws on this the moment it loads posts - lint surfaces it as a finding instead).
bxSites lint

Exits 1 when either check finds anything, 0 otherwise.

Edit this page Download Markdown Last updated Aug 23, 2026, 2:17:28 AM