CLI tool
Epistates/treemd avatar
Epistates/treemd

treemd: a markdown navigator that treats a document as a tree

A (TUI/CLI) markdown navigator with tree-based structural navigation.

705 stars33 forksRustMIT

At a glance

What is it?
treemd is a Rust TUI and CLI for reading markdown by structure, showing a foldable outline of headings beside the content and offering a jq-like query language for extracting parts of a document from scripts. The interesting part is that the same document model drives both surfaces, so the outline you navigate by hand is the one you can query from a shell, and the interactive mode writes edits back to the file.
Who is it for?
Adopt treemd if you read long markdown in a terminal, especially if you also need to extract sections from documents in a script, since the CLI exposes the same heading tree the TUI shows and the query language covers code blocks and sections without a separate parser. Do not adopt it if you need to edit markdown in a general purpose editor, since the in-place editing covers checkboxes, table cells and links rather than prose, and the TUI needs a terminal with colour support.
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 5 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 October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The document is a tree, and the tree is the interface

The pitch is short enough to state precisely. treemd shows a document's headings as a tree you can fold and search, with the section you are on beside it, and gives the shell the same view: list, extract and query any part of a document with a jq-like language.

That last clause is what separates it from a markdown pager. The outline is not a presentation layer drawn on top of a flat text buffer; it is a structural model of the document, and the CLI queries that model directly. When you run treemd with a list flag and get headings with line ranges, you are asking the same question the TUI asks when it draws the tree.

The feature list names the capabilities in order. Outline navigation covers folding, filtering and jumping between headings, with the content following the selection. Rich rendering covers syntax highlighting for 50+ languages, tables, task lists, callouts, images and Mermaid diagrams in terminals that support them. Interactive mode covers toggling checkboxes, editing table cells, following links and copying any element, with the changes written back to the file. Then seventeen themes, light ones included, each held to WCAG contrast, plus a no-color mode. And a CLI for scripts and agents, offering heading lists with line ranges, section extraction, JSON output and the query language.

The project is MIT licensed, written in Rust with a rust-version floor of 1.90, and the last push was on 2026-10-18 with v0.10.0 released the same day.

Four ways to install, and a note on the prebuilt binaries

The install section leads with the package managers, one line each:

bash
cargo install treemd       # crates.io
brew install treemd        # Homebrew, macOS and Linux
pacman -S treemd           # Arch Linux (extra)
pkgin install treemd       # NetBSD

Prebuilt binaries for Linux, macOS and Windows are on the releases page, and the readme points at a separate release binaries section for verifying them, which is the detail worth noticing. A viewer that renders files it did not write is exactly the sort of program where a checksum or signature check is cheap insurance, and the project has evidently thought about it.

Building from source is a clone and an install:

bash
git clone https://github.com/epistates/treemd
cd treemd
cargo install --path . --locked

The --locked flag matters, because the Cargo.lock in the repository pins the dependency versions and without it a fresh build resolves to whatever is newest.

There is also a completions and man page step, and it comes with a restriction worth knowing about. Shell completions, which offer only markdown files and directories, are set up interactively:

sh
treemd --setup-completions   # bash, zsh or fish, set up interactively
treemd --man-page > treemd.1 # the man page, for packagers

Completions that only offer markdown files and directories is a deliberate design decision rather than an omission. The tool knows what it can open, and the completion list reflects that instead of listing everything in the directory.

The quick start shows the same model from both sides

The quick start block is a good index of the whole tool, because each line exercises a different mode:

sh
treemd README.md              # open a file
treemd .                      # pick a file in this directory
treemd github:rust-lang/rust  # a GitHub repo's README, whatever it's named
treemd -l -n README.md        # list headings with their line ranges
treemd -s Install README.md   # print one section
treemd -q '.code[rust]' doc.md # every Rust code block

The first three open the TUI, the last three are the scriptable side. Listing headings with their line ranges is the one an agent would reach for first, because it gives you a table of contents with line ranges, which is what you need to slice a document without reading it. Printing one section by name is the extraction primitive. The query in the last line is a path expression, and.code[rust] selects code blocks whose language is rust.

The remote form is worth pausing on. treemd github:owner/repo fetches a repository's README whatever it happens to be named, and the feature list also says any markdown URL works, which means the tool is not tied to the local filesystem.

The output format follows the same idea. The CLI offers JSON output as well as the human-readable forms, so a script does not have to parse the text rendering.

Two panes, one document, and a footer that tells you the keys

The TUI layout is two panes, the outline on the left and the selected section on the right, with Tab switching between them. You move through the outline with j and k and fold with Enter, or hide the outline with w and read the content alone.

Two details make this usable rather than merely clever. The footer shows the keys for whatever you are currently doing, ? lists them all, and : opens a command palette that finds any command by name. A mode-dependent footer plus a searchable palette is how a keyboard-driven interface stays discoverable when it has this many bindings.

Search is scoped rather than global. / searches the current section and s filters the outline, and while you are typing, Tab switches between the two, so you can drive the search box and the filter without leaving the keyboard.

The outline itself has a few conveniences that are worth naming because they are unusual. Digits start a count, so 5j and 3k repeat a move. Bracket keys set the outline width to 20, 30 or 40 percent. The # key shows or hides the level markers, and T shows only headings that have open todos, with Esc clearing that filter.

Link following is a first-class navigation mode rather than a background feature. f lists the section's links and follows one by number, b and Backspace move back and forward through followed links and files, and p shows the parent section's links. In the file picker, / searches, Backspace goes up a directory and h shows hidden files.

Interactive mode writes back to the file, and the undo stack is one level

Interactive mode is where treemd stops being a viewer. Pressing i steps through the section's elements one at a time, checkboxes, tables, links, code blocks, images and details blocks. Enter uses the element, which means toggling a checkbox, expanding a details block, following a link, editing a table cell or viewing an image full screen, depending on what the element is. y copies it, and e opens your editor at its line.

Table cells are edited in place. On a table, Enter moves into the cells, the h, j, k and l keys move between cells, Enter edits the cell, and y, Y and r copy the cell, the row or the table as markdown. In the full-screen image viewer, Space plays or pauses a GIF and h and l step through its frames.

Every change is written back to the file, and Ctrl+z undoes the last edit. One level, though. The keybinding table lists Ctrl+z under interactive mode as undo the last edit, and separately under the view section as suspend to the shell, with fg returning. So undo is a single step rather than a stack, which is a real constraint for anyone making several edits in a row.

The copy behaviour is also more useful than a single copy command. y copies the element, but on a table it copies the cell, the row or the whole table as markdown, and in the general view y and Y copy the section or a link to its heading.

The parser underneath, and why the table editing works

The dependency list explains how the features are actually implemented, and two entries matter most.

The markdown parsing goes through turbovault-parser, pinned at 4.0.1, described as Turbovault integration with code-block awareness. The comment in the manifest explains the interesting part: turbovault is built on pulldown-cmark, and pulldown-cmark is used directly, but only to locate a table's source range for in-place cell edits, because turbovault's blocks do not carry that information. Same version line, so it is one copy in the build.

That is a precise explanation of a real problem. To edit a table cell in place and write the result back, you need to know where the cell lives in the original source text, not just the parsed value. A parser that hands you a structured tree has thrown that information away. Keeping a second dependency for source ranges is how treemd gets both a rich parse and editable tables.

The rest of the stack is standard for a terminal application. clap 4.6 with derive for the CLI, clap_complete with unstable-dynamic for completions, and clap_mangen for the man page. ureq 3 handles remote document fetching for the url and github: forms. unicode-width 0.2 and unicode-segmentation 1.13 handle text measurement, with the latter noted as being for grapheme clusters when wrapping the content pane, at the same version ratatui uses. serde and serde_json produce the JSON output, and indexmap backs the query language support.

The repository layout backs up the same story. There is a src/ tree with both a library and a binary, a tests/ directory, a docs/ directory, a justfile with build, release, test, check, lint, doc-check, fmt and install recipes, a proptest-regressions/ directory for property-based testing, and a skills/ directory. The justfile runs cargo test with --all-targets --all-features --locked for the full suite, and a separate minimal variant with --no-default-features, which is the shape you would expect from a project with feature-gated code paths that have to keep compiling in both configurations.

Where treemd is the wrong tool

The boundary is worth stating clearly, because a markdown TUI invites comparison with editors.

The editing model is structured elements, not prose. Checkboxes toggle, table cells change, links follow. There is no mechanism described for rewriting a paragraph, which is what you would want from an editor, and the in-place table editing writes back to the source, so a change is a text mutation of the file rather than a rich edit.

The rendering is bounded by what a terminal can do. The feature list says Mermaid diagrams and images render in terminals that support them, which is a qualifier doing real work. A terminal without image support gets a different document, and the seventeen themes plus a no-color mode address appearance rather than capability.

Then there is the reliance on a modern Rust toolchain. The manifest requires rust-version 1.90 and edition 2024, which is a floor rather than a suggestion, and the build instructions use --locked throughout, so the dependency versions in Cargo.lock are part of the deal.

What treemd is genuinely good at is reading. Folding an outline, searching within a section, jumping to a heading, following links across files, and then doing the same thing from a shell for scripts and agents. The project also ships a skills/ directory, which suggests the author is thinking about how an agent would use the tool, and that is the framing the readme uses when it describes the CLI as being for scripts and agents.

Editorial conclusion

Adopt treemd if you read long markdown in a terminal, especially if you also need to extract sections from documents in a script, since the CLI exposes the same heading tree the TUI shows and the query language covers code blocks and sections without a separate parser. Do not adopt it if you need to edit markdown in a general purpose editor, since the in-place editing covers checkboxes, table cells and links rather than prose, and the TUI needs a terminal with colour support. Before you rely on it in a pipeline, check the query language and the JSON output flags on your own documents, and if you install a prebuilt binary, verify it against the release binaries process the project describes, because a viewer that renders files you did not write is exactly the kind of tool where a signature check is worth the minute it takes.

Frequently asked questions

How do I install treemd?

Through a package manager with cargo install treemd, brew install treemd, pacman -S treemd or pkgin install treemd. To build from source, clone the repository and run cargo install --path . --locked, and prebuilt binaries for Linux, macOS and Windows are on the releases page.

What can the treemd CLI do for scripts?

It lists headings with their line ranges, extracts a named section, and queries parts of a document with a jq-like language, for example treemd -l -n README.md, treemd -s Install README.md and treemd -q '.code[rust]' doc.md. JSON output is also available so a script does not have to parse the human-readable rendering.

Can treemd edit the markdown file it displays?

In interactive mode it toggles checkboxes, edits table cells in place, follows links and copies elements, and every change is written back to the file. Ctrl+z undoes the last edit, and the documented undo is a single step rather than a stack.

Can treemd open documents that are not local files?

Yes. The feature list names remote documents, with treemd github:owner/repo or any markdown URL, and the quick start shows treemd github:rust-lang/rust for a repository README whatever it is named.

Which themes and terminal features does treemd support?

There are seventeen themes, light ones included, each held to WCAG contrast, plus a no-color mode. Rendering covers syntax highlighting for 50+ languages, tables, task lists, callouts, images and Mermaid diagrams in terminals that support them.

Official sources

  1. Epistates/treemd on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/epistates-treemd.svg)](https://hysenlabs.com/projects/epistates-treemd)

Was this useful?