edgeparse

Library Listed

EdgeParse core library — PDF parsing and structured data extraction

Downloads
6,764
Dependents
2
Stars
155
Forks
20
Contributors
2
Commits
135
Latest release
0.3.2 ·

About

From the project README ·

Fastest PDF extraction engine. Rust-native. No ML stack required for born-digital PDFs; optional in-browser OCR for image tables.

Extract Markdown, JSON (with bounding boxes), and HTML from any born-digital PDF — deterministically, in milliseconds, on CPU.

  • How accurate is it? — Two labeled boards (2026-10-01, Apple M4 Max, 200 docs):
    • Official odl-bench (mean(NID,TEDS,MHS)): EdgeParse hybrid 0.900 (leads every finished metric), deterministic 0.857, WASM 0.854.
    • EdgeParse harness: deterministic 0.782 overall at ~0.019 s/doc. Never claim a win for engines not finished (Marker, MinerU, Nutrient, Unstructured partial). Benchmark details
  • How fast? — ~0.02 s/doc deterministic on Apple M4 Max for the 200-document corpus. Hybrid mode is slower (~0.81 s/doc) when pages route to a local Docling Fast backend.
  • Does it need a GPU or Java? — No. No JVM, no GPU, no Python runtime for the CLI. Born-digital PDFs need no OCR models; optional PP-OCRv6 runs in-browser or on Node for image tables. Single ~15 MB binary.
  • RAG / LLM pipelines? — Yes. Outputs structured Markdown for chunking, JSON with bounding boxes for citations, preserves reading order across multi-column layouts. See integration examples
Read the full README

Available as a Rust library, CLI binary, Python package, Node.js package, WebAssembly module, and @edgeparse/web observable Web SDK.


Table of Contents

  • Get Started in 30 Seconds
  • What Problems Does This Solve?
  • Release Channels
  • Benchmark
  • Capability Matrix
  • Installation
  • Python SDK
  • Node.js SDK
  • WebAssembly SDK
  • CLI Reference
  • Output Formats
  • RAG / LLM Integration
  • Agent Skill
  • Architecture
  • FAQ
  • Tutorials
  • Documentation
  • Project Layout
  • Contributing
  • License

Get Started in 30 Seconds

Python (Python 3.9+):

pip install edgeparse
import edgeparse

# Markdown — ready for LLM context or RAG chunking
md = edgeparse.convert("report.pdf", format="markdown")

# JSON with bounding boxes — for citations and element-level control
data = edgeparse.convert("report.pdf", format="json")

CLI (Rust 1.85+):

cargo install edgeparse-cli
edgeparse report.pdf --format markdown --output-dir output/

Node.js (Node 18+):

npm install edgeparse
import { convert } from 'edgeparse';
const md = convert('report.pdf', { format: 'markdown' });

Release Channels

Tagged releases publish every supported distribution target through GitHub Actions:

ChannelArtifactInstall / Pull
Rust cratespdf-cos, edgeparse-core, edgeparse-clicargo install edgeparse-cli
Python SDKedgeparse wheels + sdistpip install edgeparse
Node.js SDKedgeparse + 5 platform addonsnpm install edgeparse
WebAssembly SDKedgeparse-wasmnpm install edgeparse-wasm
CLI binariesGitHub Release archives for macOS, Linux, WindowsGitHub Releases
Homebrewraphaelmansuy/edgeparse tapbrew tap raphaelmansuy/edgeparse && brew install edgeparse
ContainersGHCR + Docker Hub multi-arch imagesdocker pull ghcr.io/raphaelmansuy/edgeparse:0.2.1

Release automation and registry details: docs/07-cicd-publishing.md


What Problems Does This Solve?

ProblemEdgeParse SolutionStatus
PDF text loses reading order in multi-column layoutsXY-Cut++ algorithm preserves correct reading sequence across columns, sidebars, and mixed layouts✅ Shipped
Table extraction is broken (merged cells, borderless tables)Ruling-line table detection + borderless cluster method; --table-method cluster for complex cases✅ Shipped
OCR/ML tools add 500 MB+ of dependencies to a simple PDF pipelineZero GPU, zero OCR models, zero JVM — single 15 MB binary, pure Rust✅ Shipped
Heading hierarchy is lost (all text looks the same)Font-metric + outline/section-number heading levels; MHS score 0.552 on the current benchmark✅ Shipped
PDFs can carry hidden prompt injection payloadsAI safety filters: hidden text, off-page content, tiny-text, invisible OCG layers detected and stripped✅ Shipped
Need bounding boxes to cite sources in RAG answersEvery element (paragraph, heading, table, image) has [left, bottom, right, top] coordinates in PDF points✅ Shipped
In-browser PDF parsing uploads data to a serverWebAssembly build — full Rust engine in the browser, PDF data never leaves the device✅ Shipped

Benchmark

Evaluated on 200 real-world PDFs — academic papers, financial reports, multi-column layouts, complex tables, mixed-language documents — running on Apple M4 Max.

Current comparison set

Measured 2026-10-01 on Apple M4 Max, 200 documents, EdgeParse harness (benchmark/). Marker / MinerU / Unstructured hi_res were not finished in this run (install/time). Nutrient and Hancom were out of scope.

EngineNID ↑TEDS ↑MHS ↑PBF ↑TQS ↑TD F1 ↑Speed ↓Overall ↑
EdgeParse0.8860.5640.5520.5620.9170.897~0.02 s/doc0.782
EdgeParse [hybrid]0.8630.6030.5060.5460.9090.9410.810 s/doc0.767
Docling0.8750.5680.4500.5630.9160.9032.332 s/doc0.758
OpenDataLoader0.8730.3200.4410.5360.9170.6210.022 s/doc0.733
PyMuPDF4LLM0.8600.5090.4110.5030.9120.8570.640 s/doc0.732
OpenDataLoader [hybrid]0.8690.4220.4110.5310.9040.9412.537 s/doc0.731
MarkItDown0.8080.1930.0010.3620.8610.5580.189 s/doc0.564

Deterministic EdgeParse leads overall. Hybrid mode routes table / sparse-image pages to a local Docling Fast server (opendataloader-pdf-hybrid) and leads TEDS and table-detection F1 while still beating every finished third-party engine on overall score.

When to choose what:

Use caseRecommendation
Born-digital PDFs, latency matters, production deploymentEdgeParse — best overall accuracy/speed, zero ML stack
Complex tables, local Docling Fast availableEdgeParse --hybrid docling-fast — best TEDS on this board
Scanned documents requiring full OCRDedicated OCR pipeline or hybrid with OCR-enabled backend
Metrics
MetricWhat it measures
NIDReading order accuracy — normalised index distance
TEDSTable structure accuracy — tree-edit distance vs. ground truth
MHSHeading hierarchy accuracy
PBFParagraph boundary F1
TQSText quality score
TD F1Table detection F1
OverallNormalized aggregate benchmark score
SpeedWall-clock seconds per document (full pipeline, 200 docs, parallel)
Running the benchmark
cargo build --release
cd benchmark
uv sync
uv run python run.py          # EdgeParse on all 200 docs
uv run python compare_all.py  # Compare against 9 engines

Results → benchmark/prediction/edgeparse/ · HTML reports → benchmark/reports/

Regression thresholds

benchmark/thresholds.json defines minimum acceptable scores for CI:

{
  "nid": 0.85,
  "teds": 0.40,
  "mhs": 0.55,
  "table_detection_f1": 0.55,
  "elapsed_per_doc": 2.0
}

Capability Matrix

CapabilityAvailableNotes
Extraction
Text with correct reading order✅XY-Cut++ across columns and sidebars
Bounding boxes for every element✅[left, bottom, right, top] in PDF points
Table extraction — ruling-line borders✅Default mode
Table extraction — borderless/cluster✅--table-method cluster
Heading hierarchy detection✅Numbered + unnumbered, all levels
List detection (numbered, bulleted, nested)✅
Image extraction with coordinates✅PNG or JPEG, embedded or external
Header / footer / watermark filtering✅
Multi-column layout support✅
CMap / ToUnicode font decoding✅Handles non-standard encodings
Tagged PDF structure tree✅--use-struct-tree preserves author intent
Safety
Hidden text filtering✅Prompt injection protection
Off-page content filtering✅
Tiny-text / invisible OCG layer filtering✅
PII sanitization✅--sanitize flag
Output
Markdown (GFM tables)✅
JSON with bounding boxes✅
HTML5✅
Plain text (reading order preserved)✅
SDKs
Python (PyO3 native extension)✅Python 3.9+, pre-built wheels
Node.js (NAPI-RS native addon)✅Node 18+, pre-built addons
WebAssembly✅In-browser, no server required
Rust library✅edgeparse-core crate
CLI binary✅edgeparse-cli on crates.io
Runtime
GPU required❌ NoCPU only
JVM required❌ NoPure Rust
OCR models required❌ NoBorn-digital PDFs only
Parallel processing✅Rayon per-page parallelism
Deterministic / reproducible✅Same input → same output, always

Installation

Python
pip install edgeparse

Python 3.9+. Pre-built wheels for macOS (arm64, x64), Linux (x64, arm64), Windows (x64).

CLI
cargo install edgeparse-cli

Requires Rust 1.85+.

Rust library
[dependencies]
edgeparse-core = "0.2.1"

Docs: docs.rs/edgeparse-core · docs.rs/edgeparse-cli

Node.js
npm install edgeparse

Node 18+. Pre-built native addons for macOS (arm64, x64), Linux (x64, arm64), Windows (x64).

Build from source
git clone https://github.com/raphaelmansuy/edgeparse.git
cd edgeparse
cargo build --release
# Binary: target/release/edgeparse
System requirements
  • macOS 12+, Linux (glibc 2.17+), or Windows 10+
  • ~15 MB binary (stripped release build)
  • No Java, no Python (for the CLI), no GPU

Python SDK

Package: edgeparse · Requires: Python 3.9+ · Source: sdks/python/

edgeparse.convert()
def convert(
    input_path: str | Path,
    *,
    format: str = "markdown",       # "markdown", "json", "html", "text"
    pages: str | None = None,        # e.g. "1,3,5-7"
    password: str | None = None,
    reading_order: str = "xycut",   # "xycut" or "off"
    table_method: str = "default",  # "default" or "cluster"
    image_output: str = "off",      # "off", "embedded", "external"
) -> str: ...
edgeparse.convert_file()
def convert_file(
    input_path: str | Path,
    output_dir: str | Path = "output",
    *,
    format: str = "markdown",
    pages: str | None = None,
    password: str | None = None,
) -> str: ...  # returns output file path
Examples
import edgeparse

# Basic Markdown extraction
md = edgeparse.convert("report.pdf", format="markdown")

# JSON with bounding boxes
json_str = edgeparse.convert("report.pdf", format="json")

# Password-protected, specific pages, borderless tables
md = edgeparse.convert(
    "secure.pdf",
    format="markdown",
    pages="1,3,5-7",
    password="secret",
    reading_order="xycut",
    table_method="cluster",
)

# Write output file  
out_path = edgeparse.convert_file("report.pdf", output_dir="output/", format="markdown")
CLI entry point (Python package)
edgeparse report.pdf -f markdown -o output/
edgeparse *.pdf --format json --output-dir out/ --pages "1-3"

Node.js SDK

Package: edgeparse · Requires: Node.js 18+ · Source: sdks/node/

convert()
import { convert } from 'edgeparse';

// Markdown
const md = convert('report.pdf', { format: 'markdown' });

// JSON with bounding boxes
const json = convert('report.pdf', { format: 'json' });

// With options
const result = convert('report.pdf', {
  format: 'markdown',
  pages: '1-5',
  readingOrder: 'xycut',
  tableMethod: 'cluster',
});
ConvertOptions
interface ConvertOptions {
  format?: 'markdown' | 'json' | 'html' | 'text';  // default: "markdown"
  pages?: string;         // e.g. "1,3,5-7"
  password?: string;
  readingOrder?: 'xycut' | 'off';        // default: "xycut"
  tableMethod?: 'default' | 'cluster';   // default: "default"
  imageOutput?: 'off' | 'embedded' | 'external';  // default: "off"
}
CLI (npm)
npx edgeparse report.pdf -f markdown -o output.md
npx edgeparse report.pdf --format json --pages "1-5"

WebAssembly SDK

EdgeParse compiles to WebAssembly — client-side PDF extraction in any modern browser with no server, no uploads, and no backend infrastructure.

  • Same Rust engine, identical output to CLI/Python/Node
  • PDF data never leaves the user's device (privacy by design)
  • Works offline after initial WASM load (~4 MB cached)
  • Optional PP-OCRv6 for image-embedded tables via @edgeparse/web (consent + OPFS/Cache)
  • Zero infrastructure cost — static hosting only
Preferred: @edgeparse/web (observable SDK)
npm install @edgeparse/web edgeparse-wasm
import { EdgeParse } from '@edgeparse/web';

const ep = await EdgeParse.create({
  models: 'lazy',
  ocr: 'small',
  onBeforeDownload: async (m) =>
    confirm(`Download OCR model ${m.id} (~${(m.bytes / 1e6).toFixed(1)} MB)?`),
});

const job = ep.parse(pdfBytes, { format: 'markdown' });
job.on('progress', (p) => console.log(p.label, p.fraction));
const { markdown, quality, warnings } = await job.result;

Docs: quick-start Web SDK · OCR models · API

Low-level WASM
import init, { convert_to_string, ParseSession } from 'edgeparse-wasm';

await init();

const bytes = new Uint8Array(await file.arrayBuffer());
const markdown = convert_to_string(bytes, 'markdown');
Live demo

edgeparse.com/demo/ — drag-and-drop any PDF, all processing runs locally in your browser.

Build from source
make wasm-build          # --target web → crates/edgeparse-wasm/pkg/
make wasm-build-node     # --target nodejs → pkg-node/ (bench)

Full documentation: docs/09-wasm-sdk.md


CLI Reference

edgeparse [OPTIONS] <PDF_FILE>...
Core options
FlagDefaultDescription
-o, --output-dir <DIR>—Write output files to this directory
-f, --format <FMT>jsonOutput format(s), comma-separated
-p, --password <PW>—Password for encrypted PDFs
--pages <RANGE>—Page range e.g. "1,3,5-7"
-q, --quietfalseSuppress log output
Output format values
ValueDescription
jsonStructured JSON with bounding boxes and element types (default)
markdownStandard Markdown with GFM tables
markdown-with-htmlMarkdown with HTML table fallback for complex tables
markdown-with-imagesMarkdown with embedded or linked images
htmlFull HTML5 document with semantic elements
textPlain UTF-8 text, reading order preserved

Multiple formats: --format markdown,json

Layout & extraction options
FlagDefaultDescription
--reading-order <ALGO>xycutReading order: xycut or off
--table-method <METHOD>defaultTable detection: default (ruling lines) or cluster (borderless)
--keep-line-breaksfalsePreserve original line breaks within paragraphs
--use-struct-treefalseUse tagged PDF structure tree when available
--include-header-footerfalseInclude headers and footers in output
--sanitizefalseEnable PII sanitization
--replace-invalid-chars <CH>" "Replacement for invalid Unicode characters
Image options
FlagDefaultDescription
--image-output <MODE>externaloff, embedded (base64), or external (files)
--image-format <FMT>pngpng or jpeg
--image-dir <DIR>—Directory for extracted image files
Separator options
FlagDescription
--markdown-page-separator <STR>String inserted between Markdown pages
--text-page-separator <STR>String inserted between plain-text pages
--html-page-separator <STR>String inserted between HTML pages
Content safety options
FlagDefaultDescription
--content-safety-off <FLAGS>—Disable safety filters: all, hidden-text, off-page, tiny, hidden-ocg
Hybrid backend options
FlagDefaultDescription
--hybrid <BACKEND>offHybrid backend: off or docling-fast
--hybrid-mode <MODE>autoTriage mode: auto or full
--hybrid-url <URL>—Hybrid backend service URL
--hybrid-timeout <MS>30000Timeout in milliseconds
--hybrid-fallbackfalseFall back to local extraction on hybrid error

Output Formats

FormatFlag valueBest for
JSON with bounding boxesjsonRAG citations, element-level processing, source highlighting
Markdown (GFM)markdownLLM context windows, chunking pipelines, readable output
Markdown + HTML tablesmarkdown-with-htmlComplex tables that don't render well in pure Markdown
Markdown + imagesmarkdown-with-imagesDocuments where figures matter
HTML5htmlWeb display, accessibility pipelines
Plain texttextKeyword search, simple NLP, legacy pipelines

Combine formats: --format markdown,json

JSON output example
{
  "type": "heading",
  "id": 42,
  "level": "Title",
  "page number": 1,
  "bounding box": [72.0, 700.0, 540.0, 730.0],
  "heading level": 1,
  "font": "Helvetica-Bold",
  "font size": 24.0,
  "content": "Introduction"
}
FieldDescription
typeElement type: heading, paragraph, table, list, image, caption
idUnique identifier for cross-referencing
page number1-indexed page reference
bounding box[left, bottom, right, top] in PDF points (72 pt = 1 inch)
heading levelHeading depth (1+)
contentExtracted text

RAG / LLM Integration

EdgeParse is designed for AI pipelines. Every element has a bounding box and page number, so you can cite exact sources in answers.

Extract Markdown for chunking
import edgeparse

md = edgeparse.convert("report.pdf", format="markdown")

# Feed directly into an LLM
response = llm.invoke(f"Summarize this document:\n\n{md}")
Extract JSON for source citations
import json, edgeparse

data = json.loads(edgeparse.convert("report.pdf", format="json"))

for element in data["kids"]:
    if element["type"] == "paragraph":
        # element["bounding box"] → highlight location in original PDF
        # element["page number"] → link back to source page
        print(f"p.{element['page number']}: {element['content'][:80]}")
LangChain integration

EdgeParse has no official LangChain loader yet, but integrates trivially:

from langchain.schema import Document
import edgeparse, json

def load_pdf(path: str) -> list[Document]:
    data = json.loads(edgeparse.convert(path, format="json"))
    docs = []
    for el in data["kids"]:
        if el["type"] in ("paragraph", "heading"):
            docs.append(Document(
                page_content=el["content"],
                metadata={
                    "source": path,
                    "page": el["page number"],
                    "bbox": el["bounding box"],
                    "type": el["type"],
                }
            ))
    return docs
LlamaIndex integration
from llama_index.core import Document
import edgeparse, json

def edgeparse_reader(path: str) -> list[Document]:
    data = json.loads(edgeparse.convert(path, format="json"))
    return [
        Document(
            text=el["content"],
            metadata={"page": el["page number"], "source": path}
        )
        for el in data["kids"]
        if el.get("content")
    ]
Which output format for which use case?
Use caseRecommended formatWhy
Feed PDF to LLMmarkdownClean structure, fits in context window
RAG with source citationsjsonBounding boxes enable "click-to-source" UX
Semantic chunking by sectionmarkdownHeadings make natural chunk boundaries
Element-level filteringjsonFilter by type, page number, heading level
Web displayhtmlStyled output with semantic elements

Agent Skill

EdgeParse ships as a Claude agent skill — a structured description that teaches Claude (and any compatible AI agent) how to extract PDF content on behalf of users.

# Add the EdgeParse skill to your agent environment
npx skills add raphaelmansuy/edgeparse --skill edgeparse

# Install the Python package
pip install edgeparse

The npx skills add command registers the skill in skills-lock.json:

{
  "version": 1,
  "skills": {
    "edgeparse": {
      "source": "raphaelmansuy/edgeparse",
      "sourceType": "github"
    }
  }
}

Once installed, the agent reads skills/edgeparse/SKILL.md and knows when to call edgeparse.convert(), which format to use for different tasks, and how to handle edge cases like encrypted PDFs, borderless tables, and multi-column layouts.

See docs/08-agent-skill.md for the full integration guide (LangChain, LlamaIndex, MCP, CrewAI patterns).


Architecture

Crate structure
edgeparse/
├── crates/
│   ├── pdf-cos/            # Low-level PDF object model (fork of lopdf 0.39)
│   ├── edgeparse-core/     # Core extraction engine (~90 source files)
│   │   └── src/
│   │       ├── api/        # ProcessingConfig, FilterConfig, BatchResult
│   │       ├── pdf/        # Loader, content stream parser, font/CMap decoding
│   │       ├── models/     # ContentElement, BoundingBox, TextChunk, PdfDocument
│   │       ├── pipeline/   # 20-stage orchestrator + Rayon parallel helpers
│   │       ├── output/     # Renderers: JSON, Markdown, HTML, text, CSV
│   │       ├── tagged/     # Tagged-PDF structure tree → McidMap
│   │       └── utils/      # XY-Cut++ algorithm, sanitizer, layout analysis
│   ├── edgeparse-cli/      # CLI binary (clap derive, 25+ flags)
│   ├── edgeparse-python/   # PyO3 native extension
│   └── edgeparse-node/     # NAPI-RS native addon
└── sdks/
    ├── python/             # Python packaging (maturin, pyproject.toml)
    └── node/               # npm packaging (TypeScript wrapper, tsup)
Processing pipeline (20 stages)
PDF file
    │
    ▼
pdf-cos                   ← xref parsing, object graph, encrypted streams
    │
    ▼
edgeparse-core::pdf       ← page tree, content stream operators, font decoding,
    │                       CMap/ToUnicode, image extraction, tagged PDF
    ▼
edgeparse-core::pipeline  ← 20 sequential/parallel stages:
    │  [page range] → [watermark] → [filter] → [table borders] →
    │  [cell assignment] → [boxed headings] → [column detection] →
    │  [TextLine assembly] → [TextBlock grouping] → [table clustering] →
    │  [header/footer] → [list detection] → [paragraph] → [figure] →
    │  [heading classification] → [XY-Cut++ reading order] →
    │  [list pass 2] → [caption/footnote/TOC] → [cross-page tables] →
    │  [element nesting] → [final reading order] → [sanitize]
    ▼
edgeparse-core::output    ← render to JSON / Markdown / HTML / text

Stages marked par_map_pages run in parallel via Rayon; cross-page stages run sequentially.


FAQ

What is the best PDF parser for RAG?

For RAG pipelines, you need a parser that preserves document structure, maintains correct reading order, and provides element coordinates for citations. EdgeParse outputs structured JSON with bounding boxes for every element, handles multi-column layouts with XY-Cut++, and runs locally on CPU without a GPU or JVM. On the current 200-document benchmark it leads the finished comparison set in overall score (0.782) with ~0.02 s/doc deterministic latency. See RAG integration examples.

How do I cite PDF sources in RAG answers?

Every element in JSON output includes a bounding box ([left, bottom, right, top] in PDF points, 72 pt = 1 inch) and page number. Map the source chunk back to its bounding box to highlight the exact location in the original PDF — enabling "click-to-source" UX. No other non-OCR open-source parser provides bounding boxes for every element by default.

How do I extract tables from PDF?

EdgeParse detects tables using border (ruling-line) analysis by default. For complex or borderless tables, add --table-method cluster (CLI) or table_method="cluster" (Python). This uses a text-clustering algorithm to detect table structure without visible borders. On the current benchmark it reaches 0.596 TEDS and 0.901 table-detection F1, both best in the published comparison set.

Does it work without sending data to the cloud?

Yes. EdgeParse runs 100% locally. No API calls, no data transmission — your documents never leave your environment. The WebAssembly SDK also runs entirely in the browser: the PDF is processed client-side and never uploaded to any server. Ideal for legal, healthcare, and financial documents.

Does it handle multi-column layouts?

Yes. XY-Cut++ reading order analysis correctly sequences text across multi-column pages, sidebars, and mixed layouts. This works without any configuration change; it is the default reading order algorithm.

Does it need a GPU or Java?

No. EdgeParse is a pure Rust implementation. It requires no JVM, no GPU, no OCR models, and no Python runtime for the CLI binary. The CLI binary is ~15 MB stripped. On Apple M4 Max, it processes the 200-document benchmark corpus in about 12.7 seconds total.

How does it compare to Docling, MinerU, and Marker?
vs.EdgeParse advantageTradeoff
OpenDataLoaderFaster deterministic path with stronger table structure and heading recoveryOpenDataLoader remains close on text quality; use EdgeParse hybrid for complex tables
IBM DoclingFaster and higher overall score in the current harness snapshotDocling remains useful as the hybrid backend for hard table pages
MarkerFaster and materially better on every published metric in this benchmark familyMarker supports scanned PDFs via Surya OCR
PyMuPDF4LLMFaster with stronger tables, headings, and reading orderPyMuPDF4LLM is simpler if you only need lightweight text extraction
Does it support scanned PDFs?

Not directly — EdgeParse is built for born-digital PDFs with embedded fonts. It does not include an OCR engine. For scanned documents, use EdgeParse's hybrid backend option (--hybrid docling-fast) which routes complex pages to a Docling-Fast backend running locally.

What does "deterministic" mean?

Same input PDF → same output, every time. No stochastic models, no floating-point non-determinism from ML inference. This makes EdgeParse safe to use in CI pipelines, regression tests, and compliance workflows where reproducibility is required.

How do I chunk PDFs for semantic search?

Use format="markdown". EdgeParse preserves heading hierarchy and table structure in Markdown output — headings make natural chunk boundaries for RecursiveCharacterTextSplitter (LangChain) or heading-based splitters. For element-level control, use format="json" and split on heading level boundaries or page number changes.

Does the Python SDK run on Windows?

Yes. Pre-built wheels are available for Windows (x64). The Python package installs from PyPI with no compilation needed:

pip install edgeparse

Tutorials

Step-by-step guides with working examples live in tutorials/:

TutorialDescription
tutorials/01-cli.mdAll CLI flags with working examples and output samples
tutorials/02-python-sdk.mdpip install edgeparse — full API, batch processing, JSON parsing
tutorials/03-nodejs-sdk.mdnpm install edgeparse — TypeScript, CJS, and worker threads
tutorials/04-rust-library.mdedgeparse-core in your Rust project — config, models, Rayon
tutorials/05-output-formats.mdJSON schema, bounding boxes, Markdown variants, HTML, plain text

Documentation

Technical documentation lives in docs/:

DocumentDescription
docs/00-overview.mdProject overview, goals, and design philosophy
docs/01-architecture.mdCrate structure, module map, data-flow diagram
docs/02-pipeline.mdAll 20 pipeline stages with ASCII diagrams
docs/03-data-model.mdType hierarchy: ContentElement, BoundingBox, PdfDocument
docs/04-pdf-extraction.mdPDF loader, chunk parser, font/CMap decoding
docs/05-output-formats.mdJSON schema, Markdown renderer, HTML/text/CSV output
docs/06-sdk-integration.mdCLI flag reference, Python SDK API, Node.js SDK API, Batch API
docs/07-cicd-publishing.mdCI/CD publishing pipeline — how it works and how to configure it
docs/08-agent-skill.mdEdgeParse agent skill — npx skills add, SKILL.md structure, SDK patterns
docs/09-wasm-sdk.mdWebAssembly SDK — objectives, API, use cases, build instructions

Project Layout

edgeparse/
├── LICENSE
├── CONTRIBUTING.md
├── README.md
├── Cargo.toml               # Rust workspace (5 members)
├── Cargo.lock
│
├── crates/
│   ├── pdf-cos/             # lopdf 0.39 fork — low-level PDF object model
│   ├── edgeparse-core/      # Core extraction engine (~90 source files)
│   ├── edgeparse-cli/       # CLI binary (clap, 25+ flags)
│   ├── edgeparse-wasm/      # WebAssembly build for browsers (wasm-bindgen)
│   ├── edgeparse-python/    # PyO3 native Python extension
│   └── edgeparse-node/      # NAPI-RS native Node.js addon
│
├── sdks/
│   ├── python/              # Python wheel packaging (maturin + pyproject.toml)
│   │   └── edgeparse/       # Pure-Python wrapper + CLI entry point
│   └── node/                # npm packaging (TypeScript + tsup + vitest)
│       └── src/             # index.ts, types.ts, cli.ts
│
├── benchmark/               # Evaluation suite
│   ├── run.py               # Benchmark runner (EdgeParse)
│   ├── compare_all.py       # Multi-engine comparison (9 engines)
│   ├── pyproject.toml
│   ├── thresholds.json      # Regression thresholds
│   ├── pdfs/                # Benchmark PDFs (200 docs)
│   ├── ground-truth/        # Reference Markdown and JSON annotations
│   ├── prediction/          # Per-engine output directories
│   ├── reports/             # HTML benchmark reports
│   └── src/                 # Python evaluators and engine adapters
│
├── docs/                    # Technical documentation (Markdown)
│
├── demo/                    # Interactive WASM demo (Vite + TypeScript)
│   └── src/                 # Demo application source
│
├── examples/
│   └── pdf/                 # Sample PDFs for quick testing
│       ├── lorem.pdf
│       ├── 1901.03003.pdf   # Academic paper (multi-column)
│       ├── 2408.02509v1.pdf # Academic paper
│       └── chinese_scan.pdf # CJK + scan example
│
├── benches/                 # Rust micro-benchmarks (criterion)
├── docker/                  # Dockerfile and Dockerfile.dev
├── scripts/                 # bench.sh, publish-crates.sh
└── tests/
    └── fixtures/            # Rust integration test fixtures

Contributing

See CONTRIBUTING.md. In short:

  1. Fork, branch from main
  2. cargo fmt && cargo clippy -- -D warnings
  3. Run the benchmark to check for regressions: cd benchmark && uv run python run.py --engine edgeparse
  4. Open a PR

Star History

License

EdgeParse is licensed under the Apache License 2.0. See LICENSE for the full text.

The crates/pdf-cos/ directory is a fork of lopdf (MIT/Apache-2.0 dual-licensed).
Benchmark PDF documents (benchmark/pdfs/) are sourced from publicly available documents and are used solely for evaluation purposes.

Runs on
GPU support unknown
What shows it
  • no dependency or feature matches a backend row
Native code
None found
  • No native code found
Python bindings
No Python binding crate found
License
Apache-2.0

Compare with similar projects

Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.

edgeparse beside the projects that share a topic with it
ProjectDownloadsDependentsStarsLatest releaseRuns on (GPU)Native codeLicense
edgeparse This page Listed

EdgeParse core library — PDF parsing and structured data extraction

6,764 downloads over 30 days 2 155 0.3.2 GPU support unknown No native code found Apache-2.0
pdf_oxide Featured

The fastest Rust PDF library — 0.8ms mean, 5× faster than the industry leaders, 100% pass rate on 3,830 real-world PDFs. Text extraction, Markdown/HTML conversion, PDF creation and editing.

Python bindings

Also in Build LLM apps and agents.

316,729 downloads over 30 days 30 1,180 0.3.78 GPU support unknown Binds native code: aws-lc-rs (feature fips), lcms2-sys (feature icc-lcms2), ort-sys (feature gpu) Apache-2.0 OR MIT
oxidizePdf App Listed

Pure Rust PDF library for AI/RAG: structure-aware chunking, no ML, no C deps.

Also in Build LLM apps and agents.

62,285 downloads over 30 days Not applicable 194 5.5.7 GPU support unknown No native code found MIT

High-performance document intelligence library for Rust. Extract text, metadata, and structured data from PDFs, Office documents, images, and 91+ formats and 248 programming languages via tree-sitter code intelligence with async/sync APIs.

Also in Documents and OCR.

54,366 downloads over 30 days 7 21 4.10.4 GPU support unknown Binds native code: kreuzberg_tesseract, clipper-sys, ort-sys, tree-sitter (feature tree-sitter), tree-sitter-language (feature tree-sitter). Build uses a native toolchain: pkg-config, cc (feature build-tesseract), cmake (feature build-tesseract) MIT
serde_toon Listed

A Serde-compatible TOON (Token-Oriented Object Notation) serialization library

Also in Build LLM apps and agents.

2,384 downloads over 30 days 4 13 0.3.0 GPU support unknown No native code found Apache-2.0 OR MIT
axp App Listed

An open protocol that gives AI agents a secure, sandboxed place to run code and use tools — with lean context usage. AXP works alongside MCP

Also in Build LLM apps and agents.

Not measured Not applicable 3 Not measured Not measured Not measured Apache-2.0
xberg New

High-performance document intelligence library for Rust. Extract text, metadata, and structured data from PDFs, Office documents, images, and 107 formats and 371 programming languages via tree-sitter code intelligence with async/sync APIs.

Also in Documents and OCR.

26,095 downloads over 30 days 2 9,565 1.3.10 CUDA, Metal Binds native code: libheif-sys, libz-sys, xberg_libwpd, xberg_tesseract, clipper-sys and 4 more. Build uses a native toolchain: cc, bindgen (feature bindings), cmake (feature build-tesseract), pkg-config (feature dynamic-linking), vcpkg (feature dynamic-linking) MIT
Why ListedNo archive, New or Featured rule places it, so it is Listed.

What it lacks for Featured

  • It has 1 active dependents and 1 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 155 stars, 20 forks and 2 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.

What else the check found

Exact rules: Listed, Featured library. The check on applied thresholds version 9.

Every rule outcome, as the check records it
  • expected-interval: version 0.3.2 base 300, raised to the 365-day floor: E = 365 days
  • dormancy: last activity 2026-10-09, 31 days ago, E = 365: active
  • rot: deprecated requirement `ttf-parser (RUSTSEC-2026-0192, https://rustsec.org/advisories/RUSTSEC-2026-0192.html)`
  • featured: not featured: active_users 1 < 11 and new_adopters 1 < 9 and repository route stars 155 (needs 4539), forks 20 (needs 434), contributors 2 (needs 79)
  • listed: listed: no archive, new or featured rule applies
Crates2 crates

Measurements and sources

Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.

Sources6 sources
Adoption1 active dependents, 1 new dependents in 365 days1 not measured
Adoption measurements
SignalValueSourceFetchedCounts
Active dependents1crates.io database dumpYes
New dependents (365 days)1crates.io database dumpYes
Peak active dependents1crates.io database dumpYes
Active dependents as a share of the peak1crates.io database dumpYes
Binary downloads per releaseNot measuredYes
MaintenanceLatest human commit: 31 days ago3 not measured
Maintenance measurements
SignalValueSourceFetchedCounts
Latest human commit2026-10-09GitHub repositoryYes
Latest release2026-10-02crates.io database dumpYes
First release2026-03-23crates.io database dumpYes
Latest version0.3.2crates.io database dumpYes
Days the oldest outside issue waits for a reply229GitHub repositoryYes
Maintainer replies over 365 days7GitHub repositoryYes
Repository archivedfalseGitHub repositoryYes
Repository gonefalseGitHub repositoryYes
Release commit or manifest in the repotruecrates.io packageYes
Published docstruecrates.io database dumpYes
Latest release fails cargo checkNot measuredYes
Build check dateNot measuredYes
Build check toolchainNot measuredYes
SecurityUnpatched vulnerabilities: none
Security measurements
SignalValueSourceFetchedCounts
Unpatched vulnerabilities past the grace windownoneRustSec advisory databaseYes
RustSec unmaintained advisorynoneRustSec advisory databaseYes
Deprecation noticenonecrates.io database dumpYes
Deprecated requirementttf-parser (RUSTSEC-2026-0192, https://rustsec.org/advisories/RUSTSEC-2026-0192.html)crates.io database dumpYes
Distribution11 releases, 6,764 downloads over 30 days5 not measured
Distribution measurements
SignalValueSourceFetchedCounts
Releases11crates.io database dumpYes
Downloads over 30 days6764crates.io database dumpYes
Binary downloads over the last 3 releasesNot measuredYes
Homebrew installs on request over 365 daysNot measuredYes
Repology repository familiesNot measuredYes
Docker pull growth over 90 daysNot measuredYes
Docker pulls at the growth baselineNot measuredYes
Every version a prereleasefalsecrates.io database dumpYes
Every version 0.0.xfalsecrates.io database dumpYes
Every version yankedfalsecrates.io database dumpYes
Crate deleted from crates.iofalsecrates.io database dumpYes
Repository155 stars, 20 forks, 2 contributors, 135 commits. Stars alone never qualify a project.
Repository measurements
SignalValueSourceFetchedCounts
GitHub stars155GitHub repositoryYes — one part of the repository route
GitHub forks20GitHub repositoryYes — one part of the repository route
Contributors with a GitHub account2GitHub contributorsYes — one part of the repository route
Commits on the default branch135GitHub repositoryNo
Repository's main crate left out of the entrynonecrates.io database dumpYes
Facts that never count
Facts that never count measurements
SignalValueSourceFetchedCounts
LicenseApache-2.0crates.io database dumpNo
Runs on, from listed crates and their direct dependenciesGPU support unknowncrates.io database dumpNo
What shows each backendno dependency or feature matches a backend rowcrates.io database dumpNo
Native code, from listed crates and their dependenciesNo native code foundcrates.io database dumpNo
Python bindings, from direct dependencies of listed cratesNo Python binding crate foundcrates.io database dumpNo
Crates that depend on a listed crate directly2crates.io database dumpNo

Corrections and review history

Report a correction

No correction applies to this entry.

Judgments

A judgment enters only through an approved issue and a merged pull request.

No judgment applies to this entry.