Skip to main content

blume-migrate

Migrate an existing documentation site (Mintlify, Docusaurus, Fumadocs, Nextra, Starlight, VitePress, VuePress, Docus, MkDocs, mdBook, Fern, GitBook, ReadMe, Redocly, Docsify, Jekyll (Just the Docs), GitHub Wiki, or any docs framework) to Blume, the markdown-first docs framework on Astro. Translate the source config to blume.config.ts, restructure content into Blume's filesystem-derived navigation, rewrite JSX callouts to directives, convert icons to Lucide, and inline snippets. Use when the user asks to migrate/convert/port a docs repo to Blume, or when the repo has a docs.json/mint.json, docusaurus.config.*, meta.json with fumadocs, _meta.* with nextra, an astro.config.* with starlight(), a .vitepress/config.* or .vuepress/config.*, an mkdocs.yml or zensical.toml, a book.toml (mdBook), a fern/docs.yml, a GitBook .gitbook.yaml/gitbook-docs.yaml, ReadMe _order.yaml files in docs/ or reference/, a Redocly sidebars.yaml or @redocly/realm dependency, an index.html that sets window.$docsify, a docus or @nuxt-them

Source facts

Repository
middleapi/orpc
Last source activity
October 9, 2026 at 01:58
Detected SKILL.md language
English
Stars
5,689
Forks
172

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
32 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
blume-migrate
description
Migrate an existing documentation site (Mintlify, Docusaurus, Fumadocs, Nextra, Starlight, VitePress, VuePress, Docus, MkDocs, mdBook, Fern, GitBook, ReadMe, Redocly, Docsify, Jekyll (Just the Docs), GitHub Wiki, or any docs framework) to Blume, the markdown-first docs framework on Astro. Translate the source config to blume.config.ts, restructure content into Blume's filesystem-derived navigation, rewrite JSX callouts to directives, convert icons to Lucide, and inline snippets. Use when the user asks to migrate/convert/port a docs repo to Blume, or when the repo has a docs.json/mint.json, docusaurus.config.*, meta.json with fumadocs, _meta.* with nextra, an astro.config.* with starlight(), a .vitepress/config.* or .vuepress/config.*, an mkdocs.yml or zensical.toml, a book.toml (mdBook), a fern/docs.yml, a GitBook .gitbook.yaml/gitbook-docs.yaml, ReadMe _order.yaml files in docs/ or reference/, a Redocly sidebars.yaml or @redocly/realm dependency, an index.html that sets window.$docsify, a docus or @nuxt-themes/docus dependency, a Jekyll _config.yml (Just the Docs theme), or a GitHub wiki clone (Home.md with _Sidebar.md, [[Page Name]] links).
# Migrate to Blume Blume is a **markdown-first** documentation framework on Astro/Vite. You drop Markdown/MDX into a folder and get navigation, search, theming, Open Graph images, and a component library with no app boilerplate — **the framework is the template**. There is no starter to clone; the only thing a project owns is its content and a `blume.config.ts`. Your job is to convert a source docs repo into an **idiomatic** Blume project — not a 1:1 transliteration. Read this file, detect the source framework, open the matching `references/<framework>.md` for the exact mappings, and work the loop below. Report everything you drop or approximate. Throughout this skill (including the `references/` files), **`<skill>` means the absolute path of the directory containing this SKILL.md** — resolve it from wherever you read this file (e.g. `node_modules/blume/skills/blume-migrate` or `.claude/skills/blume-migrate`). It is a placeholder to substitute, never a literal path. ## Migration philosophy - **Target idiomatic Blume, not a mechanical port.** Prefer filesystem-derived navigation over an exhaustive explicit `navigation.sidebar`. Prefer `:::` directives over JSX callouts. Prefer Blume defaults over restating them in config. - **Every field has a default; `{}` is a valid config.** Map only what the source _declares_. If the source uses a framework default, don't write it. - **Drop chrome that has no Blume equivalent — and say so.** Navbar CTAs, custom theming, conditional redirects, and unmappable icons get reported to the user, not silently discarded or faked. - **Convert, don't preserve.** Blume's page frontmatter schema is **strict** — unknown keys are build errors. A source-only frontmatter key must be mapped to a Blume key or removed (and reported), never left to "maybe validate." ## Migration workflow 1. **Detect the source framework** and read its reference file: - `docs.json` / `mint.json` → **Mintlify** (`references/mintlify.md`) — the deepest, config-declared nav. - `docusaurus.config.*` → **Docusaurus** (`references/docusaurus.md`). - `meta.json` + `fumadocs-*` deps (content under `content/docs/`) → **Fumadocs** (`references/fumadocs.md`). - `_meta.{js,ts,json}` + `nextra` deps → **Nextra** (`references/nextra.md`). - `astro.config.*` calling `starlight({…})` → **Starlight** (`references/starlight.md`). - `.vitepress/config.{js,ts,mjs,mts}` (often `docs/.vitepress/`) or a `vitepress` dependency → **VitePress** (`references/vitepress.md`). `.vuepress/` is VuePress (next bullet). - `.vuepress/config.{js,ts,mjs}` (v1 also `config.yml`/`config.toml`; often `docs/.vuepress/`), a `vuepress.config.*`, or a `vuepress` dependency → **VuePress** (`references/vuepress.md`). It builds on `references/vitepress.md` for the Markdown layer the two share, so read both. - A `docus` dependency (often in `docs/package.json` beside a `nuxt.config.ts` with `extends: ['docus']`), or `@nuxt-themes/docus` for 1.x → **Docus** (`references/docus.md`). Pages are MDC, Nuxt Content's component syntax: `::note` … `::` is not a Blume directive, and Blume prints it as text (`BLUME_MDC_SYNTAX` warns at its line). - `mkdocs.yml`/`mkdocs.yaml` (also Zensical's `zensical.toml` and ProperDocs' `properdocs.yml`) → **MkDocs / Material for MkDocs** (`references/mkdocs.md`): nav declared in config, Python-Markdown extension syntax (`!!!` admonitions, `===` tabs, `--8<--` snippets), and Python deps, so usually no `package.json`. Run `node <skill>/scripts/mkdocs-codemod.mjs --write <content-dir>` first, then `pin-heading-ids.mjs` after the first build. - `fern/docs.yml` (beside `fern/fern.config.json`) → **Fern** (`references/fern.md`). A `fern/` folder without `docs.yml` only generates SDKs: the docs are elsewhere. - `.gitbook.yaml`/`.gitbook.yml`, `gitbook-docs.yaml`, or a `SUMMARY.md` beside a `.gitbook/` folder → **GitBook** (`references/gitbook.md`). `book.json` + `SUMMARY.md` is the legacy GitBook CLI or HonKit (same reference, its own section); `book.toml` + `src/SUMMARY.md` is mdBook (`references/mdbook.md`). - `book.toml` (at the book root, often `docs/`, `book/`, or `guide/` in a code repo; chapters in its `[book] src`, beside a `SUMMARY.md`) → **mdBook** (`references/mdbook.md`). Every URL ends in `.html`, `SUMMARY.md` is the whole nav, and `{{#include}}` pulls anchored code from across the repo: build the old book first, since it's the URL list, the old ids, and the only record of what the includes showed. - `sidebars.yaml` or an `@redocly/realm`-family dependency, usually beside a `redocly.yaml` and with Markdoc `{% … %}` tags in pages → **Redocly** (`references/redocly.md`). GitBook pages use `{% … %}` tags too, so check for GitBook's files first. A `redocly.yaml` holding only lint/bundle keys (`extends`, `rules`, `decorators`, `apis`) is Redocly CLI config, not a docs site: keep it and detect the framework from the other signals. - `_order.yaml` files in `docs/`, `reference/`, `recipes/`, or `custom_pages/` (ReadMe's bi-directional Git sync), or a CI step running `readmeio/rdme` beside pages with `category`/`parentDoc` (or `category.uri`/`parent.uri`) frontmatter (`rdme` uploads) → **ReadMe** (`references/readme.md`). ReadMe keeps settings, redirects, the glossary, and variables in its dashboard, not the repo, and changelogs only on the `main` branch. - An `index.html` setting `window.$docsify` (usually in `docs/`, beside `_sidebar.md`), or `docsify-cli` in `package.json` → **Docsify** (`references/docsify.md`). Run `node <skill>/scripts/docsify-codemod.mjs --write --snapshot .docsify-old --group-folders <docs-dir>` first, then `pin-heading-ids.mjs --old .docsify-old --map docsify-routes.json` after the first build. Its default URLs live after `#` (`/#/page`), which no server-side redirect can match; the reference adds a client-side script. - `_config.yml` (root or `docs/`) → **Jekyll** (`references/jekyll.md`); Just the Docs is `just-the-docs` in `_config.yml` or the `Gemfile`. Build the old site first with a project-local bundle: the nav comes from front matter (`parent`/`nav_order`) and is rebuilt from the old build's sidebar, and URLs end in `/` or `.html`. A `_toc.yml` beside it is Jupyter Book, not Jekyll. Run `node <skill>/scripts/jekyll-codemod.mjs --old <old build> --write .` from the Jekyll source dir first, then `pin-heading-ids.mjs --old <old build>` after the first build. - A clone of `<repo>.wiki.git` (`Home.md` at the root, often `_Sidebar.md` and `_Footer.md`, `[[Page Name]]` links, no config) → **GitHub Wiki** (`references/github-wiki.md`). Never detected: the source is named. Its old URLs stay on github.com, which can't redirect, so the reference writes a route table and link stubs for the old wiki instead of `redirects`. Run `node <skill>/scripts/github-wiki-codemod.mjs routes --repo <owner>/<repo> --write` first, classify `wiki-routes.json`, then `convert --repo <owner>/<repo> --write`. - Anything else → apply this file's mental model directly; there's no framework-specific reference, so inventory by hand. - **Also note the host repo, independent of source framework:** a pnpm/Turbo workspace, a non-`docs/` content layout, or a Vercel deploy each need integration steps (`content.root` scoping, `minimumReleaseAge`, lockfile, `vercel.json`, an Astro/Vite patch) — all in `references/monorepo.md`. Read it whenever the target isn't a bare single-package docs folder. 2. **Inventory the repo** before changing anything (a page whose body is only a `<meta http-equiv="refresh">` is a redirect, not a page: add the redirect from its old URL and report it): the config file(s), the content tree, the nav definition, snippets/partials/includes, static assets, OpenAPI/AsyncAPI specs and GraphQL schemas, redirects, i18n locales, custom components, and icon usage. Note what's declared vs. defaulted. Pages the old site published by accident (a `.github/` template, files under dot-folders, planning notes) aren't content: leave them out, add no redirects, and list them in the report. 3. **Write `blume.config.ts`** with `defineConfig` from `blume`. Map only declared fields (see the reference's mapping table); rely on defaults everywhere else. A minimal result is `defineConfig({ title: "…" })`. 4. **Restructure content.** Put `blume.config.ts` in the directory whose `package.json` runs the old docs build, which may be a workspace package such as `packages/docs` rather than the repo root. Choose `content.root` (default `docs`) — **detect where `.md`/`.mdx` actually live, don't assume a `docs/` folder.** Many repos keep content directly under an app dir (`apps/docs/api/`, `.../getting-started/`) with no `docs/` subfolder; when so, set `content.root` to that dir and scope `content.include` to the real content folders rather than leaving a bare `content.root: "."` that scans everything (see `references/monorepo.md` §1). Order with numeric prefixes (`01-intro.mdx`), group without a URL segment via `(group)/` folders, and add a `meta.ts` (`defineMeta`) only where filesystem order isn't enough. **A source that already declares per-folder navigation in a sidecar file — Fumadocs `meta.json`, Nextra `_meta.*` — _is_ that case: convert each one to a `meta.ts`, carrying over its title/icon/order/collapse, rather than dropping it and hoping filenames reproduce the intent. Filesystem inference is the fallback for folders that declare no per-folder nav, never a reason to discard one that does.** A group that exists only in the source's nav config, with its pages flat on disk, becomes a **`(group)/` folder**: it adds the sidebar group and keeps every URL, with no redirects (moving pages a folder deeper instead changes their URLs and breaks their relative asset paths). Reach for an explicit `navigation.sidebar` only when the source nav genuinely can't be expressed by files. **Reshaping into folder-per-tab moves URLs** — track every old→new path as you go; you'll turn them into `redirects` in step 5.
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub