Skip to main content

Command-line tool

Twain includes a command-line tool, twain-md, that checks and renders documents using the same engine as the app. It is handy in scripts and continuous integration, where you want to catch broken links or missing images before they ship.

Not yet published

The CLI is built but not yet published to npm. For now, run it from a checkout with node cli/twain-md.mjs …, or build a local package with npm pack in the cli/ folder and install that. It requires Node.js 18 or later. The examples below use twain-md as the command name for once it is published.

Commands

twain-md check <file...|dir> [--json] [--strict] [--component-map <name|path>] [--remote [--timeout <ms>] [--concurrency <n>]]
twain-md inventory <dir> [--json] [--component-map <name|path>]
twain-md render <file> [-o out.html] [--component-map <name|path>]
twain-md export <file> [-o out.html] [--profile <name|path>] [--component-map <name|path>]
twain-md open <file> [--changes] [--print]

check

check reports problems in one or more documents: unknown components, missing local images, broken local links, and (with --remote) unreachable remote links. By default it makes no network requests.

OptionEffect
--jsonOutput machine-readable JSON instead of text
--strictTreat informational findings (imports, expressions) as failures
--remoteAlso check remote http and https links and images over the network. It has no effect in project mode, when the argument is a directory
--timeout <ms>Per-request timeout for remote checks (default 5000)
--concurrency <n>How many remote checks to run at once (default 8)
--component-map <name|path>Use a framework map or a custom map file (see Component maps)

Findings are one of: import and expression (informational), and unknown component, missing image, broken link, remote image, and remote link (warnings). Project mode adds two more warnings: broken anchor, for a cross-file link to a heading that does not exist, and file too large, for a file over 4 MB that was inventoried but not analysed. The text output lists each file with its findings, line by line.

Exit codes:

CodeMeaning
0Clean, or only informational findings without --strict; also a successful render or export
1One or more failing findings
2A usage error, an unknown profile or component map, or a file that could not be read

Example:

twain-md check docs/**/*.md --strict
twain-md check guide.mdx --remote --timeout 3000

Give check a directory instead of files and it runs in project mode: it walks the folder for Markdown and MDX, adding the cross-file link graph and broken cross-file links and anchors. The walk skips hidden entries and the usual build and dependency folders (node_modules, .git, dist, build, and similar), goes at most ten levels deep, and stops after 5000 files, saying so when it does. A file larger than 4 MB is inventoried but not analysed, and is reported as a file too large warning, which on its own is enough to make check exit 1.

inventory

inventory walks a folder of Markdown and MDX and prints a structured picture of the whole set: per file its headings with their rendered anchor slugs, frontmatter, links and images with line numbers, MDX components, and task-list items; and across the project the link graph, orphaned files, and broken cross-file links and anchors. It is the CLI form of the MCP twain_md_project tool.

twain-md inventory docs/ # human-readable summary
twain-md inventory docs/ --json # the full structured inventory

render

render produces a single self-contained HTML page, with styling and local images embedded, and prints it to standard output (or to a file with -o):

twain-md render guide.mdx -o guide.html

This is close to the app's HTML export, with one difference: the CLI has no browser, so Mermaid diagrams stay as fenced code blocks instead of being drawn. KaTeX web fonts are not embedded in either export, so maths falls back to a system serif.

export

export is render with a profile that sets the theme, font, width, whether assets are embedded, and the title:

twain-md export guide.mdx --profile dark -o guide.html

The built-in profiles are default, dark, sepia, and print. You can also point --profile at your own JSON file, or keep named profiles in ~/.config/twain-md/profiles/<name>.json (under $XDG_CONFIG_HOME/twain-md/profiles/ if you set that variable). A profile understands these fields:

FieldValuesDefault
themeauto, light, dark, sepia, high-contrastauto
fontsans, serifsans
widthnarrow, normal, widenormal
embedAssetstrue, falsetrue
titleany textthe document's title, or the file path when it has none

open

open hands a file to the Twain app through its twain-md:// URL scheme, so a script or an editor can jump straight to a document. It only navigates: it never saves or changes anything, and the app re-validates the path it is given.

twain-md open guide.md # open it in the app, rendered
twain-md open guide.md --changes # open it with changes against the last save
twain-md open guide.md --print # print the URL and exit, without launching
OptionEffect
--changesOpen with changes marked against the last saved version
--printWrite the twain-md:// URL to standard output instead of launching the app

Launching needs macOS and the Twain app installed. On any other platform, open prints the URL to standard error and exits 2, while --print still works everywhere. On the Mac App Store edition the sandbox only lets the app open a file it has already been granted access to, so this works best for files inside a folder you have opened in Twain; the direct download has no such restriction. See Editions.