BoxLang 馃殌 A New JVM Dynamic Language Learn More...

BX Sites

v1.0.0-snapshot BoxLang Modules

鈿★笌 BX Sites

|:------------------------------------------------------: |
| 鈿★笌 B o x L a n g 鈿★笌
| Dynamic : Modular : Productive |
| :----------------------------:  |
Copyright Since 2023 by Ortus Solutions, Corp
www.boxlang.io | www.ortussolutions.com

聽

Write your content in Markdown. BX Sites turns it into a complete, themed, searchable website - ready to deploy.

It's a general-purpose static site generator, not just for documentation - docs, a blog, a marketing site, a knowledge base, anything Markdown can express, all built the same way, with the same themes, search and i18n. Built in BoxLang on top of bx-markdown, in the spirit of mkdocs: point it at a docs/ folder (or src/, if that reads better for your project) and get a themed, searchable static site out. Already on GitBook, mkdocs, or Notion, or just have a folder of Markdown? bxSites migrate --from=gitbook|mkdocs|markdown-zip|notion converts it straight into a bx-sites project - see Migrating from GitBook or Migrating from mkdocs.


Features

  • Ten built-in themes - bootstrap (default), material, tailwind, and seven more inspired by Docsy, Stripe, Docusaurus, Just the Docs, VuePress, GitBook and Notion, all overridable via a project's own .theme/ folder (inside its content root). See Themes.
  • Static, client-side search - a MiniSearch-powered index (fuzzy matching, prefix search) with a Cmd/Ctrl+K command palette, or wire up Algolia DocSearch/Pagefind/your own provider instead. See Search.
  • A rich Markdown+ toolkit - GitBook-style content blocks (cards, tabs, expandables, buttons, prompts, conditional/audience-switched content), always-on GFM tables with a sticky-header/responsive-scroll treatment, an embeddable OpenAPI/Swagger widget, admonitions, footnotes, math and Mermaid diagrams. See Content Blocks and Markdown Extensions.
  • Reusable {{ variables }} and magic functions - reference bxsites.yaml-defined values or call a small BoxLang helper function straight from Markdown, no plugin needed. See Variables & Magic Functions.
  • A blog, versioning, and i18n, all by convention - docs/blog/posts/ for authors/categories/RSS/drafts, version:new to snapshot a release, docs/i18n/<code>/ to translate. See Blog, Versioning, i18n.
  • Ship it anywhere - bxSites deploy to S3 (and any S3-compatible service), Azure Blob Storage, GCS, Firebase Hosting, FTP/SFTP, rsync, Netlify, Vercel, Cloudflare Pages, a local directory, or GitHub Pages - one shared build, every deployments/*.json target at once if you want, bxSites publish to bxSites Cloud itself, or bxSites package for a plain zip instead. See Deployment.
  • A real plugin/theme system - a plugin is just another BoxLang module; install:plugin/install:theme pull published ones from ForgeBox, and theme:import converts an existing mkdocs/jekyll/hugo theme into a starting point. See Plugins.
  • API reference generation for BoxLang and ColdBox - bxSites docbox turns your classes into themed, searchable API pages via DocBox's JSON output, and bxSites coldbox documents a whole ColdBox app - routes, handlers, models and WireBox mappings, modules, interceptors, scheduled tasks - straight from its conventions, without booting it. See DocBox API Reference and ColdBox Applications.
  • AI agent skills - bxSites skills:install (or npx skills add ortus-boxlang/bx-sites-skills, or coldbox ai skills install) teaches Claude Code, Cursor, Codex, and other AI coding assistants bx-sites' own conventions - content blocks, config keys, deployment, and more. See AI Agent Skills.
  • SEO and correctness out of the box - sitemap.xml, robots.txt (or your own hand-authored one), canonical links, llms.txt, and redirects that keep a moved/renamed page's old URL working instead of 404ing.
  • Fast and air-gapped by default - fingerprinted CSS/JS bundling and responsive images, with Bootstrap, highlight.js, Alpine.js, MiniSearch and (opt-in) Mermaid all vendored locally - zero outbound requests from a built site.

Quick Start

Needs the BoxLang runtime installed first - either the quick installer (curl -fsSL https://install.boxlang.io/ | bash) or BVM (curl -fsSL https://install-bvm.boxlang.io/ | bash). See Getting Started for details.

# OS Binary
install-bx-module bx-sites

# CommandBox
box install bx-sites

# Scaffold a new docs project (docs/ + bxsites.yaml)
bxSites new my-docs
cd my-docs

# Build the static site to site/
bxSites build

# Or build and serve locally with live reload while you write
bxSites serve

See Getting Started for the full walkthrough.

Usage

box install drops a standalone bxSites script on your PATH (via box.json's boxlang.executable), so every verb 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):

bxSites <verb> [options]
# or, equivalently:
boxlang bxSites <verb> [options]
Verb Purpose
new Scaffold a new project (docs|src/ + bxsites.yaml, defaulting to the bootstrap theme; --format=json for bxsites.json instead)
build Render docs|src/**.md into a static site in site/, including the search index, sitemap.xml, llms.txt and assets. Needs bx-markdown, bx-esapi, bx-yaml and bx-image installed
serve Build and serve the site locally with live reload (needs bx-markdown, bx-esapi, bx-yaml and bx-image too)
search-index Rebuild site/search-index.json standalone (also runs automatically during build)
clean Remove site/ and any build cache
migrate Convert an existing GitBook export, mkdocs project, plain zip of Markdown, or Notion export into docs/ + nav.json (--from=gitbook, the default, --from=mkdocs, --from=markdown-zip, or --from=notion)
audit CI-grade content check on a built site/: broken internal links/images, missing alt text, orphaned pages
stats Read-only summary report on a built site/: page/word counts, versions/locales, blog, tags, search index, site size
doctor Environment/config health check: JVM, docs/ (or src/), config validity, required modules, theme override
post:new Scaffold a new blog post at docs/blog/posts/<slug>.md
version:new Snapshot docs/ into a new docs/versions/<name>/
i18n:status Per-locale translation coverage report against the default tree
i18n:new Scaffold a new docs/i18n/<code>/ locale
page:new Scaffold a single docs page at an arbitrary path
plugin:new Scaffold a plugin module skeleton
install:plugin Download a plugin from ForgeBox into project-local boxlang_modules/
theme:new Eject a built-in theme into your content root's .theme/ for customizing
install:theme Download a theme from ForgeBox into your content root's .themes/<name>/
skills:install Install the official AI agent skill pack (ortus-boxlang/bx-sites-skills) via npx skills add
theme:import Best-effort convert a mkdocs/jekyll/hugo theme's own template files into a .themes/<name>/ scaffold
page:rename Move a docs page and rewrite every relative link that pointed at it
blog:drafts List every blog post whose frontmatter sets draft: true
blog:find Filter blog posts by author/category/tag/date range
search:query Query a built search-index.json and rank results
lint Pre-build content checks: heading level skips, blog posts missing a valid date
docbox Generate a BoxLang/CFML API reference from DocBox into the content dir (needs the bx-docbox module)
coldbox Document a ColdBox application from its conventions: routes, handlers, models, modules, interceptors, scheduled tasks
gh-deploy Build and force-push site/ to a gh-pages-style branch (--branch, --remote, --message)
deploy Build and ship site/ to a real target (s3, azure, gcs, firebase, ftp, sftp, rsync, netlify, vercel, cloudflare-pages, local, github-pages); no args deploys every deployments/*.json entry; --verbose
publish Build and publish site/ to bxSites Cloud via cloud.siteId/cloud.apiUrl in bxsites.yaml (--token, overrides the BXSITES_CLOUD_TOKEN env var)
package Build and zip site/ into a single archive (--output=<path>, defaults to site.zip)

Every verb accepts --projectRoot=<path> (or a bare positional path) to target a project other than the current directory. Run bxSites help (or bxSites with no verb at all) for full usage - -h/--help show BoxLang's own generic runtime help instead, since BoxLang's CLI reserves those as its own global flags before bxSites ever sees them; see CLI Reference.

Documentation

This repository documents itself with BX Sites - see bxsites.yaml and docs/ at the repo root, published at:

  • bxsites.io - the latest released version (bxsites.yaml's own versions.default)
  • bxsites.io/next - unreleased docs, currently being written toward the next release

Both are built with all ten built-in themes side by side (bootstrap at the root, every other theme under theme/<name>/) - this doubles as a theme gallery - use the switcher next to the dark-mode toggle to flip between them on any page. CI builds each theme as its own parallel job (see .github/workflows/pages.yml); ./buildMultiTheme.sh reproduces the same gallery layout locally for a quick preview.

Or read the source directly:

See MODULE_SPEC.md for the design spec driving this module's development.

Directory Structure

  • .github/workflows - CI: tests (tests.yml), PR checks (pr.yml), snapshot/release builds (snapshot.yml, release.yml), and publishing this repo's own docs to GitHub Pages (pages.yml)
  • models - the module's own source: models/cli (one dispatcher per bxSites verb), models/config (site config loader/validator - bxsites.yaml/.yml/.json), models/build (project scaffolding + the docs/nav/markdown/theme/search/sitemap build pipeline), models/deploy (the deploy verb's pluggable targets - S3, Azure, GCS, Firebase, FTP/SFTP, rsync, Netlify, Vercel, Cloudflare Pages, local, GitHub Pages), models/publish (the publish verb's own bxSites Cloud client)
  • resources/themes - built-in themes (native BoxLang .bxm templates + assets), ten in total: bootstrap (default), material, tailwind, plus seven material-forked themes (docsy, slate, docusaurus, justthedocs, vuepress, gitbook, notion) - all with the BoxLang brand palette, dark mode, breadcrumbs and code-copy buttons applied out of the box. A project can override any of them via its own .theme/ folder inside its content root (same layout.bxm + page.bxm contract - see Themes)
  • resources/assets - module-wide shared client-side assets: the search widget (search.js, MiniSearch-backed with a Cmd/Ctrl+K palette), the copy-code button, and per-feature init scripts (tabs, Mermaid, math, OpenAPI, prompts, conditional content, ...), plus every vendored third-party library under vendor/ (Bootstrap, highlight.js, Alpine.js, MiniSearch, Mermaid, Swagger UI) - no CDN, no outbound requests from a built site
  • docs / bxsites.yaml - this repository's own docs, built by BX Sites itself (boxlang bxSites build)
  • tests/specs - TestBox specs, one bundle per class under models/
  • box.json - package metadata used to publish to ForgeBox
  • ModuleConfig.bx - this module's configuration/CLI entry point

Local Building

Build.bx packages this module for distribution to ForgeBox: it produces a zip in build/ containing everything needed to run the module (box.json, ModuleConfig.bx, and the rest of the module's own files).

It also produces a second, self-contained artifact - build/artifacts/bx-sites-<version>-with-deps.zip - that additionally bundles every runtime dependency from box.json's dependencies block (bx-markdown, bx-esapi, bx-yaml, bx-image, bx-ftp, bx-toml) inside a modules/ folder alongside the module itself, using BoxLang's module inception: a module's own modules/ folder is discovered and activated before the module itself, so this artifact needs nothing pre-installed to run standalone - just drop it into a modules/ (or boxlang_modules/) folder on its own. The primary bx-sites-<version>.zip artifact - and the box forgebox publish step, which publishes from build/module - are unaffected; the bundled dependencies only ever land in the -with-deps artifact, built from a separate build/module-with-deps copy.

boxlang Build.bx --version=1.1.0
Option Required Default Value Description
version No1.0.0 The version of the module.
branch Nodevelopment The branch being built.
buildId NoUUID (generated)A unique identifier for the build.

Running Tests

Copy .env.example to .env for the local preview settings.

cp .env.example .env

Run the setup script once to create boxlang_modules/ and register this checkout as boxlang_modules/bx-sites. If the root modules/ folder is missing, it asks whether it should run box install for you:

boxlang Setup.bx

With CommandBox installed, run tests using bash ./testbox/run.

To preview the dogfooded documentation site locally:

boxlang bxSites serve --host="$BXSITES_PREVIEW_HOST" --port="$BXSITES_PREVIEW_PORT"

Open http://$BXSITES_PREVIEW_HOST:$BXSITES_PREVIEW_PORT in a browser. serve builds the site, watches source files, and reloads the browser when changes are detected. Stop it with Ctrl+C; the generated site/ directory is ignored and should not be committed.

Version Management

This module uses SemVer for versioning. The version is stored in box.json, used to publish to ForgeBox, and bumped automatically by the release workflow, which also tags the repo for each release.

Cutting a release

Development happens on development; a release is just merging it into main - release.yml triggers on that push and does the rest:

  1. Finalizes changelog.md's ## [Unreleased] section under the real version/date, and generates a matching docs/releases/vX.Y.Z.md "what's new" page from it.
  2. Packages the module (Build.bx), tags the repo vX.Y.Z, and publishes to ForgeBox, S3, and a GitHub Release.
  3. Bumps development's own box.json to the next minor version and carries the finalized changelog/release-notes content back onto it, so ## [Unreleased] is ready for the next cycle immediately.

A push to development instead builds and publishes a -snapshot (steps 1-2 only, no version bump - see snapshot.yml/release.yml's own snapshot: true input).

This repository doesn't have a main branch yet - create one from development (git checkout -b main development && git push -u origin main) when you're ready to cut the first release; every release after that is just merging development into it.

GitHub Actions Automation

  • pr.yml - runs the test suite against every pull request
  • tests.yml - the reusable test-suite workflow (./testbox/run), called by both pr.yml and snapshot.yml
  • snapshot.yml - on every push to development: runs tests, then builds and publishes a snapshot release
  • release.yml - builds and publishes a release to ForgeBox (a stable release from main, or a snapshot when called from snapshot.yml); requires a FORGEBOX_API_TOKEN secret
  • pages.yml - builds and publishes this repo's own dogfooded docs to GitHub Pages (see Deploying to GitHub Pages)
  • cron.yml - runs the test suite daily against development

Ortus Sponsors

BoxLang is a professional open-source project and it is completely funded by the community and Ortus Solutions, Corp. Ortus Patreons get many benefits like a cfcasts account, a FORGEBOX Pro account and so much more. If you are interested in becoming a sponsor, please visit our patronage page: https://patreon.com/ortussolutions

THE DAILY BREAD

"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.


[Unreleased]

Added

  • First release
  • docbox verb - generates a BoxLang/CFML API reference into the content directory from DocBox's own JSON output, with the class metadata DocBox's JSON strategy drops (declared properties, implemented interfaces, class annotations, per-function @return text) merged back in. Needs the bx-docbox module.
  • coldbox verb - documents a ColdBox application from its conventions on disk without booting it: routes (including resources() expansion and module entry points), handlers with their actions and the routes that reach them, models with their WireBox injections and the binder's own mappings, modules, interceptors, and scheduled tasks.
  • docbox and coldbox configuration blocks, with validation.
  • bxSitesDocBoxDoc (Gradle) and bxsites:docbox (Maven) wrap the docbox verb for JVM projects whose sources include BoxLang/CFML classes. There is deliberately no ColdBox equivalent: a ColdBox application is built through CommandBox, not a Java build tool.

Fixed

  • build/serve crashed on Windows with a PatternSyntaxException in any project with a blog post or with responsive images enabled - BlogDiscoverer, ContentLinter and ImageVariantGenerator derived a file's docs-relative path by handing an absolute directory straight to reReplace() as its pattern; a Windows path's backslashes (\U, \d, ...) are regex escapes, not literal separators. Fixed via a shared PathRelativizer, the same safe substring-based approach DocsLoader already used. serve's live-reload watcher had the same root cause in a milder form - a mixed-separator prefix check that silently always missed on Windows, degrading every edit to a full cache-clearing rebuild instead of the fast single-page path.

  • The Gradle/Maven plugins' subprocess launcher never found java.home's own java launcher on Windows (only java.exe exists there), so every Windows invocation of build/serve/every other verb silently fell back to a bare java PATH lookup instead of guaranteed relaunching on the same JVM.

  • The OpenAPI output example guide (and its four translations) linked to ../assets/openapi/example.yaml, one directory level too shallow for the page's own built (clean-URL) location - broken since the guide was added.

  • coldbox told a reader to install bx-docbox whenever class metadata was missing, including when the module was installed and the DocBox run had simply failed. The failure is now reported with its real cause, on the pages and in the verb's output, and the install advice is kept for the case that actually calls for it.

  • Spring controller-scan pages emitted a raw table whose rows carried their own Alpine x-show attributes; those never worked, because TableWrapProcessor injects its own into every row of a table with ten or more rows and the Markdown renderer entity-escapes a <tr>'s attribute values. Those pages now use a plain pipe table, which picks up bx-sites' own table filter.

$ box install bx-sites

No collaborators yet.
     
  • {{ getFullDate("2026-08-22T23:05:07Z") }}
  • {{ getFullDate("2026-10-07T10:40:03Z") }}
  • 381
  • 1,614