# mq has four names: the repository, the binary, the crate you install, and the crate the badge links

> A Rust implementation of jq for Markdown, aimed squarely at people assembling LLM prompts, with a debugger, a language server, editor extensions and a headless browser crawler in the same workspace. The tooling is careful and the release cadence is fast, which together make the install path the part most worth reading before you run anything.

**harehare/mq** — A jq-like Markdown query language for command-line processing

- Repository: https://github.com/harehare/mq
- Website: https://mqlang.org
- Stars: 1,038 · Forks: 23
- Language: Rust
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/harehare-mq

## The repository, the binary, the crate and the badge all carry different names

Four names are in play and only one of them is what you type. The repository is harehare/mq, the binary is `mq`, the command is `mq`, and the crate you install is `mq-run`.

The package manager table spells it out: Homebrew is `brew install mq`, MacPorts is `sudo port install mq`, the Arch User Repository package is `yay -S mq-bin`, crates.io is `cargo install mq-run`, and the container is `docker run --rm ghcr.io/harehare/mq:latest`. Two of those five install something whose package name is not `mq`, which is the kind of detail that sends a first-time installer to the wrong page.

Then the badge row at the top of the file links to `crates.io/crates/mq-markdown`, a third name, and the workspace manifest shows why: `mq-markdown` is a separate crate in a twenty member workspace, alongside `mq-run` which holds the binary and `mq-lang`, `mq-hir`, `mq-repl` and the rest.

The git install forms make the split even clearer:

```sh
# Install from Github
cargo install --git https://github.com/harehare/mq.git mq-run --tag v0.9.2
# Latest Development Version
cargo install --git https://github.com/harehare/mq.git mq-run --bin mq
# Install the debugger
cargo install --git https://github.com/harehare/mq.git mq-run --bin mq-dbg --features="debugger"
# Install using binstall
cargo binstall mq-run@0.9.2
```

Every one of those four lines installs `mq-run` and produces a binary called something else.

## The quick installer writes a binary and edits your shell profile

The one line install is:

```bash
curl -sSL https://mqlang.org/install.sh | bash
```

What it does is described in one sentence: it downloads the latest binary for your platform, installs it into `~/.local/bin/`, and updates your shell profile to add mq to the PATH. That is two side effects, not one, and the second one modifies a file you did not name on the command line.

The project does not hide this. It also tells you to read either the macOS and Linux shell script or the Windows PowerShell script before running it, and links both in the tree.

The alternatives differ in cost rather than in function. Homebrew needs no privileges and manages upgrades. MacPorts needs `sudo`. The Arch package is the `-bin` flavour, which means a locally built binary rather than one from the distribution. Cargo compiles from source, and `cargo binstall` exists specifically to skip the compile and take a pre-built binary. The container path runs the published image with no install at all:

`docker run --rm ghcr.io/harehare/mq:latest`

Pre-built binaries for macOS, Linux and Windows are also on the releases page, so the compile is always avoidable if you would rather not run a build.

## Subcommands are discovered by filename, so anything named mq- on your PATH is one

The extension mechanism for commands is the filesystem, not a plugin registry. Executable files that start with `mq-` placed in `~/.local/bin/` become subcommands of mq, discoverable through the same help output as the built-ins.

That is a small design with a straightforward consequence. There is no manifest, no signature and no allow list. Any file on your PATH beginning with those three characters followed by a hyphen becomes callable as `mq something`, and the user directory named in the documentation is only the recommended location.

In practice the convention keeps a user's own scripts out of the way, since anything else they wrote will not carry the prefix. It also means the trust boundary of mq extends to every directory on your PATH. On a machine where PATH includes a shared or world writable directory, that is worth knowing before you start running subcommands you did not write.

The same openness shows up elsewhere in the design. Custom functions are a named extension point, the debugger is a separate binary rather than a flag, and the editor integrations are separate packages in the same repository.

## Twenty workspace crates, one of which drives a headless browser

The manifest lists twenty members and the resolver is set to version 3 on edition 2024, with the workspace version pinned at 0.9.2 and repeated into eleven internal path dependencies. Most of the names describe a compiler pipeline: `mq-lang`, `mq-hir`, `mq-repl`, `mq-lint`, `mq-check`, `mq-test`, `mq-formatter`, `mq-help`, `mq-macros` and `mq-markdown`.

The rest are the interesting ones. `mq-wasm` and `mq-web-api` exist, the latter pulling in axum, which is how a query engine reaches a browser and a network service. `mq-ffi` with cbindgen exists for calling the engine from C. `mq-lsp` is the language server, `mq-dap` is a debug adapter, and it depends on a Debug Adapter Protocol crate still at an alpha version. `mq-crawler` depends on chromiumoxide, a headless Chrome driver, so the tool set includes fetching and parsing web pages. `mq-bench` holds benchmarks, `fuzz` is a separate fuzzing target, and `editors/zed` is inside the workspace, meaning the Zed extension is built with the same command that builds the CLI.

Two things follow. Building the workspace is not building a binary, and a cargo install that names a single crate is doing you a favour. And the dependency list is not limited to parsing libraries: a sanitizer, a browser driver, an HTTP framework and a clipboard library are all in the same tree.

## The container copies the whole repository and ends up with no shell

The Dockerfile is short. The builder stage starts from a Rust slim image pinned by digest, copies the entire working directory into the build root, and runs one cargo command targeting the `mq-run` package and the `mq` binary in release mode. The runtime stage is a distroless C++ image running as a non root user, and the only thing copied forward is the resulting binary, with ownership set to that user. The entry point is `mq` itself.

Two properties of that shape are worth naming. First, distroless means no shell, so debugging a failing container run means rebuilding rather than opening a prompt inside it. Second, copying the whole repository before the build means any source edit invalidates the dependency compilation layer, so an image build recompiles the dependency tree instead of reusing it.

There is a second Dockerfile, `Dockerfile.vercel`, plus a `vercel.json` and a `.vercelignore`, which points at the web side of the project. The task runner agrees: one recipe starts the playground development server inside `packages/mq-playground` and another starts the Chrome extension inside `packages/mq-chrome-extension`, both through pnpm.

So the repository builds three things from one source tree, a native binary, a browser extension and a hosted web playground, and only the binary has a container image.

## Queries compile to bytecode, and there is a debugger for stepping through it

The internal representation has a name that shows up in the build tooling: the task runner has a recipe described as dumping bytecode for a query, with the example invocation written as `just dump-bytecode '1 + 2'`. The recipe runs the debugger binary with bytecode dumping and an input override set to null, and the comment above it says the point is to verify that the debugger is wired to the debug trace.

The debugger itself is described as experimental and ships as a separate binary, `mq-dbg`, behind a `debugger` feature flag that appears in both the install line and the release build steps. So stepping through a query interactively is available, and is explicitly not the stable surface.

The task runner also sets a backtrace environment variable for every recipe it runs, which is a small thing that tells you the project expects its own tests to fail loudly. Benchmarks run through codspeed, which matches the badge at the top of the file, and the local variant runs cargo bench inside `crates/mq-lang`. The release build is seven separate cargo invocations rather than one, because the optional binaries and the feature gated command line tools are built separately from the main binary.

The playground, the book and the documentation site are separate surfaces again, which is what a project turns into once the language has more than one consumer.

## Three releases in six days, and the branch is a day ahead of the tag

Version 0.9.2 is the current one, and the recent history is dense: v0.9.0 on 23 September 2026, v0.9.1 on 24 September, and v0.9.2 on 28 September. The default branch received a push on 29 September, so the tip is a day beyond the newest tag.

That gap is the normal state of a repository with a release script and an active contributor, and it is also why the install instructions distinguish two paths. Pinning `--tag v0.9.2` gives you a known state; dropping the tag and asking for the `mq` binary from the default branch gives you the development version. The file lists both, and lists them separately, which is the kind of honesty that makes a fast cadence usable.

The status callout near the top says the project is under active development. That is consistent with a zero major version, a release every few days and a debugger described as experimental. What it does not tell you is whether query output changes between versions, and for a tool whose purpose is feeding text to another program, that compatibility question is the one that matters.

The workspace manifest pins eleven internal crates to the same 0.9.2, so a version bump touches all of them together, which is what makes the tag the right thing to pin in CI.

## The case for mq is entirely about Markdown as model input

The justification section does not talk about documentation generally. It talks about LLM workflows, about generating structured Markdown optimised for model consumption, and about the claim that Markdown is the primary input format for most language models. Documentation management, content analysis and batch processing are listed underneath as further uses.

The integration list follows from that. There is a VS Code extension, a Chrome extension for working with Markdown in the browser, guides for Neovim and Zed, a JetBrains plugin, an Obsidian community plugin, syntax highlighting for Helix, and a language server for people writing custom functions. For CI there is a setup action:

```yaml
steps:
  - uses: actions/checkout@v7
  - uses: harehare/setup-mq@v1
  - run: mq '.code' README.md
```

The example query pulls code blocks out of a README, which is the shape of use the tool is built for: one selector, one file, output that goes straight into a prompt.

The rest of the tree is the standard equipment of a careful project rather than a marketing one: a Nix flake, a cargo deny configuration, a pinned Rust toolchain file, a formatter configuration, a typos configuration, a fuzz target, a task list, and both `CLAUDE.md` and `AGENTS.md` for agent instructions.

Three of those surfaces have their own addresses rather than living in the repository text: the project site, a book with a section on syntax highlighting, and a playground where a query can be tried in a browser. The playground exists because of a crate rather than a page: `mq-wasm` and `mq-web-api` are what make the same query runnable in a browser tab and behind an HTTP endpoint.

## Conclusion

mq suits anyone who keeps a pile of Markdown and needs a slice of it for a prompt, a changelog check or a documentation sweep, and it is a poor fit if you want stable output guarantees from a one year old interface, because the language is at 0.9 and three of its recent releases landed inside six days. Three things to check first. Read the install line you are about to paste: the quick installer writes to your local bin directory and edits your shell profile, so it touches more than a binary. Confirm which crate you want, since the command is mq, the crate is mq-run and one badge points at mq-markdown. And know that any executable named with an mq prefix anywhere on your PATH becomes a subcommand.

## FAQ

### How do I install mq?

The quick install is curl -sSL https://mqlang.org/install.sh | bash, which downloads the latest binary into ~/.local/bin/ and updates your shell profile to add mq to the PATH. The alternatives are brew install mq, sudo port install mq, yay -S mq-bin, cargo install mq-run, and docker run --rm ghcr.io/harehare/mq:latest.

### What is the mq crate called on crates.io?

mq-run. The binary it produces is called mq, the repository is harehare/mq, and one badge at the top of the documentation links to a different crate, mq-markdown, which is a separate member of the same twenty crate workspace.

### Does mq have a debugger?

There is an experimental one called mq-dbg for inspecting and stepping through queries interactively, and it is built behind a debugger feature flag rather than shipped in the default build. The task runner even has a recipe that dumps the bytecode for a query to check the debugger wiring.

### Which editors and CI systems does mq integrate with?

VS Code, a Chrome extension, Neovim, Zed, JetBrains IDEs, Obsidian and Helix, plus a language server for custom function work. For CI there is a setup action, harehare/setup-mq@v1, whose example runs mq '.code' README.md after checkout.

### Can I add my own subcommands to mq?

Yes, by placing executables whose names start with mq- in ~/.local/bin/. The convention is filesystem based with no manifest or signature, so any such file on your PATH becomes callable as an mq subcommand.

## Sources

- [harehare/mq on GitHub](https://github.com/harehare/mq)
- [License: MIT](https://github.com/harehare/mq/blob/main/LICENSE)
- [Project website](https://mqlang.org)
- [README](https://github.com/harehare/mq/blob/main/README.md)
- [Releases](https://github.com/harehare/mq/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/harehare-mq
