hammerdown
hammerdown is a cross-platform tool and Python library for converting PDF, Word, Excel, PowerPoint, OpenDocument, CSV, and plain-text documents into clean Markdown. Word charts are rendered as SVG, OpenDocument and Markdown images are extracted, and mathematical formulas are converted to LaTeX.
The PDF pipeline is built on PyMuPDF and PyMuPDF4LLM, which do the actual page-layout reconstruction and Markdown generation. This is the central feature the project was built around. Everything else -- routing, batch handling, merging, and file-manager integration -- is built around that core.
Supported Formats
- PDF and E-books:
.pdf,.epub,.mobi,.fb2,.xps - Word and OpenDocument:
.docx,.doc,.odt - Spreadsheets:
.xlsx,.xls,.csv - Presentations:
.pptx,.ppt - Text and Markdown:
.txt,.md,.log
Table of Contents
- Output Directory Layout
- Installation
- Advanced Usage
- Implementation Notes
- Credits and Attribution
- Documentation links
Output Directory Layout
Output Markdown files are named after the source document, so report.docx becomes hm_report_docx.md and notes.txt becomes hm_notes_txt.md. The source extension is part of the name, which keeps report.docx and report.doc from overwriting each other.
Before conversion:
folder/
└── report.docx
After conversion:
folder/
├── report.docx
├── hm_report_docx.md
└── hm_images_report_docx/
└── chart_000.svg
PDF text is converted directly to Markdown without producing an asset folder. Asset folders are created only where the format exposes separate assets: Word charts are rendered as SVG, OpenDocument images are copied out, and base64 images in Markdown are decoded. Presentations and spreadsheets produce Markdown text and tables only.
Installation
Recommended: Python package (pip)
If Python (3.10+) is installed on your system, install via pip:
pip install hammerdown
Or install from local source:
git clone https://github.com/sergeypugin/hammerdown.git
cd hammerdown
pip install .
Direct Download (Standalone binaries)
If you do not have Python installed, precompiled standalone binaries are available on the GitHub Releases page or you can download directly from the links below:
| OS | Download |
|---|---|
| Windows | |
| Linux | |
| macOS |
On Linux and macOS, make the downloaded binary executable before running:
chmod +x ./hammerdown-linux-x64
./hammerdown-linux-x64 --version
File Manager Context Menu Integration
You can integrate hammerdown directly into your OS file manager to convert documents with a single right-click, without opening a terminal:
hammerdown --install
What this does:
- on Windows: adds a Hammer down file action with an icon to the File Explorer context menu for all supported document formats, adds folder context menu options for recursive directory conversions, creates a Send to shortcut (
Send to -> Hammer down) for first-level access in Windows 11, and activates an IPC coordinator to process multi-file selections in a single terminal window - on Linux: installs the launcher into
~/.local/bin, installs a FreeDesktop application entry in~/.local/share/applications/hammerdown.desktopwith MIME associations, registers KDE Dolphin ServiceMenus in~/.local/share/kio/servicemenusand~/.local/share/kservices5/ServiceMenus, and adds scripts for Nautilus, Nemo, and Caja (Scripts -> Hammer down file) - on macOS: installs the launcher into
~/.local/bin, creates an Automator Quick Action in~/Library/Services/Hammer down.workflowfor the Finder right-click context menu, and generates a drag-and-drop Droplet in~/Applications/Hammer down.appwithCFBundleDocumentTypesfor Finder "Open With"
To convert a file or folder, right-click any supported document or folder and select Hammer down file (or use Send to -> Hammer down). The Markdown output and extracted images are saved directly next to each original document.
To remove file manager integration and clean up shortcuts:
hammerdown --uninstall
To update hammerdown to the latest version:
hammerdown --update
Logging and Progress Tracking
When converting documents from the terminal, hammerdown renders a live view instead of scrolling log lines. The Summary panel shows elapsed time, the preflight estimate, completed files, the running token count, and the number of errors. The Processing panel keeps a sliding window of the file queue:
- a completed file gets a green marker and its duration, image count, and token count
- the active file shows an inline progress bar in the state column and its live elapsed time
- queued files are dimmed and show their preflight estimate
- failed files get a red marker and are repeated in a separate
Error listpanel with the failure reason - the
Processingpanel border is orange while the batch is running and green once it finishes - the
Resultspanel summarizes merged documents, converted files, and extracted images
In non-interactive environments (CI pipelines, redirected logs, or non-TTY outputs) no live view is drawn. Each file is announced when it starts and reported when it finishes, and the same Summary, Error list, and Results panels are printed once at the end as plain text without terminal control characters:
Processing report.pdf ~8.1s...
Completed report.pdf (8.1s, ~1_200 tokens)
Processing notes.txt ~0.5s...
Completed notes.txt (0.5s, ~12 tokens)
When using hammerdown as a Python library, custom progress callbacks can be passed to to_markdown() or convert_file():
def on_progress(current: int, total: int, unit: str):
print(f"Processed {current}/{total} {unit}")
hammerdown.convert_file("report.pdf", progress_callback=on_progress)
Advanced Usage
Command Line Interface
Convert one or multiple files:
hammerdown report.pdf
hammerdown report.docx workbook.xlsx slides.pptx
Options:
-i,--include REGEX-- only process files whose normalized relative path matches REGEX; may be repeated-e,--exclude REGEX-- skip files whose normalized relative path matches REGEX; may be repeated; exclusions always take priority-w,--overwrite-- overwrite plain-text source files (.txt,.md) in-place instead of creating a copy-s,--skip-existing-- skip conversion when the target Markdown file already exists; without it, existinghm_*.mdoutputs are overwritten-o,--output-dir DIR-- save Markdown output and extracted images under DIR, preserving the relative layout of the input tree-m,--merge OUTPUT_MD-- merge every converted Markdown document into a single target Markdown file--stdout-- write the merged Markdown document to stdout; errors go to stderr--confirm-- with--stdout, print a preflight estimate and ask for confirmation before writing anything-v,--version-- display version information
Include and exclude filters are applied to the path relative to the directory that was passed on the command line. Include narrows the recursive scan first, then exclude removes matches from that set:
hammerdown -i 'reports/.*' -e '/draft/' folder/
hammerdown -s report.pdf
Merging Documents into a Single File
-m / --merge converts many documents and concatenates the results into one Markdown file. This is convenient when you want to feed a whole project folder into an LLM as a single context block:
hammerdown -m summary.md project/report.pdf project/notes.docx project/drafts/
The target file is built incrementally and has two parts.
First, a directory tree of every source document, relative to their common root:
Directory structure:
└── project/
├── report.pdf
├── notes.docx
└── drafts/
└── plan.md
Then one block per document. Each block starts with a line of 48 = characters, a FILE: line with the path relative to the common root, the same separator again, and the converted Markdown:
================================================
FILE: report.pdf
================================================
# Quarterly Report
Revenue grew by 12% in Q3.
================================================
FILE: drafts/plan.md
================================================
# Draft Plan
- collect metrics
- review results
Key properties:
- output is written as the batch runs, so a partially converted file is still usable if the run is interrupted
- extracted assets are not mixed with the originals: for the target
summary.md, images, charts, and decoded pictures are written intohm_merged_into_summary_images/next to the target, in subfolders that mirror each document's relative path, and their links are rewritten accordingly --mergeis rejected together with--overwriteand with--output-dir, so plain-text sources are never modified during a merge- combined with
-s/--skip-existing, the whole merge is skipped when the target file already exists - the merge target cannot also be one of the source documents
After the run the sources stay where they were, and the merged file sits next to its assets:
project/
├── report.pdf
├── notes.docx
├── drafts/
│ └── plan.md
├── summary.md
└── hm_merged_into_summary_images/
├── hm_images_notes_docx/
│ └── chart_000.svg
└── drafts/
└── hm_images_plan_md/
└── embedded_img_0.png
Streaming to stdout
--stdout produces the same merged document as -m, but writes it to stdout instead of a file, and does not create any intermediate hm_*.md files:
hammerdown --stdout project/ > summary.md
Assets are inlined as base64 data URIs, so the stream is self-contained. Progress tables and per-file messages are suppressed; errors go to stderr, and the exit code is non-zero when any document failed.
Add --confirm to inspect the cost before anything is printed. Missing paths are reported first, then the preflight line shows the file count, a token estimate for text sources, and an estimated duration. The prompt accepts y and yes, rejects n and no, and re-asks on anything else:
[!] drafts: file or directory not found
[!] missing.md: file or directory not found
Preflight: 16 files, ~2_400 tokens from text sources, estimated time ~1m 43.9s.
Continue and write Markdown to stdout? [y/n] Lk
Please answer "y" or "n".
Continue and write Markdown to stdout? [y/n] nO
Cancelled.
Only formats that are already plain text (.txt, .md, .log, .csv) contribute to the token estimate, because the size of a PDF, DOCX, or XLSX says nothing about the Markdown that comes out of it. For mixed inputs the clause is marked from text sources; when no such files are present, the token clause is omitted entirely. --confirm requires an interactive stdin; without a terminal it cancels safely instead of waiting. --stdout is incompatible with --merge, --output-dir, --overwrite, and --skip-existing.
Python Library Quickstart
Use hammerdown directly in your Python code:
import hammerdown
# Convert a file on disk
hammerdown.convert_file("report.pdf", skip_existing=True)
# Get Markdown text in memory
text, image_count = hammerdown.to_markdown("report.docx")
# Convert a batch with CLI-equivalent options
hammerdown.convert_files(["project/"], merge="summary.md", include=[r"reports/.*"])
For specialized format converters and low-level helpers, see docs/PYTHON.md.
Implementation Notes
Extracting Base64 Images from Markdown
If you have a Markdown file with embedded base64 images, running hammerdown with --overwrite extracts each image using its MIME type (png, jpeg, webp, gif, svg and other supported image subtypes) into a sibling folder named after the source. For LMS.md, the first decoded image is written as hm_images_LMS_md/embedded_img_0.png and the link in the document is rewritten to that path. The image is not converted to PNG: PNG is used only when the source data URI says image/png.
hammerdown LMS.md --overwrite
Math Formulas and Symbol Normalization
Equations inside Word and OpenDocument files are automatically translated into standard LaTeX syntax. Special math characters and Greek letters are mapped using a catalog aligned with official LaTeX references:
- Official Reference: Rice University LaTeX Symbols Reference
- Bundled Copy: symbols.pdf
Tables and Spreadsheets
Tables are reconstructed as real Markdown tables instead of loose text:
- CSV: the delimiter is detected from the first lines (comma, semicolon, tab, or pipe), and the file is decoded through the same UTF-8, CP1251, CP1252, and Latin-1 fallback chain as other text inputs
- XLSX: every worksheet starts with a
# Sheet: Dataheading. Cells with evaluated values use them; when a formula has no cached value, the formula text itself is used. Empty rows and columns at the edges are trimmed, and separate blocks of cells on the same sheet become separate Markdown tables - DOCX and PPTX: table cells are rendered as Markdown rows. Pipes inside a cell are escaped as
\|, and empty cells are kept so the column layout stays stable
The shared renderer lives in parsers/markdown_render.py, and the matrix segmentation logic used by spreadsheets and CSV lives in parsers/tables.py.
Credits and Attribution
- The CLI flag functionality for
-m/--merge,-i/--include, and-e/--excludewas adapted from gitingest, an excellent reference implementation for packing a directory tree into a single LLM-friendly text blob.hammerdownadapts those ideas to document conversion. - PDF, EPUB, MOBI, FB2, and XPS conversion is powered by PyMuPDF and PyMuPDF4LLM. This is the central feature the project was built around.
- Office documents are parsed with python-docx, openpyxl, and python-pptx.
Documentation links
For additional guides and specifications:
- Python API Reference -- complete guide to Python library methods
- Technical Reference -- internal format processing and parser details
- Architecture -- system layers and Mermaid pipeline diagram
- Performance & Estimation Model -- conversion benchmarks, multi-threading architecture, and ETA model
- Contributing Guidelines -- development setup and testing guidelines
Metadata
Release files for hammerdown 3.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hammerdown-3.0.3.tar.gz | 254.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hammerdown-3.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 497.1 kB
Release files / hammerdown-3.0.3.tar.gz
| Download URL | hammerdown-3.0.3.tar.gz |
|---|---|
| Size | 254.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
abc5575263b9b8bf929cc703583e614006f7501f265ad0c9c3f1d37a80d46b92
|
|
BLAKE2b-256 checksum How to use checksums |
4b30209966fa271245dd0b2ec1b263cfd888ef3d62d13f31e6070185fd0f035c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / hammerdown-3.0.3-py3-none-any.whl
| Download URL | hammerdown-3.0.3-py3-none-any.whl |
|---|---|
| Size | 242.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3d43f09918330094dc9d33d74d9fa33b4016c70fa89182c68710e3b8a92858f6
|
|
BLAKE2b-256 checksum How to use checksums |
82866c738c7fc966792188cc16e78fa8bd45ec910dff25105d80a5a9c3309292
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logSecurity for hammerdown 3.0.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for hammerdown-3.0.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.