CLI
Every Tangly command (init, dev, build, check, migrate, eject, add, preview) with flags, defaults, and examples.
~ 6 min read
The tangly binary is the primary surface for working on Tangly projects. Eight commands cover scaffolding, dev, build, validation, migration, ejection, and content scaffolding.
tangly --helpInstall
npm install --save-dev tanglyyarn add --dev tanglypnpm add --save-dev tanglybun add --dev tanglyOr install globally:
bun add -g tanglyStaying up to date
In an interactive terminal, tangly checks npm at most once every 12 hours and prints a one-line notice when a newer version is published:
⚠ Update available: tangly 0.1.5 → 0.1.6
Upgrade: `npm i -g tangly@latest` (or run `npx tangly` for the local copy)
The check is fail-silent (offline or slow registry: no notice) and never runs in CI or piped output. Opt out with TANGLY_NO_UPDATE_CHECK=1 or NO_UPDATE_NOTIFIER=1.
Every command also stamps the running version into its output, and tangly --version prints it directly, so you can always confirm which binary ran.
Common flags
Every command accepts these:
| Flag | Default | Description |
|---|---|---|
--root <dir> | . | Project root |
--config <path> | docs.json | Path to docs.json relative to --root |
The other flags vary per command.
init
Scaffold a new Tangly project. Two paths: pick a built-in template (interactive), or hand --from <dir> to ingest an existing folder of .md/.mdx files.
tangly init [dir] [--from <dir>] [--template <name>] [--name <name>]| Arg / flag | Type | Default | Description |
|---|---|---|---|
dir | positional | . | Target directory |
--from | string | — | Path to existing markdown folder. Walks the tree (folders → groups), synthesizes docs.json. Idempotent: re-runs merge new files into existing nav. |
--template | string | starter | Template name. Skip the interactive prompt. |
--name | string | — | Project name. Skip the interactive prompt. |
Examples
tangly init my-docs
tangly init . --from ../legacy-docs
tangly init --template starter --name "My Docs" my-docsdev
Start the dev server with HMR.
tangly dev [--port 4321] [--host] [--no-open] [--debug] [--tunnel]| Flag | Type | Default | Description |
|---|---|---|---|
--port | string | 4321 | Port |
--host | boolean | false | Bind 0.0.0.0 so other devices on the LAN can reach the dev server. Without this, only localhost/127.0.0.1 works. |
--open | boolean | true | Open browser on start. Use --no-open to suppress. |
--debug | boolean | false | Verbose Vite/Astro logging |
--tunnel | boolean | false | Expose via a cloudflared quick tunnel. Requires cloudflared on PATH. |
The dev server pre-validates your docs.json manifest before launching Astro. Schema errors surface immediately, not buried in a stack trace.
tangly dev --port 8080 --host --no-openbuild
Production build to dist/.
tangly build [--out ./dist] [--adapter <auto>] [--base /] [--site-url <url>] [--env <env>] [--analyze]| Flag | Type | Default | Description |
|---|---|---|---|
--out | string | ./dist | Output directory |
--adapter | vercel | cloudflare | node | static | (auto) | Auto-detected from project files: vercel.json → vercel, wrangler.toml/wrangler.jsonc → cloudflare, Dockerfile → node, else static. |
--base | string | / | Subpath. Pass --base /docs to deploy under /docs. Rewrites every internal link, asset URL, sitemap entry, llms.txt URL, and Pagefind result. |
--site-url | string | docs.json siteUrl | Absolute deploy URL. Overrides siteUrl for canonical, og:image, sitemap, and robots.txt. Also reads TANGLY_SITE_URL. |
--env | production | preview | (auto) | Deploy environment. preview emits robots: noindex and points canonical at the production domain. Also reads TANGLY_ENV. |
--analyze | boolean | false | Write a build-size report to dist/_tangly/. |
Site URL & environments
Canonical tags and og:image need an absolute URL, but the deploy host varies (production, staging, PR previews). Tangly resolves it per build, highest priority first:
--site-url/TANGLY_SITE_URL- Platform auto-detect — Vercel, Netlify, and Cloudflare Pages deploy URLs are read automatically
siteUrlindocs.json
og:image points at the current deploy (so the image resolves on a preview); canonical points at the production domain (so previews never compete in search). Non-production deploys (--env preview, or an auto-detected preview/branch context) also get <meta name="robots" content="noindex, nofollow">.
# Staging deploy: cards resolve at staging, canonical + sitemap stay on prod, noindex
tangly build --site-url https://staging.docs.example.com --env previewOn Vercel/Netlify this is zero-config — PR previews self-reference and go noindex automatically. Cloudflare Pages exposes no production signal, so set --env preview (or TANGLY_ENV=preview) on preview branches. In tangly dev, canonical/og:image use the live request origin so you can preview cards locally.
Output
dist/
├── index.html redirects to first nav page
├── introduction/index.html
├── guides/<slug>/index.html
├── images/ copied from project root
├── logo/
├── og/<slug>.png generated social cards
├── sitemap.xml
├── robots.txt
├── llms.txt
└── llms-full.txt
The build also generates a per-page <slug>.md file (markdown, no MDX) so AI agents can fetch a clean text version of any page.
Examples
tangly build
tangly build --adapter cloudflare --base /docs
tangly build --analyzecheck
Validate config, links, frontmatter, and MDX.
tangly check [--strict] [--no-links] [--json] [--include-drafts]| Flag | Type | Default | Description |
|---|---|---|---|
--strict | boolean | false | Warnings become errors (non-zero exit). Use this in CI. |
--no-links | boolean | false | Skip link checking |
--json | boolean | false | Machine-readable output |
--include-drafts | boolean | false | Include draft: true pages in checks |
tangly check
tangly check --strict
tangly check --json | jq '.errors'Exit code is 0 when there are no errors (or no errors+warnings under --strict), 1 otherwise.
MDX validation
Every page is parsed with the same MDX syntax configuration the build uses (the remark plugins that affect what parses as a JSX expression), so check passing predicts build passing for this class of failure:
- Syntax errors (unclosed JSX tags, malformed expressions, bad
import/export) are reported withfile:line:column. - Unbound expression identifiers are flagged before they become prerender
ReferenceErrors. The classic case is a literal placeholder in prose —{search_term_string}is valid MDX, compiles, and only explodes at render time:
✗ rules/schema/website-search.mdx:5:6 — ReferenceError at build: `search_term_string` is not defined
hint: MDX treats {…} as a JSX expression — wrap literal placeholders in backticks
The fix is usually to wrap the placeholder in backticks: `{search_term_string}`. Identifiers bound by the file’s import/export statements, expression-local declarations and arrow params, MDX-provided names (props, frontmatter, components), and JS globals are all recognized. Files under /snippets are never scanned — reusable snippets legitimately take bare {props}-style variables from the importing page.
migrate
Migrate a project to Tangly. Two paths:
- Legacy: project has
mint.json→ full conversion viaconvertMintToDocs. - Modern: project has
docs.json→ validate + update the$schemaURL.
tangly migrate [--yes] [--keep-source]| Flag | Type | Default | Description |
|---|---|---|---|
--yes | boolean | false | Skip confirmation prompts |
--keep-source | boolean | false | Keep mint.json after legacy migration. Without this flag, mint.json is renamed to mint.json.bak (or .bak.1, .bak.2, …). |
Examples
tangly migrate
tangly migrate --yes
tangly migrate --keep-sourceIf your theme: value isn’t a Tangly theme (a Mintlify alias like aspen or maple), migrate rewrites it to tang — the schema maps every alias to tang at parse time anyway, so the rewrite only makes the file say what it does. The notice lists the other Tangly themes if you’d rather pick one.
When docs.json has no siteUrl, migrate prompts for your production URL (used for canonical links and social cards). Press Enter to skip; --yes skips the prompt entirely.
eject
Materialize the synthesized Astro project into your repo. Irreversible.
tangly eject [--out ./.tangly] [--yes]| Flag | Type | Default | Description |
|---|---|---|---|
--out | string | ./.tangly | Eject destination |
--yes | boolean | false | Skip confirmation |
After eject:
./.tangly/contains a real Astro project (astro.config.mjs,src/, etc.)package.jsonadds raw Astro deps (astro,@astrojs/mdx,tailwindcss, …) and rewritesdev/build/previewscripts to callastrodirectly. Thetanglypackage is kept as a dep. The materializedastro.configstill importstangly/pluginfor the docs runtime, and theme components still import from@tanglydocs/theme-ui.
You manage astro.config.mjs and integrations from then on.
tangly eject --out ./astro-site --yesadd
Scaffold a new page, snippet, or changelog entry.
tangly add <type> <path> [--template <name>] [--no-nav]| Arg / flag | Type | Default | Description |
|---|---|---|---|
type | positional | — | page | snippet | changelog |
path | positional | — | Slug or filename. e.g. guides/billing, shared/disclaimer, 1.2.0 |
--template | string | — | Template name from ./templates/ |
--no-nav | boolean | false | Don’t auto-insert into docs.json navigation |
Page
Writes <path>.mdx and inserts the slug into the last navigation.groups (or navigation.pages) entry in docs.json.
tangly add page guides/billingSnippet
Writes snippets/<path>.mdx. Snippets aren’t inserted into nav (they’re not pages).
tangly add snippet shared/disclaimerChangelog
Writes changelog/<path>.mdx with an <Update> block ready to fill in. Date is today; version is parsed from the slug if it looks semver-shaped.
tangly add changelog 1.2.0preview
Serve the built dist/ locally (Astro’s static preview server).
tangly preview [--port 4321] [--out ./dist]| Flag | Type | Default | Description |
|---|---|---|---|
--port | string | 4321 | Port |
--out | string | ./dist | Output directory to serve |
Use this to verify the production build before deploying.
tangly build && tangly previewSource
packages/tangly/src/cli/commands/- Each command’s source:
init.ts,dev.ts,build.ts,check.ts,migrate.ts,eject.ts,add.ts,preview.ts