CLI Reference
Every bxSites verb and its flags.
On this page
- Global options
- new
- build
- serve
- search-index
- clean
- gh-deploy
- deploy
- package
- migrate
- --from=gitbook (default)
- --from=mkdocs
- --from=markdown-zip
- --from=notion
- All four
- check
- stats
- doctor
- post:new
- version:new
- i18n:status
- i18n:new
- page:new
- plugin:new
- install:plugin
- theme:new
- install:theme
- skills:install
- theme:import
- page:rename
- blog:drafts
- blog:find
- search:query
- lint
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
| Flag | Description |
|---|---|
-h, --help | Show usage and exit |
-v, --version | Show the module version and exit |
Every verb below ships with core. An installed and activated addon module
can register further verbs of its own (e.g. a commercial deploy/hosting
addon adding bxSites cloud publish) - --help lists whatever's
currently activated in your project alongside the verbs below. See
CLI Providers if you're writing one.
new
Scaffold a docs project.
bxSites new [path] [--name=...] [--theme=<see guides/themes.md for all 10>] [--description=...] [--format=yaml|json]
--name- the site name written into the site config (defaults to the target directory's name)--theme- defaults tobootstrap--description- the site description written into the site config--format-yaml(default, scaffoldsbxsites.yaml) orjson(scaffoldsbxsites.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). A native BoxLang file watcher - not a poll loop - reacts to a saved change immediately, and only reconverts the page(s) that actually changed rather than the whole site, so the save-and-reload loop stays fast.
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
buildwrites 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 togh-pages--remote- defaults toorigin--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.).
deploy
Builds the site, then ships it to a real deployment target - S3 (and any
S3-compatible service - DigitalOcean Spaces, Cloudflare R2, Backblaze B2,
MinIO), Azure Blob Storage, Google Cloud Storage, Firebase Hosting, FTP,
SFTP, rsync-over-SSH, Netlify, Vercel, Cloudflare Pages, a local directory,
or GitHub Pages (the same push gh-deploy does, just reachable from this
one unified command too).
bxSites deploy --entry=<name> [--verbose]
bxSites deploy [--target=local|github-pages] [target-specific flags] [--verbose]
bxSites deploy [--verbose]
Three ways to invoke it:
--entry=<name>- dispatches to whatever target adeployments/<name>.jsonfile declares (see below). Every target exceptlocal/github-pagesneeds this - there's more configuration than a couple of flags can reasonably carry.--target=<name>with its own flags - a flag-only shorthand for the two simplest targets, needing nodeployments/folder at all:local(--destination=<path>) andgithub-pages([--branch] [--remote] [--message], every field optional, same defaults asgh-deploy).- Neither flag - deploy everything. Every
deployments/*.jsonentry is deployed in turn, off a single shared build (the site is built once, not once per target). Requires at least onedeployments/*.jsonentry to exist. One target failing doesn't stop the rest - every entry is attempted, and the command only exits non-zero if at least one of them failed; the final summary reports how many succeeded (e.g.Deployed to 2/3 target(s) (1 failed)).
--verbose prints a progress line as the build starts/finishes and as each
target starts/finishes, instead of just the final one-line summary.
See Deployment for every target's own config
shape and a real deployments/*.json example for each.
package
Builds the site, then zips it into a single distributable archive - a
plain zip whose root is the built site's own contents (not a wrapping
site/ folder), ready to attach to a release or hand to any host that
only accepts a zip upload.
bxSites package [--output=<path>]
--output defaults to <projectRoot>/site.zip (a relative value is
resolved against the project root); a nested destination's parent
directories are created automatically.
migrate
Converts an existing docs project into this one - --from picks the
source format: gitbook (the default), mkdocs, markdown-zip, or notion.
bxSites migrate --source=/path/to/gitbook-export
bxSites migrate --source=/path/to/mkdocs-project --from=mkdocs
bxSites migrate --source=/path/to/export.zip --from=markdown-zip
bxSites migrate --source=/path/to/notion-export --from=notion
--source(required) - path to the export/project's root directory (SUMMARY.mdforgitbook,mkdocs.ymlformkdocs), or a.zipfile (markdown-zip;notionaccepts either a.zipor an already-extracted folder)--from-gitbook(default),mkdocs,markdown-zip, ornotion
--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.
--from=markdown-zip
A plain .zip of Markdown files - no proprietary export format to
translate, since a folder's own nesting already is bx-sites' own nav
convention and a page-to-page relative .md link already resolves the
way bx-sites expects. Mostly a straight copy: every non-.md file (an
image, say) is relocated to docs/assets/imported/ and every page's own
reference to it rewritten to match. No bxsites.yaml/docs/nav.json is
written - a plain zip carries no site name or nav structure of its own to
translate.
--from=notion
A Notion "Export as Markdown & CSV" archive (a .zip, or an
already-extracted folder) - handles Notion's own two quirks nothing else
here migrates from has: every page/sub-page folder is suffixed with a
space and a 32-character id (disambiguating same-titled pages, never
meant to be read), and a page's title is repeated as a literal leading
# Heading rather than carried in frontmatter. Both are cleaned up: the
id suffix is stripped and the remaining name slugified for the output
filename, the leading heading becomes a real title frontmatter field
instead of a duplicate first line, and every link/image target (which
Notion writes URL-encoded, still pointing at the original id-suffixed
names) is rewritten to match. Non-.md files are relocated to
docs/assets/imported/, same as markdown-zip above.
All four
Prints a summary of pages (and, for mkdocs/markdown-zip/notion, 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 insite/. Fails the check. - Missing alt text - any
<img>with noaltattribute at all. An emptyalt=""(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'sindex.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. frontmatterhidden: 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-defaultdocs/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) -nonewhen 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, ornonewhen 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.yaml/.json 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 frontmattertitle--slug- defaults to a slugified--title--date- defaults to today (yyyy-MM-dd)--authors,--categories,--tags- comma-separated--draft- defaults totrue(pass--!draftto 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.yaml'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.yaml's plugins array.
install:plugin
Download a published plugin from ForgeBox and drop it straight into the
project's own boxlang_modules/ - BoxLang's own auto-loaded local-module
convention, so nothing beyond the bxSites binary itself is needed (no
box/CommandBox involved).
bxSites install:plugin --name=bx-sites-plugin-analytics [--version=1.2.0]
--name(required) - the ForgeBox slug to install--version- a specific version; omit for the latest
Prints the module's real registered mapping name once loaded - add that
name to bxsites.yaml's plugins array to activate it (installing alone
never activates a plugin - see Plugins).
theme:new
Eject one of the built-in themes into the project's own theme/ folder
for customizing, matching mkdocs' --theme eject workflow.
bxSites theme:new --theme=material
--theme(required) -bootstrap,material,tailwind,docsy,slate,docusaurus,justthedocs,vuepress,gitbook, ornotion- see Themes
Fails rather than overwriting an existing theme/. See
Themes for the override contract (layout.bxm +
page.bxm).
install:theme
Download a published theme from ForgeBox into the project's own
themes/<name>/ - nothing but the bxSites binary needed, same as
install:plugin.
bxSites install:theme --name=bx-sites-theme-blog1 [--version=1.0.0]
--name(required) - the ForgeBox slug to install--version- a specific version; omit for the latest
Validates the downloaded package against the ThemeProvider contract
(layout.bxm + page.bxm) before finishing, so a broken package fails at
install time rather than at the next build. Set bxsites.yaml's
theme.name to the installed name to use it - see
Themes.
skills:install
Install the official AI agent skill pack
(ortus-boxlang/bx-sites-skills) into every AI coding assistant this
project has configured - a thin wrapper over npx skills add, so a
freshly-scaffolded project's assistant knows bx-sites from the first
prompt. Also runnable as the two-word bxSites skills install - every
colon-joined verb doubles as its own space-separated form this way.
bxSites skills:install [--skill=<name>]
--skill- install just this one skill (its bare name, e.g.bx-sites-deployment) instead of the full thirteen-skill set
Requires Node.js/npx on PATH. See
AI Agent Skills for what a skill is, the full
skill list, and the other two install paths (npx skills add/coldbox ai skills install) that don't need bxSites at all.
theme:import
Best-effort conversion of a theme from another static site generator's
ecosystem (mkdocs/jekyll/hugo) into a bx-sites theme scaffold under
themes/<name>/ - a starting point, not a lossless one-command port.
bxSites theme:import --source=mkdocs --path=/path/to/theme --name=my-imported-theme
--source(required) -mkdocs,jekyll, orhugo--path(required) - the source theme's own root folder--name(required) - the destination name, written tothemes/<name>/
Safe to re-run against the same --name - layout.bxm/page.bxm are
overwritten and any newly-found asset folders merged in. See
Importing a theme for exactly what does and
doesn't get translated, and what to check afterward.
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 currentdocs/-relative path--to(required) - its newdocs/-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.
Also stamps the moved page's own frontmatter redirect_from with its old
URL, so a build (Redirects) keeps answering for it
instead of letting the rename 404 every outside link this project doesn't
control the source of.
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--sinceand/or on/before--untilmatch--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 to10
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 frontmatterdate(builditself throws on this the moment it loads posts -lintsurfaces it as a finding instead).
bxSites lint
Exits 1 when either check finds anything, 0 otherwise.