CLI reference
Command-line interface for Gutterpress — markdown to print-ready PDF.
The CLI is for power users who want to script builds, run in CI, batch-process projects, or work outside the desktop app. If you just want to write a book and export a PDF, use the desktop app instead.
Install
Standalone binary (no Node, no Bun required)
Download for your platform from the latest release:
| Platform | Binary |
|---|---|
| Linux x64 | gutterpress-cli-linux-x64 |
| Linux ARM64 | gutterpress-cli-linux-arm64 |
| macOS Apple Silicon | gutterpress-cli-macos-arm64 |
| macOS Intel | gutterpress-cli-macos-x64 |
| Windows x64 | gutterpress-cli-windows-x64.exe |
Move the binary somewhere on your PATH, mark it executable (chmod +x), and you're done.
Every new GitHub release includes SHA256SUMS.txt. Verify the hash for your
download before running it, especially when bypassing Gatekeeper or
SmartScreen. See the installation guide for
commands and the complete supported-platform matrix.
From Homebrew (macOS and Linux)
brew tap dimm-city/gutterpress https://github.com/dimm-city/gutterpress.git
brew install dimm-city/gutterpress/gutterpress
From Scoop (Windows x64)
scoop bucket add gutterpress https://github.com/dimm-city/gutterpress.git
scoop install gutterpress/gutterpress
From npm
npm install -g gutterpress
Node.js 22 or newer is required for the npm install.
Installing with an npm git URL is intentionally unsupported. This repository
is a Bun monorepo, its generated dist/ is not committed, and the repository
root is not the published CLI package. Use one of the installs above, or clone
the repository and run bun install when contributing to Gutterpress itself.
System requirements
The CLI needs a Chromium-based browser for PDF generation, and a few external tools for PDF post-processing and validation depending on which features you use. See User Guide: Chapter 7 — System Setup for the full per-feature requirements matrix.
The short version: CLI PDF rendering needs a Chromium-based browser. Optional PDF/X output additionally needs Ghostscript and qpdf; the desktop app uses its bundled browser for standard PDF export.
Quick start
# Scaffold a new project (manifest + starter chapter + stylesheet)
gutterpress new "My First Book" --preset dtrpg
# Build a PDF from a project directory
gutterpress build ./my-book
# Live native-engine preview (automatic updates over WebSocket)
gutterpress preview ./my-book
# Custom output path
gutterpress build ./my-book --out dist/my-book.pdf
# Print-ready PDF/X (CMYK + ICC profile, validation enabled)
gutterpress build ./my-book --format pdfx --icc path/to/profile.icc
# HTML output (a self-contained directory with book.html + assets)
gutterpress build ./my-book --format html --out dist/my-book/
Project layout
A Gutterpress project is a directory. The CLI doesn't impose much structure; the most common shape is:
my-book/
├─ manifest.yaml ← optional but recommended; metadata + config
├─ chapter-01.md ← markdown files, processed in alphabetical order
├─ chapter-02.md (or in the order listed in manifest.yaml#source.files)
├─ css/ ← your stylesheets
│ └─ print.css
└─ images/ ← images referenced from markdown or CSS
The CLI discovers assets from what the book actually references — there is no
directory list to keep in sync. Fonts are no exception: a font can live
anywhere in the project; @font-face { src: url(...) } in your CSS resolves
relative to that CSS file, wherever it is, and the build embeds it
automatically. Images referenced from markdown or HTML must live inside the
project folder (they keep their own relative path in the output); images
referenced only from CSS may live anywhere the CSS can reach.
See User Guide: Chapter 1 — Getting Started for a full first-project walkthrough and examples/ for working starters.
Manifest
manifest.yaml is where you control everything that isn't authored in markdown — book title, the page-size preset, custom styles, extensions (looks and plugins), validation rules, PDF/X configuration. It is the only recognized project manifest filename. The schema lives in docs/schema-autocomplete.md for YAML autocomplete in editors.
Minimal example:
title: "My Book"
authors:
- "Your Name Here"
# Pick a page-size preset or supply page.width / page.height yourself
preset: dtrpg
styles:
- css/print.css
source:
files:
- chapter-01.md
- chapter-02.md
The full configuration cascade is CLI flags > manifest.yaml > preset defaults. See the configuration reference for details.
Commands
Gutterpress has 8 subcommands. new, preview, build, and publish are the
primary author commands; validate and preflight are CI / advanced
checks; doctor reports system readiness; and ext manages the
project's extensions (plugins, looks, component libraries). Every
command also accepts --help for the authoritative, always-current flag list
(gutterpress <command> --help) — this section is regenerated from the same
source.
gutterpress new
Scaffold a new book, plugin or theme from an embedded starter template — the fastest way to start (see Quick start).
--kind book is the default. Every new book picks the vendor preset it's designed for: dtrpg (DriveThruRPG print-on-demand), book (neutral 6x9in trade book), or custom (you supply the trim size in points).
--kind plugin and --kind theme scaffold an extension package instead — a folder with a package.json a book can load. The plugin starter carries a declarative marker table, a hand-written markdown-it rule, component CSS and a bun test fixture suite; the theme starter carries the six-file layered CSS architecture (tokens / base / components / page-templates / page-rules / book), each sheet opening with its own OWNS / MUST NOT CONTAIN contract header. Both include a README explaining which conventions are load-bearing. An extension needs no preset, trim size or publish target, so the book-only flags below are rejected rather than ignored when --kind names one — and --prefix/--description are likewise rejected for a book.
gutterpress new <name> [--kind <id>] [options]
--kind <id> What to create: book (default), plugin, theme
--prefix <str> Class/custom-property prefix an extension claims (default: its slug, e.g. "field-notes-"); --kind plugin|theme only
--description <text> One-line description recorded in the extension's metadata; --kind plugin|theme only
--preset <id> Vendor preset the book is designed for: dtrpg, book, custom (required for a book)
--author <name> Author name to record in the project
--dir <path> Parent directory to create the project in (default: current directory)
--folder <name> Folder name to create (default: a slug of the project name)
--template <id> Starter template: book, zine, technical (default: book)
--targets <ids> Publish targets recorded in the manifest (comma-separated: dtrpg, itch; or "none") — default: the preset's
--page-width <pt> Trim width in points, 72pt = 1in (required with --preset custom; optional override otherwise)
--page-height <pt> Trim height in points, 72pt = 1in (required with --preset custom; optional override otherwise)
--page-tolerance <pt> Allowed trim deviation when validating a built PDF (default: 0.5)
--git Initialise local version history (default: true; use --no-git to skip)
--no-git
gutterpress preview
Live HTML preview server by default. Every change — a single Markdown edit,
CSS, manifest, multi-file, deletion, or other structural change — reloads the
full document over WebSocket. This path is pure JS and
needs no external tools. Pass --format pdf or --format pdfx for a one-shot
build-and-open instead. --manifest applies only to those one-shot PDF/PDF-X
modes; live HTML preview discovers the project manifest from its input
directory.
Before it loads plugins, preview downloads any pinned npm extension whose
copy is missing (see Restoring pinned extensions).
If that fails it warns and previews anyway; the one-shot PDF modes fail fast.
gutterpress preview [input-dir] [options]
--format <fmt> html (default, live HMR) | pdf | pdfx
--port <n> Bind port (default: 3579, html only)
--host <h> Bind host (default: 127.0.0.1). Pass 0.0.0.0 to expose on the LAN.
--no-watch Disable file watching (html only)
--open Automatically open browser (default: true; use --no-open to skip)
--no-open
--verbose Enable verbose output
--debug Debug mode (preserve temporary files)
--out <dir> Output directory (pdf|pdfx only)
--pdfx-flavor <flavor> PDF/X flavor: x1a | x3 (pdfx only)
--icc <path> Path to ICC profile (required for --format pdfx)
--manifest <path> Path to manifest.yaml (pdf|pdfx only)
--strip-annotations Strip PDF annotations for PDF/X compliance (pdfx only)
--skip-lint Skip the CSS print-safety check (pdf|pdfx only)
--skip-pre-validate Skip pre-build validation (pdf|pdfx only)
--skip-post-validate Skip post-build PDF/X validation (pdfx only)
--allow-shrink Build anyway when content is wider than the page content box (pdf|pdfx only)
gutterpress build
Build a PDF (default) or HTML output. Pipeline: validate:pre → convert → assets → build → validate:post. The CSS print-safety check (remote urls, risky print effects, page-containment) runs once, inside validate:pre, as the source.stylelint check — there is no separate lint phase.
Before it loads plugins, build downloads any pinned npm extension whose copy is missing — a fresh clone has the pins but not the files — and prints one Downloaded name@version (pinned in manifest.yaml) line per package. If a download fails, the build stops and names the extension, why, and how to retry. See Restoring pinned extensions.
gutterpress build [input-dir] [options]
--format <fmt> pdf | pdfx | html (default: pdf)
--out <path> Output file or directory. For pdf|pdfx, --out may also be a .pdf file path.
--title <title> Override manifest title
--pdfx-flavor <flavor> PDF/X flavor: x1a | x3 (--format pdfx only)
--icc <path> Path to ICC profile (required for --format pdfx)
--manifest <path> Path to manifest.yaml
--strip-annotations Strip PDF annotations for PDF/X compliance
--skip-lint Skip the CSS print-safety check (default: it runs for pdf/pdfx)
--skip-pre-validate Skip pre-build validation
--skip-post-validate Skip post-build PDF/X validation
--allow-shrink Build anyway when content is wider than the page content box. Chromium then scales the WHOLE book down to fit it — the build reports that whole-document scale (e.g. "about 0.72x its declared size") plus every offender, as warnings.
A --out <dir> is shared between formats safely: each build delivers only
what its own format produces, so it never disturbs another format's output
already sitting in that folder. --format html writes book.html (with the
viewer bundle), index.html, and referenced assets. --format pdf/pdfx
writes only its own PDF (e.g. my-book-pdf.pdf). This is what makes the
two-command sequence below safe:
gutterpress build --format html --out ./_site
gutterpress build --format pdf --out ./_site
./_site ends up with the paginating book.html from the first command
plus the PDF from the second — the pdf build never overwrites book.html.
gutterpress publish
Push a built PDF/HTML artifact to a publishing platform (itch.io, DriveThruRPG, Amazon KDP, Azure Static Web Apps, Shopify, Google Drive) or copy it to a local folder (local, the desktop's default first destination), headlessly and CI-safely. Credentials live in a 0600 user-config store (never in the project); provider env vars override it for CI. Most providers connect with a pasted API key; Google Drive connects through your browser instead (--connect opens the sign-in page — nothing to paste).
gutterpress publish [project] [options]
--provider <id> local | itch | drivethrurpg | kdp | azure-swa | shopify | gdrive
--list List providers and connection status
--connect Store an API key for --provider (from --token, the provider's env var, or piped stdin) — or, for gdrive, open the browser to connect
--disconnect Forget the stored key for --provider
--account <label> Named-credential label for --connect/--disconnect (keep several accounts per provider); omit for the default
--token <key> API key for --connect (prefer stdin/env var to keep it out of shell history)
--file <path> Artifact to publish (PDF path, or HTML export dir). Default: the manifest's output location
--manifest <path> Path to manifest.yaml
--dry-run Preflight only; don't contact the platform
--json Machine-readable JSON output (CI)
--open Open the result page / guided upload page in the browser
# List providers and connection status
gutterpress publish --list
# Store an API key for itch.io, then publish
gutterpress publish --provider itch --connect
gutterpress publish --provider itch ./my-book
# Google Drive connects via your browser, not a pasted key
gutterpress publish --provider gdrive --connect
gutterpress publish --provider gdrive ./my-book
gutterpress validate
Run the validation pipeline (pre-build source checks and/or post-build PDF checks). Tools that aren't installed are skipped with a warning — they don't fail the run. See User Guide: Chapter 6 — Validation for the full check list and User Guide: Chapter 7 — System Setup for which external tools each check needs.
The positional directory and --pdf/--input are independent: the positional (or --input) sets the pre-build source directory, --pdf separately points at a built PDF for post-build checks. --input overrides the positional if both are given. When a source directory is given, missing pinned npm extensions are downloaded first, as for build (a failed download exits 3 with the reason). This holds for preflight too. The Downloaded … lines go to stderr, so --format json output stays parseable.
gutterpress validate [dir] [options]
--pdf <path> Path to the PDF file to validate (post-build checks)
--input <dir> Source directory for pre-build checks (overrides the positional directory)
--manifest <path> Path to manifest.yaml
--category <c> Comma-separated categories: source, pdf, asset, heuristic
--only <ids> Run only these check IDs/selectors (comma-separated)
--skip <ids> Skip these check IDs/selectors (comma-separated)
--format <fmt> text (default) | json
--phase <p> pre | post | all | pre-build | post-build (default: all)
--target <t> Publish targets to validate against (comma-separated, e.g. dtrpg,itch), overriding the manifest's `targets:`
--fix Rewrite the source markdown in place with markdownlint's auto-fixes (source.markdownlint only)
--fix is the only thing validation ever writes, and only when you ask for
it: it applies markdownlint's own auto-fixes to the markdown, prints every
file it rewrote, and still reports whatever cannot be fixed mechanically. It
uses the same .markdownlint.* config the source.markdownlint check uses,
and does nothing when no config is found. A file with uncommitted changes is
rewritten too — you get a notice, not a refusal.
It writes only when source.markdownlint is actually part of the run, so
--skip source.markdownlint, an --only that names other checks, or a
--phase/--category that filters the source checks out all leave your
markdown untouched — --fix can never rewrite a file for a check the report
does not mention.
Two narrowed runs replace the former lint and audit commands (removed in
0.11.10 — each was a thin alias over this same pipeline):
# CSS print-safety only — remote url(), rasterizing effects, page containment
# (the check `gutterpress lint <dir>` used to run; findings list file and line:col)
gutterpress validate my-book --only source.stylelint
# Asset checks only — image DPI / format / color space, fonts
# (what `gutterpress audit <dir>` used to run)
gutterpress validate my-book --category asset --phase pre
gutterpress preflight
Run a deterministic print preflight against an already-built PDF and write a GO/FIX/NO-GO report (JSON + Markdown) — the automatable gate for CI before handing a PDF to a printer.
gutterpress preflight [dir] --pdf <path> [options]
--pdf <path> Path to the PDF file to preflight (required)
--input <dir> Optional source directory for pre-build checks (overrides the positional directory)
--manifest <path> Path to manifest.yaml
--target <t> Publish targets to preflight against (comma-separated, e.g. dtrpg,itch), overriding the manifest's `targets:`
--report-dir <dir> Output directory for preflight reports (default: alongside the PDF)
--name <name> Base filename for report outputs
Exits 1 when the computed status is NO-GO (errors, or a required check skipped/failed).
gutterpress doctor
Report the Gutterpress version, platform and config paths, and whether each external tool is available. Missing tools include the features that use them and platform-specific installation guidance.
gutterpress doctor
gutterpress ext
List, add, remove, enable, or disable the project's extensions. Markdown-it
plugins, looks (stylesheets) and component libraries are all extensions — one
extensions: list in manifest.yaml, in load order (see
Extensions below). These are the same shared-lib functions the
desktop app's Look and Features views call, so an extension added from the
terminal is the same entry the GUI shows.
gutterpress ext
--help Show ext subcommands (list, add, remove, enable, disable, search)
Every subcommand takes the project directory as an optional trailing positional (default: the current directory).
gutterpress ext list
List the project's extensions in load (= cascade) order: each specifier as written, whether it is bundled, a path, or an npm package, what it carries (markdown, styles, snippets, components), and any warning — not installed, not found, not pinned.
gutterpress ext list ./my-book
gutterpress ext add
Add an extension. What SOURCE is decides what happens:
- an npm package (
nameorname@version) is downloaded straight from the registry along with its runtime dependencies, hash-verified, vendored into the project underplugins/npm/, load-tested, and written back pinned asname@<exact version>. This does not invoke npm, Bun, Node.js tooling, or package install scripts; - a bundled feature (
markdown-it-mark,markdown-it-sub,markdown-it-sup,markdown-it-abbr,gutterpress-gfm-alerts) is simply listed — nothing to install, works offline; - a folder or plugin-file path is load-tested and listed as a manifest-relative path, referenced in place — never copied;
- a
.zipor.cssfile, or an http(s) URL, is validated (every declared sheet must exist and parse; print-safety findings are warnings) and landed inextensions/<id>/, then listed as./extensions/<id>; - with
--look,SOURCEis a built-in look id, copied intoextensions/<id>/as the author's own editable files and listed.
Adding something already listed re-pins or updates that entry instead of adding a second one.
An npm install also makes sure the book's .gitignore ignores plugins/npm/
(append-only; an author's own !plugins/npm/ re-include is respected and the
install warns that downloaded extensions shouldn't be committed). The manifest
pin is what travels with the book; the downloaded copy does not.
Restoring pinned extensions
A fresh clone has manifest.yaml's name@version pins but not the downloaded
copies under plugins/npm/. build, validate, preflight and preview
download any missing (or incomplete) pinned version before they load plugins —
exactly the pinned version, through the same registry-resolved, hash-verified,
load-tested install as ext add, without touching the manifest. Builds and
checks do it inside the shared plugin-loading step, so every build and export
(including the desktop's) and every check run does it, and fails with the
extension, the reason and how to retry when it cannot. Nothing is downloaded,
and the network is not used, when every copy is present; unpinned names, local
paths and bundled features are never touched. The plugin loader itself stays
offline. The desktop app does the same when it opens a book.
Once a package's pinned version is installed (by ext add or a restore), its
other downloaded versions under plugins/npm/<name>/ are deleted — a cache
that a pulled pin or branch switch would otherwise leave to pile up — except a
version another enabled manifest entry still pins. A failed install removes the
folders it created and nothing else.
gutterpress ext add <source> [dir] [options]
--export <name> Named module export to use as the plugin function (npm and path extensions only)
--look Treat SOURCE as a built-in look id (clean-book, zine, technical-doc): copy it into extensions/ and add it
gutterpress ext add markdown-it-highlightjs ./my-book
gutterpress ext add markdown-it-highlightjs@4.3.0 ./my-book
gutterpress ext add markdown-it-emoji@3.0.0 ./my-book --export full
gutterpress ext add markdown-it-mark ./my-book
gutterpress ext add ./plugins/field-notes ./my-book
gutterpress ext add zine ./my-book --look
gutterpress ext add ./parchment.zip ./my-book
gutterpress ext add https://example.com/looks/cool/ ./my-book
gutterpress ext remove
Remove an extension from the manifest, by the specifier as written there (for
an npm package the bare name is enough). An npm extension's vendored copy
under plugins/npm/ is deleted too; a path extension's folder is yours and is
never touched.
gutterpress ext remove markdown-it-highlightjs ./my-book
gutterpress ext remove ./extensions/zine ./my-book
gutterpress ext enable / gutterpress ext disable
Turn a configured extension off without removing it (disable writes
enabled: false on the entry, so the toggle is reversible), or back on.
gutterpress ext disable markdown-it-mark ./my-book
gutterpress ext enable markdown-it-mark ./my-book
gutterpress ext search
Search npm for extensions — the same list the desktop app's Features view
shows under "Find more on npm." Not project-scoped (no dir argument): it
queries the registry for packages tagged gutterpress (Gutterpress
extensions: plugins, looks, component libraries) or markdown-it-plugin (the
markdown-it ecosystem's own tag — those work in Gutterpress unchanged), and
prints each match's name@version, which kind it is, and its description,
ending with the ext add command to install it.
gutterpress ext search [query]
gutterpress ext search
gutterpress ext search footnote
An empty or omitted query lists the most relevant tagged packages. To
publish an extension, npm publish it with "gutterpress" in its
keywords — there is no index to be added to and nothing to register. Set
GUTTERPRESS_NPM_REGISTRY to point at a different registry (http/https only)
— useful for a private mirror, or for testing; the installer uses the same
setting, and only accepts tarballs from that registry's own origin.
Exit codes
Every command follows the same exit-code contract, so CI can branch on the result without parsing output:
| Code | Meaning |
|---|---|
0 |
Clean — no findings, nothing to fix. |
1 |
Findings — the command ran fine but reported findings/validation failures (validate/preflight findings, a build quality-gate rejection). |
2 |
Usage — the invocation itself was wrong: a bad flag, positional argument, preset, or value. |
3 |
Pipeline — the build/render/export pipeline itself failed for a reason unrelated to usage or findings (I/O error, missing tool, renderer crash). |
This applies uniformly across build, preview, validate, preflight, publish, ext, new, and doctor.
Extensions
Gutterpress uses markdown-it under the hood, so pure-JavaScript plugins that follow the (md, options) => void signature work without a Gutterpress-specific API. Plugins, looks (stylesheets) and component libraries are all extensions: one extensions: list in manifest.yaml, in load order. Every entry is a bare specifier, and its form says what it is:
extensions:
# a feature bundled with Gutterpress — nothing to install, works offline
- markdown-it-mark
# a folder or plugin file, relative to manifest.yaml — referenced in place
- ./extensions/clean-book
- ./plugins/my-custom-plugin.js
# an npm package, pinned to the exact version `gutterpress ext add` installed
- markdown-it-highlightjs@4.3.0
# the object form, only when an entry needs more than its specifier
- use: markdown-it-emoji@3.0.0
export: full # the plugin function is a named export
- use: markdown-it-anchor@9.2.0
options:
level: 2
- use: ./plugins/drafts.js
enabled: false # keep the entry, skip loading it
An extension folder (or npm package) describes itself in its package.json — there is no second, Gutterpress-specific manifest file. npm's own fields are read as-is, and everything Gutterpress needs sits under one optional "gutterpress" key:
{
"name": "field-notes",
"description": "Margin notes and term boxes",
"author": "You",
"keywords": ["gutterpress", "markdown-it-plugin"],
"main": "plugin.js",
"gutterpress": {
"styles": ["styles/plugin.css"],
"snippets": "snippets",
"components": "components.yaml",
"tokensFile": "styles/tokens.css"
}
}
main is the markdown-it plugin — npm's own convention — so a plain markdown-it plugin package needs nothing else at all. A look needs only gutterpress.styles (an ordered list, relative to the folder); a component library carries both. gutterpress.markdown exists for the one case main can't express: a package whose main is not the plugin. Folders still carrying the removed gutterpress.json or theme.json fail to load with a message showing the package.json that replaces them.
Order is load order: a later entry's markdown runs after earlier entries' (and sees their output) and its CSS wins ties — each extension's stylesheets are wrapped in their own cascade layer (@layer ext.<name>), declared in list order, so this holds however an extension writes its CSS; the project's own styles: stay unlayered and load after every extension, beating all of them at any specificity. There is no priority and no path:/name: wrapper — a manifest still carrying plugins: fails with a message that prints the same entries rewritten as extensions:. The engine: and engineStyles: keys are gone too (there is one engine; move any engineStyles entries to the end of styles:).
Pinned npm packages and their runtime dependencies live under plugins/npm/
as a plain nested node_modules tree, which Node's own module resolution loads.
The pin travels with the project; the downloaded copy is gitignored, and
build, validate, preflight and preview download a missing pinned version first
(nothing is fetched when every copy is present). Each tarball's integrity is
checked against the registry's hash when it is installed. Install/build scripts, native addon compilation, bundled
node_modules, and non-registry dependency selectors are intentionally
unsupported. Only install packages you trust: extensions run unsandboxed with
the process's full filesystem and network privileges.
Use the entry's export field, or ext add --export <name>, for packages
that expose a named plugin function instead of a default export.
A plugin's declared markers (export const markers) are its components. Each
one's example snippet — snippets/<marker>.md by default, or the marker's own
snippet: path — is what the desktop editor inserts for it, and an optional
validate(component) function on the marker checks what authors put inside;
its problems appear in gutterpress validate and the desktop Problems panel.
See User Guide: Chapter 5 — Plugins for the full list contract and for authoring custom plugins, and Chapter 4 — Styling & Theming for looks.
CI / scripting
The standalone binary is the easiest way — drop it in a GitHub Actions step and you're done:
- name: Build PDF
run: |
curl -L -o gutterpress \
https://github.com/dimm-city/gutterpress/releases/latest/download/gutterpress-cli-linux-x64
chmod +x gutterpress
sudo apt-get install -y google-chrome-stable ghostscript
./gutterpress build ./my-book --out dist/my-book.pdf
The binary is self-contained except for the system tools described in User Guide: Chapter 7 — System Setup. On a runner with Chrome and Ghostscript present, you don't need a separate Node or Bun install.
Troubleshooting
Ghostscript executable not found— Ghostscript is required only for PDF/X and ink-coverage checks. Standard Windows installs are auto-detected; for a non-standard install, setGHOSTSCRIPT_PATHto the full path ofgs,gswin64c.exe, orgswin32c.exe. See User Guide: Chapter 7 — System Setup.No Chrome or Chromium binary found— install a Chromium-based browser or setCHROMIUM_PATH=/path/to/chrome. The desktop app includes its own browser and needs no separate browser install.Tool "X" not found — skippingduring validate — that's the graceful path; the check requiresXand isn't available. Install the tool or accept the skip.- All validate checks skipped on Windows — was a bug pre-0.1.7 (used
which, which isn't on stock Windows); fixed to usewhere.exe.