The bookmd command line and configuration
A collection is a small project: package.json, portal.config.ts and the content/ folder. The engine provides the bookmd command, which runs the application in the disposable .bookmd/ work area; the static output goes to the build/ folder. Running it requires Bun 1.4.0+ and Node 22.12+.
Commands
bookmd dev
bookmd check
bookmd build
bookmd preview
bookmd content
bookmd sources
bookmd plan
--config <file> gives the configuration; the default is portal.config.ts in the current folder. The paths of the project are relative to the configuration file.
- Arguments after
-- go to Vite (for example bookmd preview -- --host 127.0.0.1).
- An invalid command or setting, missing input and a failing tool all end with a non-zero exit code.
dev watches the content folder and reloads the browser. After changing the configuration or the engine, restart it.
Configuration (portal.config.ts)
export default {
title: 'BookMD',
contentRoot: './content',
entrypoint: 'books.md',
basePath: ''
};
The BASE_PATH environment variable overrides basePath, even when its value is empty. The configuration is executable TypeScript, so do not put secrets in it.
Installing into a collection
A collection needs a package.json that depends on the @atom-forge/bookmd package, a portal.config.ts, and content/books.md with at least one book (see the examples/minimal folder):
{ "private": true, "type": "module",
"scripts": { "dev": "bookmd dev", "build": "bookmd build", "check": "bookmd check" },
"dependencies": { "@atom-forge/bookmd": "^0.1.4" } }
- Do not commit the
.bookmd/, build/ and node_modules/ folders; the lockfile is fine to commit.
- Upgrading or rolling back: change the version, update the lockfile, then
check and build.
- An empty book list is an error:
books.md needs at least one book.
Local preview in the browser (/@dev)
The /@dev page of any BookMD site (and of the dev server) previews a local folder directly in the browser, without installing anything. Authors should read Previewing your book locally.
Change detection: bookmd plan
If the collection contains included books, plan tells you whether a new build is needed:
bookmd plan --instance-commit <sha> [--baseline plan.json] [--out plan.json] [--force]
bookmd build --sources plan.json
plan resolves every ref to a concrete commit (without downloading) and writes a plan file: the commit of the collection, the engine version, the fingerprints of bun.lock and the book list, and the commits of the included sources. It compares the plan with that of the last successful publication and prints Changed: <reasons> or Unchanged: nothing to publish. In GitHub Actions it also sets the changed and reasons outputs.
- A missing, corrupt or incomplete baseline always means a full build;
--force always rebuilds.
build --sources plan.json downloads exactly the planned commits and never resolves a ref again, so the commit that was checked is the commit that is built, even if a branch has moved on in the meantime.
- Storing the baseline is the collection's job: keep the plan file only after a successful deployment.
A book that does not build
An included book that fails (a broken link, a missing file, an invalid id or slug) does not stop the build of the others. Each included book is built on its own first, and then:
- With
--baseline plan.json (the plan of the last successful publication), the engine uses the book's last good commit instead. sources --sources plan.json --baseline baseline/plan.json downloads it in advance, because the later steps have no credentials.
- Without a good earlier version (a new book, or no baseline) the book is left out of the site.
- Either way a warning names the book and the problem: on stderr, as a GitHub Actions annotation and in the job summary.
- The plan file passed with
--sources is updated with what was really built (used per source), so the next run knows which commits are good. A book that is left out has used: null. The change detection is not affected.
- Local content, the book list, id collisions and download or access errors still stop the build. A private book whose
publish: true was removed is left out; it does not fall back to an older, approved version.
bookmd sources --sources plan.json --baseline baseline/plan.json
bookmd check --sources plan.json --baseline baseline/plan.json
bookmd build --sources plan.json --baseline baseline/plan.json
The
bookmdcommand line and configurationA collection is a small project:
package.json,portal.config.tsand thecontent/folder. The engine provides thebookmdcommand, which runs the application in the disposable.bookmd/work area; the static output goes to thebuild/folder. Running it requires Bun 1.4.0+ and Node 22.12+.Commands
bookmd dev # development server with live reload bookmd check # check the content and the links bookmd build # static site into the build/ folder bookmd preview # serve the finished build locally bookmd content # process the content only (for debugging) bookmd sources # download the included Git sources bookmd plan # change detection, see below--config <file>gives the configuration; the default isportal.config.tsin the current folder. The paths of the project are relative to the configuration file.--go to Vite (for examplebookmd preview -- --host 127.0.0.1).devwatches the content folder and reloads the browser. After changing the configuration or the engine, restart it.Configuration (
portal.config.ts)export default { title: 'BookMD', // optional title contentRoot: './content', // required; the engine only reads it entrypoint: 'books.md', // required; relative to the content folder basePath: '' // optional, for example '/books', no trailing slash };The
BASE_PATHenvironment variable overridesbasePath, even when its value is empty. The configuration is executable TypeScript, so do not put secrets in it.Installing into a collection
A collection needs a
package.jsonthat depends on the@atom-forge/bookmdpackage, aportal.config.ts, andcontent/books.mdwith at least one book (see theexamples/minimalfolder):{ "private": true, "type": "module", "scripts": { "dev": "bookmd dev", "build": "bookmd build", "check": "bookmd check" }, "dependencies": { "@atom-forge/bookmd": "^0.1.4" } }.bookmd/,build/andnode_modules/folders; the lockfile is fine to commit.checkandbuild.books.mdneeds at least one book.Local preview in the browser (
/@dev)The
/@devpage of any BookMD site (and of thedevserver) previews a local folder directly in the browser, without installing anything. Authors should read Previewing your book locally.Change detection:
bookmd planIf the collection contains included books,
plantells you whether a new build is needed:planresolves every ref to a concrete commit (without downloading) and writes a plan file: the commit of the collection, the engine version, the fingerprints ofbun.lockand the book list, and the commits of the included sources. It compares the plan with that of the last successful publication and printsChanged: <reasons>orUnchanged: nothing to publish. In GitHub Actions it also sets thechangedandreasonsoutputs.--forcealways rebuilds.build --sources plan.jsondownloads exactly the planned commits and never resolves a ref again, so the commit that was checked is the commit that is built, even if a branch has moved on in the meantime.A book that does not build
An included book that fails (a broken link, a missing file, an invalid
idorslug) does not stop the build of the others. Each included book is built on its own first, and then:--baseline plan.json(the plan of the last successful publication), the engine uses the book's last good commit instead.sources --sources plan.json --baseline baseline/plan.jsondownloads it in advance, because the later steps have no credentials.--sourcesis updated with what was really built (usedper source), so the next run knows which commits are good. A book that is left out hasused: null. The change detection is not affected.publish: truewas removed is left out; it does not fall back to an older, approved version.