shift-labs-ai/markit

🖍️ Convert anything to markdown. Mark it.

Rust

1,324

210 commits

updated Aug 17, 2026

See the code

README

markit

Convert anything to markdown. PDF, DOCX, PPTX, XLSX, HTML, EPUB, Jupyter, RSS, images, audio, URLs, and more. Works as a CLI and as a library.

npm install -g @shiftlabs/markit

Quick Start

# Documents
markit report.pdf
markit document.docx
markit slides.pptx

# Data
markit data.csv
markit config.json
markit schema.yaml

# Web
markit https://example.com/article
markit https://en.wikipedia.org/wiki/Markdown

# Media
markit photo.jpg                          # EXIF metadata
markit recording.mp3                      # Audio metadata

# Text only, skipping image extraction
markit report.pdf --no-images

# Write to file
markit report.pdf -o report.md

# Pipe it
markit report.pdf | pbcopy
markit data.xlsx -q | napkin create "Imported Data"

Supported Formats

FormatExtensionsHow
PDF.pdfBuilt-in Rust engine
Word.docxBuilt-in Rust engine; headings, images, and tables
PowerPoint.pptxBuilt-in Rust engine; slides, notes, and tables
Excel.xlsxBuilt-in Rust engine; sheets become markdown tables
HTML.html .htmBuilt-in Rust engine; scripts/styles stripped
EPUB.epubBuilt-in Rust engine; spine-ordered chapters
Jupyter.ipynbBuilt-in Rust engine; cells and outputs
RSS/Atom.rss .atom .xmlBuilt-in Rust engine; dated feed items
CSV/TSV.csv .tsvBuilt-in Rust engine; markdown tables
JSON.jsonBuilt-in Rust engine; formatted code block
YAML.yaml .ymlBuilt-in Rust engine; code block
XML/SVG.xml .svgBuilt-in Rust engine; code block
Images.jpg .png .gif .webpBuilt-in Rust metadata extraction
Audio.mp3 .wav .m4a .flacBuilt-in Rust metadata extraction
ZIP.zipBuilt-in Rust recursive conversion
URLshttp:// https://Rust fetcher with markdown negotiation
Wikipedia*.wikipedia.orgBuilt-in Rust main-content extraction
Code.py .ts .go .rs ...Built-in Rust fenced code block
Plain text.txt .md .rst .logBuilt-in Rust pass-through

Benchmarks

Non-OCR PDF to Markdown: parsers that read the text layer already inside a PDF, with no OCR and no model calls. Measured on one machine, with image extraction off for every parser.

markitliteparseanydoc
olmOCR-bench score45.0%38.8%31.2%
shitty-pdf-bench text recovered100.0%83.2%91.0%
shitty-pdf-bench conversion time23.2s55.4s322.2s

olmOCR-bench is AllenAI's public benchmark. shitty-pdf-bench is ours: 40 hash-pinned public PDFs, 50,884 pages of semiconductor manuals, standards, RTL documents, scans, and malformed files.

Against the wider non-OCR field, on a 16-document subset covering 3,476 pages and 52 sampled passages:

markitliteparseanydocpypdfpdfplumbermarkitdownpymupdf4llm
Text recovered100.0%98.1%94.2%84.6%73.1%73.1%90.4%
Pages/s3,61248624770312511

Method, provenance, and per-category results are in rust/BENCHMARKS.md; the harness that reproduces them is in benchmark/.


For Agents

Every command supports --json. Raw markdown with -q.

markit report.pdf --json       # Structured output for parsing
markit report.pdf -q           # Raw markdown, nothing else
markit onboard                 # Add instructions to CLAUDE.md

SDK

markit is also a Node library. Every format uses the same bundled Rust engine as the CLI on supported macOS and Linux platforms—there is no second fallback implementation:

import { Markit } from "@shiftlabs/markit";

const markit = new Markit();
const { markdown } = await markit.convertFile("report.pdf");
const { markdown } = await markit.convertUrl("https://example.com");
const { markdown } = await markit.convert(buffer, { extension: ".docx" });

CLI Reference

markit <source>                          # Convert file or URL
markit <source> -o output.md             # Write to file
markit <source> --json                   # JSON output
markit <source> -q                       # Raw markdown only
markit <source> --no-images              # Skip image extraction
markit <source> -i ./images              # Extract images to a directory
cat file.pdf | markit -                  # Read from stdin
markit formats                           # List supported formats
markit onboard                           # Add to CLAUDE.md

Development

bun install
bun run build:native
bun run dev -- report.pdf
bun test
bun run check
cd rust && cargo test

Distribution

Releases publish @shiftlabs/markit plus six scoped native binary packages for macOS and Linux (x64/ARM64, glibc/musl). npm selects the matching binary through optionalDependencies. The former markit-ai package is a deprecated compatibility shim that re-exports this SDK.

# 1. Update the same version in package.json, rust/Cargo.toml,
#    and npm/*/package.json.
# 2. Verify locally.
bun run verify

# 3. Tag and push. GitHub Actions builds and publishes all seven packages.
git tag v0.6.0
git push origin v0.6.0

The release workflow requires an npm automation token in the repository secret NPM_TOKEN. It publishes platform packages first through napi prepublish, then @shiftlabs/markit, then the deprecated markit-ai shim, and finally creates the GitHub release.

License

MIT

shift-labs-ai/markit

🖍️ Convert anything to markdown. Mark it.

Rust

1,324

210 commits

updated Aug 17, 2026

See the code

README

markit

Convert anything to markdown. PDF, DOCX, PPTX, XLSX, HTML, EPUB, Jupyter, RSS, images, audio, URLs, and more. Works as a CLI and as a library.

npm install -g @shiftlabs/markit

Quick Start

# Documents
markit report.pdf
markit document.docx
markit slides.pptx

# Data
markit data.csv
markit config.json
markit schema.yaml

# Web
markit https://example.com/article
markit https://en.wikipedia.org/wiki/Markdown

# Media
markit photo.jpg                          # EXIF metadata
markit recording.mp3                      # Audio metadata

# Text only, skipping image extraction
markit report.pdf --no-images

# Write to file
markit report.pdf -o report.md

# Pipe it
markit report.pdf | pbcopy
markit data.xlsx -q | napkin create "Imported Data"

Supported Formats

FormatExtensionsHow
PDF.pdfBuilt-in Rust engine
Word.docxBuilt-in Rust engine; headings, images, and tables
PowerPoint.pptxBuilt-in Rust engine; slides, notes, and tables
Excel.xlsxBuilt-in Rust engine; sheets become markdown tables
HTML.html .htmBuilt-in Rust engine; scripts/styles stripped
EPUB.epubBuilt-in Rust engine; spine-ordered chapters
Jupyter.ipynbBuilt-in Rust engine; cells and outputs
RSS/Atom.rss .atom .xmlBuilt-in Rust engine; dated feed items
CSV/TSV.csv .tsvBuilt-in Rust engine; markdown tables
JSON.jsonBuilt-in Rust engine; formatted code block
YAML.yaml .ymlBuilt-in Rust engine; code block
XML/SVG.xml .svgBuilt-in Rust engine; code block
Images.jpg .png .gif .webpBuilt-in Rust metadata extraction
Audio.mp3 .wav .m4a .flacBuilt-in Rust metadata extraction
ZIP.zipBuilt-in Rust recursive conversion
URLshttp:// https://Rust fetcher with markdown negotiation
Wikipedia*.wikipedia.orgBuilt-in Rust main-content extraction
Code.py .ts .go .rs ...Built-in Rust fenced code block
Plain text.txt .md .rst .logBuilt-in Rust pass-through

Benchmarks

Non-OCR PDF to Markdown: parsers that read the text layer already inside a PDF, with no OCR and no model calls. Measured on one machine, with image extraction off for every parser.

markitliteparseanydoc
olmOCR-bench score45.0%38.8%31.2%
shitty-pdf-bench text recovered100.0%83.2%91.0%
shitty-pdf-bench conversion time23.2s55.4s322.2s

olmOCR-bench is AllenAI's public benchmark. shitty-pdf-bench is ours: 40 hash-pinned public PDFs, 50,884 pages of semiconductor manuals, standards, RTL documents, scans, and malformed files.

Against the wider non-OCR field, on a 16-document subset covering 3,476 pages and 52 sampled passages:

markitliteparseanydocpypdfpdfplumbermarkitdownpymupdf4llm
Text recovered100.0%98.1%94.2%84.6%73.1%73.1%90.4%
Pages/s3,61248624770312511

Method, provenance, and per-category results are in rust/BENCHMARKS.md; the harness that reproduces them is in benchmark/.


For Agents

Every command supports --json. Raw markdown with -q.

markit report.pdf --json       # Structured output for parsing
markit report.pdf -q           # Raw markdown, nothing else
markit onboard                 # Add instructions to CLAUDE.md

SDK

markit is also a Node library. Every format uses the same bundled Rust engine as the CLI on supported macOS and Linux platforms—there is no second fallback implementation:

import { Markit } from "@shiftlabs/markit";

const markit = new Markit();
const { markdown } = await markit.convertFile("report.pdf");
const { markdown } = await markit.convertUrl("https://example.com");
const { markdown } = await markit.convert(buffer, { extension: ".docx" });

CLI Reference

markit <source>                          # Convert file or URL
markit <source> -o output.md             # Write to file
markit <source> --json                   # JSON output
markit <source> -q                       # Raw markdown only
markit <source> --no-images              # Skip image extraction
markit <source> -i ./images              # Extract images to a directory
cat file.pdf | markit -                  # Read from stdin
markit formats                           # List supported formats
markit onboard                           # Add to CLAUDE.md

Development

bun install
bun run build:native
bun run dev -- report.pdf
bun test
bun run check
cd rust && cargo test

Distribution

Releases publish @shiftlabs/markit plus six scoped native binary packages for macOS and Linux (x64/ARM64, glibc/musl). npm selects the matching binary through optionalDependencies. The former markit-ai package is a deprecated compatibility shim that re-exports this SDK.

# 1. Update the same version in package.json, rust/Cargo.toml,
#    and npm/*/package.json.
# 2. Verify locally.
bun run verify

# 3. Tag and push. GitHub Actions builds and publishes all seven packages.
git tag v0.6.0
git push origin v0.6.0

The release workflow requires an npm automation token in the repository secret NPM_TOKEN. It publishes platform packages first through napi prepublish, then @shiftlabs/markit, then the deprecated markit-ai shim, and finally creates the GitHub release.

License

MIT

Significant stargazers

(top 24 of 35)

Matteo Collina

11,404 followers · starred Apr 2026

Peter Steinberger

53,314 followers · starred Mar 2026

Cosimo Lupo

456 followers · starred Mar 2026

Nico Bailon

2,102 followers · starred Mar 2026