CLI tool
miantiao-me/bm.md avatar
miantiao-me/bm.md

bm.md: a Markdown formatter that targets WeChat public accounts first

更好用的 Markdown 排版助手|一键适配微信公众号、网页与图片。

619 stars74 forksTypeScriptLGPL-3.0

At a glance

What is it?
bm.md is a TypeScript Markdown editor and export pipeline built around one output channel: WeChat public account articles. It ships a web editor, a CLI named bmmd, a REST API and an MCP integration, under LGPL-3.0. The useful judgement is narrow: it is worth a look if WeChat is your publishing target, and largely redundant if it is not.
Who is it for?
Adopt bm.md if WeChat public accounts are a real publishing target and you want the formatting handled by a tool rather than by hand. Skip it if your output is a static site or a docs pipeline, where a Markdown-to-HTML step plus your own CSS already covers the job and the 16 style presets are noise.
Can I use it commercially?
Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The specific problem: WeChat will not accept your Markdown

WeChat public accounts do not render Markdown. An author writes in Markdown, then has to convert it into inline-styled HTML that survives WeChat's editor, which strips or ignores much of what a normal stylesheet would provide. The common workaround is a manual pass: paste the converted HTML, fix the spacing, re-apply code block styling, re-check that images still load from a host WeChat will accept. Repeat for every article. bm.md exists to collapse that pass into one step. The README describes the project as a Markdown formatting assistant with WeChat public account adaptation, and the CLI example makes the intent explicit: bmmd render article.md --platform wechat --output article.html. The audience is therefore narrow and identifiable. It is people who publish long-form Chinese content to WeChat and who already write in Markdown. Engineers who never touch WeChat get much less from the project, because the platform flag is the part that carries the domain knowledge.

What the editor actually does between input and output

The editing surface is CodeMirror 6, and the README calls the experience live preview. Alongside the editor sits a style layer: 16 typography presets, described as ranging from paper-style reading to retro and from dark editing to activist poster, with a gallery modal that tiles the presets for preview and one-click switching. Code highlighting is separate, with 14 code themes across light and dark. Two diagram paths are listed, Mermaid and AntV Infographic, which means the pipeline has to handle fenced blocks that are not ordinary code before producing final output. Export targets are HTML, JPEG download, PNG copy, paginated PDF and direct print. There is also an import direction: Markdown, HTML, and several office and document formats converted to Markdown, including Office, OpenDocument, text-extractable PDF, RTF, CSV and EPUB. The architecture documentation is linked in the README rather than reproduced in it, so the internal module boundaries are not visible from the material here. What is visible is the shape: one core Markdown processing path, exposed through several front ends, with platform-specific formatting applied at the end.

Running it locally, and the environment variables that matter

The prerequisites are stated plainly: Node.js >= 20 and pnpm 11.11.0. The setup is the standard three commands. Clone the repository, run pnpm install, then pnpm dev, and the README says to open http://localhost:2663. A production build and preview use pnpm build followed by pnpm preview. Environment variables are all optional according to the README, and the reference file is .env.example. Two are client-visible: VITE_APP_URL and VITE_API_URL. Two are read on the server for analytics: ANALYTICS_SCRIPT_URL and ANALYTICS_SITE_ID. Storage is where the interesting constraint sits. S3 turns on only when S3_ENDPOINT, S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY are all three configured; S3_BUCKET, S3_REGION and S3_PUBLIC_BASE_URL then describe the destination and the public address. If the S3 set is incomplete, the README states that the storage service falls back to the DC image host, configured through DC_UPLOAD_URL. That fallback is convenient for a local run and worth understanding before a production deploy, since a half-finished S3 configuration does not fail loudly, it changes where your images live.

The CLI is the part most likely to outlive the web app

The npm package is named bmmd, and the README positions it as reusing the core Markdown processing capability from the command line. It accepts a file argument or stdin, and defaults to stdout. Installation is either global with pnpm add -g bmmd or ephemeral with pnpm dlx bmmd, which is the lower-commitment way to evaluate it. Four documented invocations cover the surface: render to a WeChat-targeted HTML file, extract from piped input with cat article.md | bmmd extract, and lint with --fix to repair Markdown and write back to the source file. For local development the build target is pnpm build:cli and the entry file is bin/bmmd.mjs. The extract subcommand is the one that deserves attention, because it implies a path from a document to Markdown that is separate from the render path. If you already have a corpus of HTML or office documents, that is the subcommand to try first. The render path, by contrast, only makes sense if the wechat platform flag does something you cannot reproduce with a CSS file.

Where bm.md is the wrong tool

The most obvious failure mode is a mismatch of output channel. If you publish to a static site, a documentation portal or a CMS that accepts HTML and lets you ship your own stylesheet, the 16 presets and the WeChat adaptation are solving a problem you do not have. You would be adopting a full TanStack Start application, with Nitro deployment targets and a storage layer, to do a job a Markdown parser and a stylesheet already do. The second limitation is the deployment surface itself. The README lists Cloudflare Workers, Vercel, Netlify, Docker, Alibaba ESA and Tencent EdgeOne among the Nitro targets, with worked configuration for Alibaba Cloud and Tencent EdgeOne EdgeOne builds. That breadth is a maintenance commitment, not a free feature: each target has its own build command, root directory, output directory and function entry path, and the README's EdgeOne note says the build environment is detected automatically by std-env with Nitro choosing the official preset. Automatic detection is convenient until it picks wrong, and when it does, the failure appears at deploy time. Third, the README does not state what the WeChat platform flag changes in the generated HTML. Without that, you cannot judge how much of the tool's value is the formatting rules and how much is the editor around them.

How it differs from a general Markdown-to-HTML converter

The natural alternative is a general converter such as Pandoc, or a Markdown renderer inside a static site generator. The difference in approach is where the platform knowledge lives. Pandoc takes a document and a target format and produces output according to a template you supply; the WeChat-specific rules, if you need them, are yours to write and maintain. bm.md inverts that: the platform is a first-class argument, --platform wechat, and the formatting decisions are baked into the tool rather than into a template you own. That is a real trade. You get the WeChat rules without writing them, and you lose the ability to change them without forking an LGPL-3.0 project. Pandoc also does not give you a live preview editor or a preset gallery, though it handles a wider range of document formats than the import list here. The honest comparison is not feature-by-feature. It is that bm.md is opinionated about one destination and Pandoc is opinionated about none. If your destination is WeChat, the opinion is the product.

Licence and the cost of keeping it current

The licence is LGPL-3.0, stated in the README and in the repository's licence file. For a self-hosted internal deployment this is usually unremarkable. Where it needs attention is distribution: if you modify bm.md and ship it, or link it into a distributed product, the LGPL-3.0 terms apply to that distributed work. This is not legal advice and the specifics depend on how you integrate, so read the licence text and get proper guidance if you are shipping a modified version. On maintenance, the material here is thin. No releases were retrieved for this review, so there is no changelog to read and no version history to reason about. What can be observed is the shape of the dependency surface: TanStack Start on React 19, Vite 8, Tailwind CSS 4, shadcn/ui, and Nitro for deployment. That is a modern, fast-moving stack, and upgrading any one of those major versions is a real piece of work. The project also carries an MCP integration and a documented UI skill for agent constraints, which are additional surfaces that will need updating as those conventions change. Budget for periodic dependency upgrades rather than treating this as a set-and-forget tool.

Editorial conclusion

Adopt bm.md if WeChat public accounts are a real publishing target and you want the formatting handled by a tool rather than by hand. Skip it if your output is a static site or a docs pipeline, where a Markdown-to-HTML step plus your own CSS already covers the job and the 16 style presets are noise. Before committing, verify three things: that the LGPL-3.0 terms fit how you intend to distribute the code, that your Node version satisfies the stated >= 20 requirement with pnpm 11.11.0, and that the S3 variables in .env.example are either fully set or deliberately left unset, because a partial S3 configuration silently falls back to the DC image host. Check the CLI against one real article first: pnpm dlx bmmd render article.md --platform wechat --output article.html.

Official sources

  1. Issues
  2. License: LGPL-3.0
  3. miantiao-me/bm.md on GitHub
  4. Project website
  5. README
Community notes

Community notes