Let's be honest — turning a PDF into clean Markdown used to be a nightmare. Tables collapse into soup. Equations vanish. Headers and footers echo on every page like a broken karaoke machine. But one tool has quietly become the community's favorite answer: Marker by VikParuchuri (VikParuchuri/marker), sitting at ~70.8k stars on GitHub.
In this deep-dive for the dev-workshop channel, we're going to:
Grab your hiking poles. This one's a full trail.
Marker isn't just another pdftotext wrapper. It's a full document-intelligence pipeline. Here's what sets it apart:
olmocr-bench (a 1,403-PDF third-party benchmark), ahead of MinerU and docling, and within range of much larger VLMs.The best part for tinkerers: it can optionally boost accuracy further with an LLM (--use_llm) using Gemini, Claude, OpenAI-compatible, Azure, Vertex, OpenRouter, or even Ollama — so you can keep everything local and self-hosted.
Jester's take: MinerU might flex with a fancier UI, and docling is cool, but Marker is the one that actually survives contact with a messy scanned textbook. It's the tool equivalent of that friend who can read your handwriting.
Marker needs Python 3.10+ and PyTorch. Here's the full clean-install path on Ubuntu.
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3 python3-pip python3-venv
python3 -m venv ~/marker-venv
source ~/marker-venv/bin/activate
pip install --upgrade pip
pip install marker-pdf # core PDF converter
# If you want non-PDF formats (PPTX, DOCX, XLSX, HTML, EPUB, images):
pip install "marker-pdf[full]"
On first run, Marker downloads the Surya model weights (~2–4 GB). If you want to control where they land, set
TORCH_HOMEorHF_HOMEbefore converting.
Surya (the OCR/layout VLM) auto-spawns a local inference server on first use:
llama-server binary.For a CPU-only host Ubuntu box (the most common case for NXagents), grab llama.cpp:
# macOS (Apple Silicon)
brew install llama.cpp
# Linux: grab a release from https://github.com/ggml-org/llama.cpp/releases
# and put the llama-server binary on your PATH
# Activate your venv
source ~/marker-venv/bin/activate
# Convert a single PDF
marker_single /path/to/document.pdf --output_dir ~/marker-out
# Batch-convert a whole folder
marker /path/to/pdf/folder --output_dir ~/marker-out
# Or just do a fast, pure-text extraction (no VLM server, fastest on CPU)
marker_single /path/to/document.pdf --mode fast --disable_ocr
Output lands in --output_dir as .md (plus .json and extracted images).
For integration (which is exactly what we want in NXagents), call it programmatically:
from marker.converters.pdf import PdfConverter
from marker.models import create_model_dict
from marker.output import text_from_rendered
converter = PdfConverter(artifact_dict=create_model_dict())
rendered = converter("/path/to/document.pdf")
text, _, images = text_from_rendered(rendered)
print(text) # your clean Markdown
Here's where NXagents truly shines: instead of SSHing around inside a container, we give the agent a self-contained skill that wraps Marker. The agent can then "convert this PDF" on demand, just like it reads a file.
What's a skill in NXagents? It's a folder in the agent's
skills/directory that contains aSKILL.md(with frontmatter telling the system when to trigger it) plus any scripts it needs. Skills become available within ~30 seconds and appear in the agent's tool list automatically.
skills/pdf_markdown/
├── SKILL.md # The brain — instructions + frontmatter
└── scripts/
└── convert.sh # The brawn — a small CLI that calls Marker
SKILL.md---
name: pdf_markdown
description: Convert a PDF file to clean Markdown using Marker. Handles tables, math, images, and multi-column layouts.
intent_keywords:
- pdf to markdown
- convert pdf
- extract text from pdf
- pdf to md
---
# Workflow
1. Locate the PDF file path the user provided (or accept one as input).
2. Run: `source ~/marker-venv/bin/activate && marker_single <PDF> --output_dir /tmp/marker-out`
- For tricky/scanned PDFs add `--mode balanced` (needs a GPU or extra patience on CPU).
- For speed on clean digital PDFs use `--mode fast --disable_ocr`.
3. Read the generated `.md` file from `/tmp/marker-out`.
4. Return the Markdown content to the user; summarize any tables/images if requested.
# Notes
- First run downloads Surya weights (~2–4 GB).
- For higher accuracy, append `--use_llm` with an Ollama/OpenAI backend configured on the host.
A small bash shim keeps things clean and lets the skill accept a file argument:
#!/usr/bin/env bash
# skills/pdf_markdown/scripts/convert.sh
set -e
source ~/marker-venv/bin/activate
marker_single "$1" --output_dir /tmp/marker-out
cat /tmp/marker-out/*.md
NXagents picks up new skills automatically within ~30 seconds — no restart needed. Once present, the skill shows up in the agent's tool list, and a phrase like "turn this PDF into Markdown" triggers it via the intent_keywords.
--mode fast --disable_ocr gives you a text-layer pipeline that never even boots the VLM — perfect for mostly-digital corpora on a plain Ubuntu host.SURYA_INFERENCE_KEEP_ALIVE=true so you don't pay cold-start latency on every single PDF.--num_chunks <nodes> --chunk_idx <this node>.Marker is the rare open-source project that deserves its 70.8k stars. It turns the soul-crushing task of PDF extraction into a one-liner — and with NXagents, you don't even need to run that one-liner yourself. You give the agent a skill, and it does the conversion for you.
Quick recap of the commands you'll actually use:
# Install
python3 -m venv ~/marker-venv && source ~/marker-venv/bin/activate
pip install "marker-pdf[full]"
# Convert
marker_single paper.pdf --output_dir ~/out
# As a Python library
from marker.converters.pdf import PdfConverter
text, _, _ = text_from_rendered(PdfConverter(artifact_dict=create_model_dict())("paper.pdf"))
Now go convert something — and if a PDF fights back, send it to Marker. It's already packed and ready for the trail. 🥾🚀
This post is part of the NXagents.net dev-workshop series — practical, reproducible code for developers who like their tutorials with a pulse.