A collection of utilities for working with Markdown files — from Swift library, to CLI tool, to Agent Skill. Each layer is built on top of the previous one.
MarkdownUtilities— A Swift library for parsing and manipulating Markdown content.md-utils— A command-line tool, built on top ofMarkdownUtilities, for performing operations on Markdown files.markdown-utilities— An Agent Skill for AI coding assistants, built on top of themd-utilsCLI.
The markdown-utilities Agent Skill teaches AI coding assistants how to use md-utils for Markdown operations. It provides commands, examples, and reference documentation that are loaded on demand.
Prerequisite: Install the
md-utilsCLI first (see CLI Installation below).
npx skills add https://github.com/DandyLyons/md-utils --skill markdown-utilitiesVisit the skills.sh page for more details.
Personal usage — install the skill just for yourself:
/plugin marketplace add DandyLyons/md-utils
/plugin install markdown-utilities@md-utils
Project-wide — share the skill with your whole team automatically:
Add to .claude/settings.json in your project:
{
"enabledPlugins": {
"markdown-utilities@md-utils": true
},
"extraKnownMarketplaces": {
"md-utils": {
"source": {
"source": "github",
"repo": "DandyLyons/md-utils"
}
}
}
}Team members will be prompted to install the skill when they open the project in Claude Code.
Using Mint
# Install mint (if you haven't done so already)
brew install mint
# Install
mint install DandyLyons/md-utils
# Run without installing
mint run DandyLyons/md-utils <command>git clone https://github.com/DandyLyons/md-utils.git
cd md-utils
swift build -c release
# Binary will be at .build/release/md-utilsAdd to your Package.swift:
.package(url: "https://github.com/DandyLyons/md-utils.git", from: "0.1.0")Then add "MarkdownUtilities" to your target's dependencies:
.target(
name: "YourTarget",
dependencies: [
.product(name: "MarkdownUtilities", package: "md-utils"),
]
),This project is on a 0.x.x release and is not yet API stable. The API and CLI may change between releases. Breaking changes will be documented in release notes.
- Table of Contents — Generate TOC with multiple output formats (Markdown, JSON, plain text, HTML)
- Heading Manipulation — Promote/demote headings while maintaining nested structure
- Section Operations — Extract sections by name or index; reorder sections (move up/down/to position)
- Content Selection — Extract body without frontmatter, select by line range, extract by section
- YAML Front Matter — Full CRUD operations with 12+ subcommands including get, set, remove, rename, search (JMESPath), sort keys, array manipulation, and multi-format dump (JSON, YAML, raw, PropertyList)
- Format Conversion — Convert Markdown to plain text or CSV
- File Metadata — Read file metadata including standard and extended attributes (xattr)
- Wikilink Parsing & Resolution — Parse Obsidian-flavored wikilinks, resolve against a vault directory, detect broken/ambiguous links, find backlinks
- Link validation (URL/reference link checking)
- Markdown flavor validation (CommonMark, GFM, Obsidian)
- Additional format conversions (HTML, RTF, XML)
- File metadata writing
Build and run with Swift Package Manager:
swift run md-utils <command> [options]# Generate a table of contents
swift run md-utils toc README.md
# Get a frontmatter value (JSON by default)
swift run md-utils fm get --key title document.md
# => [{"path":"...","value":"My Title"}]
swift run md-utils fm get --key title posts/ | jq '.[] | select(has("value")) | .value'
# Set a frontmatter value
swift run md-utils fm set --key tags --value "[swift, cli]" document.md
# Dump frontmatter as JSON
swift run md-utils fm dump document.md
# Search frontmatter with JMESPath
swift run md-utils fm search --query "tags[?contains(@, 'swift')]" docs/
# Convert Markdown to plain text
swift run md-utils convert to-text document.md
# Extract a section by name
swift run md-utils extract --name "Installation" README.md
# Promote all headings by one level
swift run md-utils headings promote document.md
# List wikilinks with resolution status
swift run md-utils links list --vault ~/notes note.md
# Check for broken wikilinks
swift run md-utils links check --vault ~/notes docs/
# Find backlinks to a file
swift run md-utils links backlinks --vault ~/notes --target "My Note"
# Read file metadata
swift run md-utils meta read document.md
# Extract lines 10-20
swift run md-utils lines --start 10 --end 20 document.mdRun swift run md-utils --help or swift run md-utils <command> --help for full usage details.
Project-level md-utils settings live in .md-utils/md-utils.json. The schema command group creates and uses this folder to validate Markdown YAML frontmatter against JSON Schema files. Schemas only apply to frontmatter, not Markdown body content.
Treat the directory containing .md-utils/ as the md-utils project root. Commands that use project configuration read .md-utils/md-utils.json relative to the current working directory; md-utils does not search parent directories for project configuration. Run schema/config commands from the directory that contains .md-utils/:
cd /path/to/project
md-utils schema validatePaths in schemaRules[].match.paths and the default schemaDirectory are interpreted relative to that same working directory. If you run md-utils from a subdirectory, it will look for .md-utils/md-utils.json in that subdirectory.
Default layout:
.md-utils/
md-utils.json
md-utils.schema.json
schemas/
book.schema.json
Example config:
{
"$schema": "md-utils.schema.json",
"schemaDirectory": ".md-utils/schemas",
"schemaRules": [
{
"name": "books",
"schema": "book.schema.json",
"frontmatterRequired": true,
"match": {
"paths": ["Books/**/*.md"],
"frontmatter": {
"tags": { "includes": "Book" }
}
}
}
]
}Config fields:
$schema: Optional editor hint for autocomplete and validation.schemaDirectory: Directory for JSON Schema files. Defaults to.md-utils/schemas.schemaRules: Rules that map schemas to Markdown files.schemaRules[].name: Unique rule name formd-utils schema validate <rule-name>.schemaRules[].schema: Schema file, resolved relative toschemaDirectory.schemaRules[].frontmatterRequired: Iftrue, matched files without frontmatter fail; iffalse, they are skipped.schemaRules[].match.paths: Glob patterns matched against project-relative Markdown paths.schemaRules[].match.frontmatter: Frontmatter matchers. Initially supports{ "includes": value }for array values.
Schema commands:
md-utils schema init books --path "Books/**/*.md" --tag Book
md-utils schema add published --path "Books/**/*.md" --no-frontmatter-required
md-utils schema list
md-utils schema validate
md-utils schema validate books
md-utils schema remove books
md-utils schema remove books --delete-schemaschema init bootstraps .md-utils/ and adds an initial rule. schema add adds another rule to existing config. schema remove removes a rule; --delete-schema also deletes that rule's schema file when it is not shared by another rule.
If a file matches multiple rules, all matching schemas apply. Files matching no rules are ignored. Invalid YAML frontmatter is always reported as an error because schema validation cannot proceed.
- Swift 6.2 or later
- All testing uses the native Swift Testing framework
- MarkdownSyntax — Swift Markdown parsing and syntax tree
- swift-parsing — Parser combinators
- swift-argument-parser — CLI argument parsing
- PathKit — File path handling
- JSONSchema.swift — JSON Schema validation
- Yams — YAML parsing and serialization
- jmespath.swift — JMESPath query language for JSON
macOS is the primary development and testing platform. All features are fully supported on macOS.
Linux: All dependencies are reported as buildable on Linux (Swift Package Index). The code avoids Apple-only frameworks and the one Darwin-specific feature (extended attributes) is cleanly stubbed out on non-Darwin platforms via #if canImport(Darwin). Some FileMetadata fields (e.g. creation date, access date, owner) may return nil on Linux due to differences in swift-corelibs-foundation. The project has not been tested on Linux.
Windows: Not currently tested or verified. Compatibility is unknown.
I don't have a Linux or Windows machine to test on, but I'm happy to accept PRs that improve compatibility on other platforms.
The project is still in its early stages and is not yet open for contributions. If you have a suggestion, please open an issue to discuss it.