Write books in Markdown, compile to EPUB 3.3 โ and deconstruct existing EPUBs back to readable Markdown (best-effort). Like Fountain for screenplays.
Project description
ProseDown
Write books in Markdown. Compile to EPUB. Like Fountain is for screenplays, ProseDown is for ebooks: plain text that compiles to a complex format. Two lines of frontmatter, one Markdown file, valid EPUB 3.3.
๐ jeffalldridge.github.io/prosedown โ live site, full spec, cheat sheet.
Why this exists
Most ebook tools fall into one of three buckets โ and each forces a tradeoff most authors don't want to make:
- Closed editors (Vellum, Scrivener) hide everything in a closed app. You can't open your manuscript anywhere else without exporting.
- Power tools (Pandoc, LaTeX) are heavy. Full citation engines and custom syntax for things 99% of authors don't need.
- Raw editors (Sigil, Calibre) make you hand-edit XHTML inside a zip file. Useful for fixing existing books, painful for writing new ones.
| Vellum | Scrivener | Pandoc | LaTeX | ProseDown | |
|---|---|---|---|---|---|
| Plain text source | โ | โ | โ | โ | โ |
| Open in any editor | โ | โ | โ | โ | โ |
| EPUB output | โ | โ | โ | with effort | โ |
| Zero configuration | โ | โ | โ | โ | โ |
| Standard Markdown | n/a | n/a | mostly | โ | โ |
| Free | $250 once | $59 once | โ | โ | โ |
| macOS / Win / Linux | macOS only | โ | โ | โ | โ |
| EPUB โ source | โ | โ | partial | โ | โ (best-effort) |
ProseDown sits between: plain Markdown source files an author can open in any editor โ Obsidian, VS Code, iA Writer, TextEdit โ that compile to a professional EPUB by convention, with no configuration.
ProseDown is not for fixed-layout books, picture books, comics, poetry with line-level control, drama formatting, academic citations, or media overlays. See the scope boundaries in the spec.
Five design principles
The decisions that shape every part of the format.
- One file is enough. A single
.mdwith two YAML lines is a valid project. The barrier to entry is zero. - Convention over configuration. Cover auto-detected. CSS auto-detected. Chapter order from filenames. Authors shouldn't configure what can be inferred.
- Standard everything. CommonMark Markdown. Standard YAML. No custom syntax. Lock-in is the enemy of adoption โ and your files should outlive any single tool.
- Two directions. Build is primary, deterministic, EPUBCheck-clean. Deconstruct is best-effort and practical, not a lossless archive.
- Non-destructive. Opens cleanly in Obsidian, Hugo, Jekyll, or any other Markdown tool. A format that fights your other tools isn't a format worth adopting.
The whole tool, in seven lines
No configuration files, no project initializer, no template wizard.
cat > on-simplicity.md <<'EOF'
---
title: "On Simplicity"
author: "Jane Smith"
---
# On Simplicity
The simplest things are often the most profound.
EOF
prosedown build on-simplicity.md on-simplicity.epub
That's a valid EPUB 3.3 โ passes EPUBCheck, opens in Apple Books, Kobo, Calibre, anything that reads ebooks. Two required frontmatter fields, one Markdown file, no configuration.
When your book outgrows a single file, point prosedown build at a
folder of numbered chapters. See spec/examples/ for
four progressively larger projects.
How build works
Markdown source on the left, EPUB 3.3 on the right, a small handful of well-defined steps in the middle.
your project prosedown build EPUB 3.3
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ book.md โ โ parse YAML โ โ META-INF/ โ
โ 01-intro.md โ โโโถ โ resolve files โ โโโถ โ container.xml โ
โ 02-chapter.md โ โ render Markdown โ โ OEBPS/ โ
โ cover.jpg โ โ build OPF/NCX โ โ chapters/ โ
โ style.css โ โ pack ZIP โ โ images/ โ
โ โ โ โ โ nav.xhtml โ
โ โ โ โ โ content.opf โ
โ โ โ โ โ mimetype โ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
deterministic ยท EPUBCheck-clean
same source โ same bytes
Everything is auto-detected: cover by filename, CSS by filename, chapter order by numeric prefix. Same source produces the same bytes โ diff-clean under git, reproducible builds work.
How deconstruct works (the other direction)
An existing EPUB on the left, a clean Markdown project you'd actually want to edit on the right.
existing.epub deconstruct Markdown project
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ .epub (zip) โ โ read OPF โ โ book.md โ
โ XHTML โ โโโถ โ classify roles โ โโโถ โ 000-cover.md โ
โ + assets โ โ walk spine โ โ 001-chapter.md โ
โ + OPF โ โ XHTML โ Markdown โ โ 002-chapter.md โ
โ โ โ extract images โ โ ... โ
โ โ โ extract css โ โ images/ โ
โ โ โ โ โ css/ โ
โ โ โ โ โ โ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
best-effort ยท documented normalization
Building is the primary use case โ stable and deterministic. Deconstruction is best-effort with documented normalization. The goal is readable Markdown an author would want to edit, not a lossless archive of the original EPUB.
ProseDown at a glance
If you only read one section, read this one. The full spec is the source of truth; this is the cheat sheet.
Required frontmatter
Two fields. That's the floor. Everything else is inferred or optional.
---
title: "Your Book"
author: "You"
---
Optional frontmatter
language: en # default: en
publisher: "โฆ"
date: 2026-04-30
isbn: "978-โฆ"
description: |
Short blurb.
cover: "cover.jpg"
css: "style.css"
ProseDown synthesizes a deterministic UUID from title + author + language.
Project layouts
# Single-file project โ one file, one essay, one EPUB.
my-essay.md # frontmatter + body
# Multi-chapter project โ filename order = chapter order.
my-book/
book.md # frontmatter only
00-copyright.md
01-chapter-1.md
02-chapter-2.md
cover.jpg # auto-detected
style.css # auto-detected
Conventional slugs (auto-classified by role)
- Frontmatter:
copyright,dedication,acknowledgments,foreword,preface - Part dividers:
part-1,part-2, โฆ - Backmatter:
afterword,about-the-author,colophon,notes - Anything else: chapter
Title resolution
- Frontmatter
title:(if set) - First
#heading in body - Deslugified filename
Same logic on deconstruct โ round-trips preserve the title source.
Standard Markdown
CommonMark plus GitHub-flavored extensions:
tables, definition lists, fenced code, footnotes ([^1]). No custom
dialect.
Excluded files
Filenames starting with _ are skipped at build time. Useful for
parking drafts in the same folder.
_09-deleted-scene.md
_draft.md
Pick your path
Three ways into ProseDown depending on what you're trying to do.
1. I want to write a book
You're an author. You want to focus on the words and have something publishable come out the other end.
- Five-minute quickstart
- Single-file example โ start here
- Multi-chapter example โ when one file isn't enough
- Multi-part example โ front/back matter, parts
- Features example โ images, captions, glossary
2. I want to understand the format
You're evaluating ProseDown for a workflow, a tool you're building, or out of curiosity about how the design hangs together.
- The spec โ single source of truth
- Why ProseDown โ design rationale
- XHTML mapping reference โ for implementers
- Roadmap โ where it's going
3. I want to build on it
You're writing a tool, plugin, or alternate compiler. The spec is open and the reference compiler is MIT.
- PyPI package โ
pip install prosedown - Contributing โ setup, PR checklist, what fits
- Help wanted โ especially a Rust or Go compiler for v1.0
- Live site โ landing page + spec
Install
pip install prosedown
Requires Python 3.10+.
prosedown --help
prosedown --version
prosedown build path/to/project path/to/output.epub
prosedown deconstruct path/to/book.epub path/to/output-project/
The build path uses only MIT- and BSD-licensed dependencies. The
deconstruct path additionally pulls in html2text (GPL-3.0+) and
EbookLib (AGPL-3.0+) โ see THIRD_PARTY_LICENSES.md.
Develop
git clone https://github.com/jeffalldridge/prosedown
cd prosedown
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
prosedown --help
python tests/test_suite.py # 36 synthetic tests, all green
Running against a real-world corpus
The synthetic tests in tests/test_suite.py always run. To additionally
exercise ProseDown against real EPUBs from Standard Ebooks, Project
Gutenberg, etc., point at a local corpus:
PROSEDOWN_CORPUS=/path/to/corpus python tests/test_suite.py
The corpus is not redistributed via this repo โ it can include copyrighted material. The expected layout is documented in the test file.
What's in this repo
prosedown/
spec/
prosedown.md # โ The specification (start here)
xhtml-mapping.md # Markdown โ XHTML mapping reference
examples/
single-file/ # One-file essay
multi-chapter/ # Numbered chapters in a folder
multi-part/ # Parts + front/back matter
with-features/ # Images, captions, glossary
src/prosedown/ # Reference compiler (Python 3.10+)
__init__.py
data/prosedown-default.css
tests/
test_suite.py # 36 synthetic tests, all green
docs/
site/ # GitHub Pages site source
quickstart.md
why-prosedown.md
scripts/
build_site.py # Renders spec/prosedown.md โ site
pyproject.toml # Installable as `pip install prosedown`
Spec
The current spec is at spec/prosedown.md, version
0.6.1. Pre-1.0; minor refinements likely before 1.0. The spec uses
MUST, SHOULD, and MAY per
RFC 2119 where two compilers
need to agree on exact behavior.
A conforming compiler MUST produce EPUB 3.3 output that passes EPUBCheck without errors.
Implementations in other languages are welcome โ see
spec/xhtml-mapping.md for the Markdown โ XHTML
mapping reference. The full spec also lives as a rendered HTML page at
jeffalldridge.github.io/prosedown/spec/.
Roadmap
See ROADMAP.md for what's planned for v0.7, v1.0, and
beyond โ plus what's deliberately out of scope.
Contributing
PRs welcome โ see CONTRIBUTING.md for the setup, PR
checklist, and the difference between spec changes and code changes.
For security issues, see SECURITY.md.
Credits
- Built on CommonMark (Markdown), EPUB 3.3, and XHTML 1.1.
- Reference implementation in Python:
Markdown,PyYAML,beautifulsoup4,lxml,html2text,EbookLib. - Conceptual ancestor: Fountain (plain text for screenplays).
Full attribution in THIRD_PARTY_LICENSES.md.
License
MIT. ยฉ 2026 Jeff Alldridge / Tent Studios, LLC.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file prosedown-0.6.2.tar.gz.
File metadata
- Download URL: prosedown-0.6.2.tar.gz
- Upload date:
- Size: 58.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30182998f55b090a7d177e08df9102ab78f4910e429d8ea3a4c88337c25b6348
|
|
| MD5 |
0c458c16a3b381085b2d10e90051894c
|
|
| BLAKE2b-256 |
1cd2a47b90d4d39864d97fd8d29eab9d2f1d9008dac5ddac8d232dfdbc42d23f
|
Provenance
The following attestation bundles were made for prosedown-0.6.2.tar.gz:
Publisher:
release.yml on jeffalldridge/prosedown
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prosedown-0.6.2.tar.gz -
Subject digest:
30182998f55b090a7d177e08df9102ab78f4910e429d8ea3a4c88337c25b6348 - Sigstore transparency entry: 1414960440
- Sigstore integration time:
-
Permalink:
jeffalldridge/prosedown@2ba95ac1e2c3923f7d01979bdd77d9d5aecc649f -
Branch / Tag:
refs/tags/v0.6.2 - Owner: https://github.com/jeffalldridge
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2ba95ac1e2c3923f7d01979bdd77d9d5aecc649f -
Trigger Event:
push
-
Statement type:
File details
Details for the file prosedown-0.6.2-py3-none-any.whl.
File metadata
- Download URL: prosedown-0.6.2-py3-none-any.whl
- Upload date:
- Size: 44.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
196dd1c3dee822061bd6872dee300427fc4705e6a1ec8c2a2a34b8e3ac8b9ec1
|
|
| MD5 |
52f740750270188976735313cfde5b6d
|
|
| BLAKE2b-256 |
3ca09f4f87be829d3a547e97cac4ef1a92466843aca00340c8e8253f699b51d0
|
Provenance
The following attestation bundles were made for prosedown-0.6.2-py3-none-any.whl:
Publisher:
release.yml on jeffalldridge/prosedown
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prosedown-0.6.2-py3-none-any.whl -
Subject digest:
196dd1c3dee822061bd6872dee300427fc4705e6a1ec8c2a2a34b8e3ac8b9ec1 - Sigstore transparency entry: 1414960579
- Sigstore integration time:
-
Permalink:
jeffalldridge/prosedown@2ba95ac1e2c3923f7d01979bdd77d9d5aecc649f -
Branch / Tag:
refs/tags/v0.6.2 - Owner: https://github.com/jeffalldridge
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2ba95ac1e2c3923f7d01979bdd77d9d5aecc649f -
Trigger Event:
push
-
Statement type: