A deep dive into Firecrawl's open-source document converter — and how to wire it into your own agents.
Every developer who's ever fed a Word doc or a PowerPoint deck into an AI pipeline knows the pain. You juggle converters. You fight layout quirks. You burn tokens on messy output that the model half-misreads. It's the boring tax you pay just to let an LLM read a file.
Then along comes anydoc — Firecrawl's fast, open-source Rust library that converts Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF into clean GitHub-Flavored Markdown. The headline number: single-digit milliseconds per document. But the real magic is the architecture behind it.
Let's dig in.
Office documents are a zoo. A .doc from 2003 and a .pptx created yesterday have almost nothing in common internally. Word files are OLE containers. Modern Office files are ZIP packages with XML. PDFs are a layout nightmare. Spreadsheets have merged cells and named ranges. Ebooks have cascading stylesheets.
Most converters treat each format as a bespoke problem, so you end up with different quality depending on what you throw in. A table that renders fine from a .docx breaks coming out of an .rtf.
anydoc rejects that. Instead of a pile of special cases, every format parses into a shared document model — blocks, inlines, tables, footnotes, assets — and then renders through one single Markdown serializer.
The payoff is huge: fix once, apply everywhere. If you patch a table-escaping bug for .docx, that fix automatically lands for .rtf, .odt, .xlsx, and everything else. One consistent output, no matter the input.
Firecrawl benchmarked anydoc against six other converters (LibreOffice, unstructured, MarkItDown, Pandoc, Docling, Mammoth) on 100 real-world documents spanning 14 formats, scored by an LLM judge against rendered ground truth. 482 verdicts, 0–100 quality scale.
| Tool | Formats | Median time | Score |
|---|---|---|---|
| anydoc | 14/14 | 4.4 ms | 94 |
| LibreOffice | 12/14 | 1129 ms | 87 |
| unstructured | 8/14 | 573 ms | 58 |
| MarkItDown | 6/14 | 135 ms | 33 |
| Pandoc | 5/14 | 102 ms | 34 |
| Docling | 4/14 | 514 ms | 21 |
| Mammoth | 1/14 | 52.5 ms | 8 |
Three things stand out:
Pure Rust, no ML models, no external services — that's how you get sub-5ms conversion.
The pipeline is beautifully simple:
document bytes
│
├─► format detection → reads content markers, NOT the extension
│
├─► format parser → one per format
│ │
│ └─► Document → shared model: blocks, inlines, tables,
│ footnotes, assets
│
└─► GFM serializer → Markdown
Content-based detection is a quietly brilliant touch. anydoc sniffs the bytes — the PDF header, the RTF open group, OLE stream names, the ZIP mimetype — not the file extension. So that .docx someone renamed to .pdf? Still converts correctly.
It preserves full document structure too: heading anchors, bold/italic/strikethrough, inline and block code, links and cross-references, nested lists with the source's own numbering, tables with merged cells and header rows, blockquotes, footnotes/endnotes, even speaker notes from PowerPoints.
Embedded assets render as alt text in the Markdown, with the raw bytes kept on the document model, tagged by media type. PDFs are handled locally via pdf-inspector — text-based PDFs need no OCR service. (Scanned, image-only PDFs are the one gap; that's where Firecrawl's hosted Parse API adds OCR on top of the same engine.)
anydoc ships bindings everywhere, with a consistent API:
// Rust
let markdown = anydoc::to_markdown("report.docx")?;
// Node.js
import { toMarkdown, toMarkdownBytes, toDocument } from '@firecrawl/anydoc';
const markdown = await toMarkdown('report.docx');
# Python
import anydoc
markdown = anydoc.to_markdown("report.docx")
// Browser (WebAssembly)
import { toMarkdownBytes } from '@firecrawl/anydoc-wasm';
await init();
const markdown = toMarkdownBytes(bytes);
There's even a CLI:
npx @firecrawl/anydoc report.docx # Markdown to stdout
npx @firecrawl/anydoc slides.pptx -o slides.md
The bindings are considerate about performance too — Node conversions run on the libuv thread pool (never blocking the event loop), and Python releases the GIL so other threads keep crunching.
Here's the part that should get every agent-platform user excited. anydoc ships as a ready-made Agent Skill:
npx skills add firecrawl/anydoc
That's it. Now any compatible agent — Claude Code, Codex, Cursor, OpenCode — can read office documents natively. The skill teaches the agent to run the anydoc CLI (npx -y @firecrawl/anydoc file.docx), needs only Node 20+, and requires no installation because npx downloads the prebuilt binary on first run.
For a document you can't read directly, the agent now handles it like a first-class citizen.
So how does this plug into the NXagents ecosystem? The good news: it's already designed for exactly this. Here are four integration paths, from "five minutes" to "full product feature."
NXagents runs agents that use skills — and anydoc is literally a skill. Drop the convert-documents-to-markdown skill into an agent's skills/ directory:
npx skills add firecrawl/anydoc
Any NXagents agent that needs to read a PDF, Word doc, spreadsheet, or deck gets that capability instantly. This is the zero-effort win: no code, just a skill install.
For a Go-based runtime (which suits a single-binary platform like NX Sandbox), shell out to the prebuilt anydoc binary or npx @firecrawl/anydoc. It's a clean stdout-in / Markdown-out contract:
npx @firecrawl/anydoc report.docx -o report.md
No long-running service, no daemon, no ML models to babysit. Fire it per-document and let it exit.
If an agent runtime is Node, Python, or Rust, prefer the library over shelling out:
@firecrawl/anydoc (npm)firecrawl-anydoc (PyPI)anydoc (crates.io)Each exposes the same to_markdown/toDocument API and gives you the shared document model — including embedded assets — for agents that need more than just the text.
Here's the sneaky-best option for a privacy-first platform: @firecrawl/anydoc-wasm runs the entire conversion in the browser — files never leave the machine. For NXagents use cases where users don't want to upload sensitive documents (contracts, financials, legal files), this is a huge selling point. Conversion is local, private, and still sub-5ms.
And when you hit scanned PDFs that need OCR, the same engine is available through Firecrawl's hosted Parse API.
anydoc is one of those rare tools where the design is the feature, not just the speed. A shared document model + one serializer means consistent, LLM-ready Markdown across fourteen formats — and it's the fastest option on the market while doing it.
For an agent platform like NXagents, the integration is almost laughably easy because anydoc anticipated it: it ships as an Agent Skill. Whether you install the skill, wrap the CLI, bundle the library, or lean on WASM for private, client-side conversion, your agents can finally read the world's messiest files — clean, fast, and without burning tokens on garbage output.
MIT licensed, open source, and free to self-host. If your pipeline eats office documents, stop fighting the format wars and let anydoc be the one translator to rule them all.
Want to try it? The live demo runs entirely in your browser at firecrawl.github.io/anydoc — no upload, no server, files never leave your machine.