Skip to content

DandyLyons/md-utils

Repository files navigation

md-utils

Certified Shovelware

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.

  1. MarkdownUtilities — A Swift library for parsing and manipulating Markdown content.
  2. md-utils — A command-line tool, built on top of MarkdownUtilities, for performing operations on Markdown files.
  3. markdown-utilities — An Agent Skill for AI coding assistants, built on top of the md-utils CLI.

Agent Skill Installation

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-utils CLI first (see CLI Installation below).

Option A: skills.sh (Recommended)

npx skills add https://github.com/DandyLyons/md-utils --skill markdown-utilities

Visit the skills.sh page for more details.

Option B: Claude Code Plugin

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.


CLI Installation

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>

From Source

git clone https://github.com/DandyLyons/md-utils.git
cd md-utils
swift build -c release
# Binary will be at .build/release/md-utils

Library Installation

Swift Package Manager

Add 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"),
    ]
),

Status

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.

Features

Implemented

  • 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

Planned

  • Link validation (URL/reference link checking)
  • Markdown flavor validation (CommonMark, GFM, Obsidian)
  • Additional format conversions (HTML, RTF, XML)
  • File metadata writing

CLI Usage

Build and run with Swift Package Manager:

swift run md-utils <command> [options]

Examples

# 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.md

Run swift run md-utils --help or swift run md-utils <command> --help for full usage details.

Project Configuration

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 validate

Paths 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 for md-utils schema validate <rule-name>.
  • schemaRules[].schema: Schema file, resolved relative to schemaDirectory.
  • schemaRules[].frontmatterRequired: If true, matched files without frontmatter fail; if false, 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-schema

schema 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.

Architecture

  • Swift 6.2 or later
  • All testing uses the native Swift Testing framework

Dependencies

Platform Compatibility

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.

Contributing

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.

About

Markdown Utilities.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages