Skip to content

stevenybw/mdselect

Repository files navigation

mdselect

中文说明

Select Markdown sections by heading path.

mdselect is a small, zero-runtime-dependency command-line tool for inspecting a Markdown outline and extracting complete sections without losing their original formatting.

Why mdselect?

Line-oriented tools such as grep can find a heading, but they do not know where that section ends. A full Markdown AST library understands much more of the format, but usually requires writing a program and choosing rendering semantics.

mdselect fills the gap:

  • query the heading hierarchy directly from the shell;
  • return a matched heading together with its body and descendants;
  • preserve the original Markdown content without parsing and re-rendering it;
  • use regular expressions in a compact heading path expression;
  • run with only the Python standard library.

Installation

mdselect requires Python 3.10 or newer.

pipx install mdselect
# or
uv tool install mdselect
# or
python -m pip install mdselect

To install a development checkout:

python -m pip install -e ".[test]"

Codex plugin

This repository also provides the recall-markdown-memory skill as an installable Codex plugin. The skill uses the mdselect executable from the task environment; installing the plugin does not install Python or the PyPI package automatically.

Install the CLI first and verify that it is on PATH:

pipx install mdselect
mdselect --version

Then add the repository marketplace and install the plugin:

codex plugin marketplace add stevenybw/mdselect
codex plugin add mdselect@mdselect

Start a new Codex session after installation. Invoke the skill explicitly with $mdselect:recall-markdown-memory, or ask Codex to recall a decision, preference, or other context from Markdown memory and let the skill trigger automatically.

The first release targets shell-enabled Codex CLI, IDE, and local desktop tasks. For a Codex Cloud environment, add CLI installation to its setup script, for example:

python -m pip install mdselect

The skill is read-only. It searches only user-specified or project-configured memory locations, plus the conventional MEMORY.md, memory/, and .agents/memory/ paths; it does not scan every Markdown file by default.

Quick start

Given handbook.md:

# Engineering Handbook

## Getting Started

Introductory material.

### Local Setup

Create a virtual environment.

## Operations

Operational notes.

Print its outline:

mdselect outline handbook.md
# Engineering Handbook
  ## Getting Started
    ### Local Setup
  ## Operations

Extract the complete Getting Started subtree:

mdselect select --mpath '/Engineering/Getting Started' handbook.md
## Getting Started

Introductory material.

### Local Setup

Create a virtual environment.

Add a trailing slash to omit the matched heading line:

mdselect select --mpath '/Engineering/Getting Started/' handbook.md

mpath syntax

An mpath is a slash-separated heading path:

Form Meaning
/Guide/Install Absolute query: the first segment only matches level-one headings.
Install Relative query: the first segment matches headings at any level.
/^Guide$/^Install$/ Each segment is a Python regular expression; anchors make matches exact. The trailing slash omits the matched heading.
/ Return the original document unchanged.

The complete rules are:

  1. Each non-empty segment is compiled as a Python regular expression and matched with re.search.
  2. A leading slash makes the query absolute: its first segment is tested only against level-one (#) headings.
  3. Without a leading slash, the first segment is tested against every heading.
  4. Every later segment is tested against descendants of the current matches, at any depth.
  5. A trailing slash excludes the final matched heading line while keeping its body and descendants.
  6. /, //, and an empty expression are no-ops that return the original document.
  7. A slash cannot appear inside a segment.
  8. Multiple matches retain document order and are separated by one blank line.
  9. When both an ancestor and its descendant match, only the ancestor is rendered as a result because its subtree already contains the descendant.

mdselect select -h prints these rules without requiring the README.

Exit status

Situation Status
Successful outline or selection 0
No matching section 0, with empty standard output
Invalid arguments or regular expression 2
File cannot be read non-zero

The no-match behavior is intentional so selection can be used in shell pipelines without treating an optional section as a command failure.

Supported Markdown and boundaries

  • ATX headings from # through ###### are supported when the marker starts in column one and is followed by whitespace.
  • Optional closing hash markers are removed from the heading title used for matching.
  • Backtick and tilde fenced code blocks are recognized; heading-like lines inside a fence are ignored.
  • Selected content is rendered from the original lines, preserving tables, blockquotes, blank lines, inline markup, and fences.
  • Files are read as UTF-8.
  • Setext headings are not supported.
  • mdselect does not interpret front matter, links, inline Markdown, or HTML as an AST.

Comparison

Tool Best for Structural section extraction
grep / rg Finding matching lines across files No
Markdown AST library Full parsing, transformation, and custom rendering Yes, with application code
mdselect Shell-friendly outline and heading-subtree selection Yes, directly from the CLI

Use grep or rg to discover candidate files, then use mdselect when the unit you need is a Markdown section rather than a line.

Python API

from mdselect import outline, select

print(outline(markdown_text))
section = select(markdown_text, "/Guide/Install")

The package also exports Section, parse, render_subtree, and InvalidPattern.

Contributing and security

See CONTRIBUTING.md for development and pull request guidance. Report security issues privately as described in SECURITY.md.

License

MIT

About

No description, website, or topics provided.

Resources

License

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages