harehare/mq: a jq-like query language for Markdown files
A jq-like Markdown query language for command-line processing
At a glance
- What is it?
- mq treats Markdown as structured data and gives it a jq-style filter, map and transform language. It is aimed at people who process Markdown in bulk, especially in LLM pipelines, and it installs from a shell script, Homebrew, Cargo or Docker.
- Who is it for?
- Adopt mq if you already reach for jq on JSON and want the same shape of tool for Markdown, particularly for LLM prompt and output handling or for batch edits across many documents. Do not adopt it if you need a stable, frozen query language for a long-lived production pipeline: the README states the project is under active development, the workspace version is 0.8.5, and the last push was on 2026-09-10.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What mq is for and who actually needs it
Markdown is a text format, but most of the time you do not want to treat it as text. You want the third section of a document, every code block under a heading, or the front matter as a map. grep gives you lines. sed gives you substitutions. Neither understands that a heading owns the paragraphs beneath it.
mq's pitch is that Markdown should be queried the way jq queries JSON. The README states the tool is "a command-line tool that processes Markdown using a syntax similar to jq" and that it lets you "slice, filter, map, and transform structured data." The intended audience is listed explicitly: LLM workflows, generation of Markdown input for language models, documentation management, content analysis, and batch processing across multiple files.
The LLM angle deserves scrutiny rather than dismissal. Prompts and model outputs are frequently Markdown, and the operations people actually perform on them (pull out a section, strip boilerplate, rewrite heading levels, merge fragments) are structural, not textual. That is the gap mq targets. If your Markdown work is one-off editing in an editor, mq is overhead. If it is a script that runs over a directory of files, the comparison to jq is fair.
How the Markdown query engine is put together
The Cargo workspace is the clearest view of the architecture. There is no single binary crate doing everything. mq-markdown handles parsing, mq-lang holds the language and interpreter, mq-hir provides a high-level intermediate representation, mq-repl implements the interactive shell, and mq-lsp implements the Language Server Protocol. mq-run is the crate that produces the mq binary, and mq-dap plus the debugger feature back the experimental mq-dbg tool.
That split matters for two reasons. First, the parser is a library, not a side effect of the CLI, which is why an FFI crate (mq-ffi) and a WASM crate (mq-wasm) can exist alongside the command line. Second, the language tooling is not an afterthought: mq-lint, mq-formatter, mq-check, mq-test and mq-crawler are all workspace members, and the justfile builds them in one recipe. A project that ships a linter and a formatter for its own query language is treating the language as something users will write at length.
The justfile also reveals a bytecode layer. The dump-bytecode recipe runs mq-dbg with --dump-bytecode and -I null, and its comment describes "Tarn bytecode." So queries are compiled to an intermediate bytecode before execution rather than walked directly. The README does not document the bytecode format or promise stability for it, and the recipe comment ties the flag to debugger wiring, so treat the dump as a development aid, not an interface.
Extensibility has two documented paths. Custom functions are a stated feature, and external subcommands work by placing executables whose names start with mq- in ~/.local/bin/. The latter is the same convention git uses, which means extending mq does not require touching the Rust codebase.
Installing mq and running a first query
The quickest path on macOS or Linux is the install script. The README says it downloads the latest binary for your platform, installs it to ~/.local/bin/, and updates your shell profile to add mq to PATH.
curl -sSL https://mqlang.org/install.sh | bashAfter that, a new shell should have mq on PATH. If you prefer a package manager, the README lists Homebrew, yay on Arch, Cargo and Docker. The Cargo package name is mq-run, not mq.
brew install mq
cargo install mq-run
docker run --rm ghcr.io/harehare/mq:latestFor a pinned build rather than the latest development version, the README gives a tag-based install. The current release at the time of writing is v0.8.5.
cargo install --git https://github.com/harehare/mq.git mq-run --tag v0.8.5Building from a clone is also supported. The justfile defines a build recipe that produces the release binaries, including mq, mq-dbg with the debugger feature, mq-lsp, mq-crawler, mq-test, and the CLI features of mq-check and mq-lint.
cargo build --release -p mq-run --bin mqThe README does not print a worked query example in the text provided, so the place to learn the syntax is the book and the playground, both linked from the project site at https://mqlang.org. For interactive experimentation, the README lists REPL support as a feature, so running mq with no pipeline is the natural starting point. What you should look for first is whether a selector can address a heading and return its section, because that single capability is the difference between mq and a line-oriented tool.
Where mq is the wrong tool
The README carries a notice that the project is under active development. The workspace version is 0.8.5, the release cadence shown is three releases in about three weeks during August and September 2026, and the last push was on 2026-09-10. Rapid minor releases at a 0.x version mean the query syntax and built-in function set can change between versions. If you pin mq in a CI pipeline that other people depend on, budget for reading release notes on every bump.
There is a second, quieter limitation. mq is a Markdown processor, so it is only as good as its parser's coverage of the Markdown you feed it. Documents that are Markdown in name but not in practice, such as generated HTML with embedded Markdown fragments, or files using a dialect the parser does not implement, are the cases where a query language has nothing to grip. The README does not document which Markdown dialect or extensions the parser handles, so that is something to verify against your own corpus before adopting.
Finally, consider the shape of the problem. If you need to find a string and replace it, sed or ripgrep are faster to write and have no install step. If you need to validate that a documentation site builds, a static site generator's own checks are closer to the failure you care about. mq earns its place when the operation is structural and repeated.
mq against the tools you already have
The honest alternative is not another Markdown query language, because there is no widely deployed one. It is the combination of a general-purpose parser and a general-purpose query tool.
One approach is to convert Markdown to HTML or JSON, then use jq or XPath on the result. Pandoc plus jq is the classic version of this. The difference in approach is real: that pipeline makes the conversion an explicit, inspectable step, and you get the full maturity of jq's language. The cost is that you lose the direct correspondence between the query and the Markdown source. Line numbers and source positions refer to the converted document, not the file you edited, which makes round-tripping edits back to Markdown awkward. mq keeps the query operating on Markdown itself, which is the whole point of the project.
The other approach is to write a script against a Markdown parsing library in Python or JavaScript. That gives you arbitrary logic, and it is the right answer when your transform is genuinely bespoke. It is the wrong answer when the transform is one of the common ones, because you end up maintaining a small program where a query would do. mq's bet is that the common cases are common enough to deserve a language, and the presence of mq-lint and mq-formatter suggests the author expects queries to accumulate.
On the input side, the repository lists html-to-markdown among its topics, which points at a conversion path in the other direction: HTML in, Markdown out, then query. The README does not document that workflow in the text provided, so treat it as a topic hint rather than a documented feature.
Licence, maintenance and the cost of upgrading
mq is MIT licensed, stated in the README badge and in the workspace package metadata. MIT is permissive: you can use it commercially, modify it, and redistribute it, provided the copyright notice and licence text travel with it. That is a description of the licence terms, not legal advice, and if you are embedding mq in a product you should have your own counsel read the LICENSE file at the repository root.
The maintenance picture from the repository alone: the repository is not archived, the last push was on 2026-09-10, and the most recent release was v0.8.5 on 2026-09-08. That is a project with recent activity. It is also a project that labels itself as under active development, so the upgrade cost is not zero. The practical approach is to pin a version, which the README supports directly through the tagged Cargo install and through binstall with an explicit version, and to read the release notes before moving.
The workspace structure lowers the cost of some kinds of change and raises it for others. Because mq-markdown, mq-lang and mq-hir are separate crates, a change to the query language does not force a change to the parser. But the crates are versioned together at 0.8.5 through workspace dependencies, so you cannot mix a newer language crate with an older runner without checking compatibility yourself. The README does not document a compatibility policy between crate versions.
Editorial conclusion
Adopt mq if you already reach for jq on JSON and want the same shape of tool for Markdown, particularly for LLM prompt and output handling or for batch edits across many documents. Do not adopt it if you need a stable, frozen query language for a long-lived production pipeline: the README states the project is under active development, the workspace version is 0.8.5, and the last push was on 2026-09-10. Before committing, read the book at mqlang.org/book, try your real documents in the playground at mqlang.org/playground, and check whether the built-in functions and selectors cover the transforms you need, because the README lists them as features without enumerating them.
Frequently asked questions
How do I install harehare/mq?
The README gives a quick install script at https://mqlang.org/install.sh that downloads the latest binary, puts it in ~/.local/bin/ and updates your shell profile. It also lists Homebrew (brew install mq), yay on Arch (yay -S mq-bin), Cargo (cargo install mq-run) and Docker (docker run --rm ghcr.io/harehare/mq:latest). Pre-built binaries for macOS, Linux and Windows are on the GitHub releases page.
Is harehare/mq a replacement for jq?
No. The README describes mq as processing Markdown with a syntax similar to jq, so it is the same style of tool applied to a different input format. If your data is JSON, jq is the direct tool; mq is for when the data is Markdown.
Does harehare/mq have a REPL and editor support?
The README lists REPL support as a feature for testing and experimenting with queries. It also lists a Language Server Protocol implementation and a VS Code extension, with additional editor integrations documented for Neovim, Zed and JetBrains IDEs.
Can I extend harehare/mq with my own commands?
Yes, through external subcommands. The README states that placing executable files whose names start with mq- in ~/.local/bin/ extends mq with custom subcommands. Custom functions are also listed as a feature, with LSP support described for custom function development.
What licence does harehare/mq use?
MIT, according to the licence badge in the README and the license field in the workspace package metadata. The LICENSE file is at the repository root.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/harehare-mq)