Build a personalized daily newspaper as a print-ready PDF.
Project description
Morning Paper
Own your algorithm. Your personal newsroom.
An agent composes your newspaper. Code prints it.
Your preferences live in files you own.
Set up with AI (recommended)
Open your strongest model — Claude Fable with the 1M context works great — and paste this:
I want a Morning Paper: an open-source personal newspaper my agent composes
and prints, with preferences I own as files
(https://github.com/dmthepm/morning-paper). First read the entire README,
then explore the repo enough to understand the architecture (agent composes,
code renders; a private newsroom repo holds my preference files; the honesty
doctrine binds). Then interview me briefly about my sources, page budget, and
printer. Then: install the engine, run `morning-paper doctor` and fix
anything it flags, run `morning-paper demo` so I see the product, create my
private newsroom repo, build my first real edition, and teach me the daily
loop — including the desk sheet and how my handwritten notes get read back.
Get me to a printed (or PDF) first edition, then stop and show me what you
set up.
Prefer to drive it yourself? Everything below is the manual path.
Try it
Typeset the bundled sample edition — no config, no network, no keys:
uvx --from "morning-paper[pretty]" morning-paper demo
macOS first:
brew install pango gdk-pixbuf(WeasyPrint needs Pango).
Or keep it on your PATH instead of a one-off run:
uv tool install "morning-paper[pretty]"
morning-paper demo
The demo renders a fully synthetic edition through the broadsheet style pack
and tells you exactly where the PDF landed. Print it. That is the product.
The Claude Code plugin
The plugin turns Claude Code into your newsroom staff:
/plugin marketplace add dmthepm/morning-paper
/plugin install morning-paper@morning-paper
Then say "set up my morning paper". The setup skill installs the engine,
interviews you about sources and shape, and creates your private newsroom
repo — your preferences as files you own, not a feed you rent. The edition
skill composes and prints each day's paper.
For Agents (read this first if you are one)
Your human wants a daily printed paper. You can give them one. If they pasted the "Set up with AI" prompt above, follow it — it is the full onboarding arc (read, explore, interview, install, demo, newsroom repo, first edition, daily loop). Otherwise:
- Install:
uv tool install "morning-paper[pretty]"(orpipx install "morning-paper[pretty]"; usepiponly inside a venv — PEP 668 blocks it on brew/system Pythons), thenmorning-paper doctor.morning-paper demoproves the print path end to end. - If this repo is installed as a Claude Code plugin, run the
setupskill — it interviews the reader, creates their private newsroom repo (preferences as files: the owned algorithm), and wires a morning routine. Theeditionskill composes and renders each day's paper. - The CLI speaks JSON. The verbs you need:
morning-paper stage <url>-> stages it for tomorrow and answers with a page estimate ("that adds ~5 pages")morning-paper inbox-> poll the contributor inbox: mail from the configured masthead (an allowlist of trusted senders) becomes staged pages and the sender gets a confirmation;--dry-runpreviews (docs/inbox.md)morning-paper queue-> what's staged vs the page budgetmorning-paper estimate <file.md>-> page count, nothing writtenmorning-paper render <file.md> --style <s> --palette <p>-> the PDFmorning-paper doctor --json-> machine-readable install status (add--strictto get a nonzero exit when the typewriter renderer is unavailable)
- Page estimates need the pretty print stack (
[pretty]+ WeasyPrint):estimatefails without it, andstagefalls back to a rough words-per-page heuristic instead of a real layout pass. Runmorning-paper doctorfirst if the numbers matter. - Article extraction is local by default (
trafilatura): the URL is fetched from this machine and never sent to a third party. If local extraction recovers too little, thejinafallback re-fetches throughr.jina.ai(anonymous tier: shared rate limits, 40-second timeout) and the result carries an honest note saying the URL left the machine. Failures raise clean errors instead of staging garbage. - Composition contract, class vocabulary, and chart directives: docs/composing.md.
- Honesty rule: a section with no data says "not configured" — never fabricate.
What it does
- Builds a daily paper from Hacker News and RSS feeds — JSON, Markdown, HTML, and print-ready PDF artifacts on disk
- Prints any article on demand with
morning-paper print <url> - Stages material for tomorrow's edition against a page budget
(
stage,queue,estimate) - Typesets any markdown file through four print style packs with
morning-paper render - Renders charts from plain-text directives (
mp-bars,mp-spark,mp-stats) as inline SVG — stdlib only, no plotting library - Works without an LLM key
No database. No Docker. No SaaS requirement. It is not a second-brain platform, a wiki, or a closed recommendation engine — it is a CLI that prints a newspaper.
Your daily paper
uv tool install "morning-paper[pretty]"
morning-paper init # starter config
morning-paper doctor # must say: typewriter ready
morning-paper build # today's edition
pipx install "morning-paper[pretty]" works the same way. Prefer either
over bare pip: on Macs and Linux boxes whose default Python is Homebrew's
or the distro's, pip install outside a virtual environment fails with
externally-managed-environment (PEP 668), and inside an existing
environment it can silently keep an older version unless you pass
--upgrade. If you manage your own venv,
pip install "morning-paper[pretty]" is still fine.
Artifacts land under:
~/.local/share/morning-paper/<date>/
The plain morning-paper install (no [pretty]) falls back to a simpler
renderer — it works, but it is not the output you should judge the product by.
Sources
| Source | Auth needed? | Status |
|---|---|---|
| Hacker News | No | Included |
| RSS feeds | No | Included |
| Article URLs | No | Included via print / stage |
Four styles, two palettes
morning-paper styles lists them all — a family of four, each named for the
print genre it is and the job it does. Every style pairs with either palette:
mono (laser printers; weight carries emphasis) or color (inkjet: warm
ink, working red, data blue).
| Style | What it is |
|---|---|
broadsheet |
The newspaper you read: unified serif system, restrained color — the default recommendation |
brief |
The operator brief you work through with a pen: dense Courier, queue rows, link cards, no forced page breaks |
field-card |
The reference card you tape next to the phone: boxed sans one-pager — scripts, checklists, do/don't splits |
zine |
The pocket guide you hand to someone: half-letter photocopier paste-up — marker strips, halftone bands, checkbox steps |
morning-paper render brief.md --style broadsheet --palette color
The 0.4.x names (editorial, flow, ops-card, magazine, typewriter)
still work for one release as deprecated aliases of their successors.
Rendering
Two renderers, one honest contract:
typewriter— the product look. Requires the pretty stack ([pretty]+ WeasyPrint). Courier Prime ships vendored (SIL OFL), so typesetting is offline-deterministic.portable— explicit pure-Python fallback. Lower fidelity; use it only when you intentionally want the simpler output.
If typewriter cannot render, Morning Paper fails clearly instead of
silently generating a lower-quality PDF. morning-paper doctor says plainly
which path you are on, and on macOS prints the exact Pango fix when that is
the problem.
Article extraction defaults to local: the page is fetched directly from
your machine and parsed with trafilatura
— no API key, no rate limits, and the URLs you read never leave your
computer. The jina extractor (the anonymous r.jina.ai reader tier)
remains available, and runs automatically as a fallback when local
extraction recovers too little content — with the privacy trade stated
plainly: jina sends each URL to a third-party service, so the fallback is
flagged with an honest note in the print/stage output rather than
happening silently. Set article_extractor: jina in config if you prefer
the remote reader. Some domains (YouTube, GitHub, Instagram, LinkedIn, HN
comment pages) do not extract meaningfully and are rejected with a clear
error. A validation gate rejects shell pages and too-short extractions
instead of printing garbage. Extraction is a replaceable backend; the
renderer, validation, and image pipeline are designed to survive extractor
upgrades.
The honesty doctrine
A section with no data prints "not configured" — never invented headlines, never filler. Page estimates come from a real layout pass when the print stack is installed. Malformed chart data degrades to an honest placeholder. If the good renderer can't run, the build fails loudly rather than quietly shipping something worse. The paper never lies to you about what it knows.
Docs
- docs/composing.md — the composition contract for agents: document structure, class vocabulary, chart directives
- docs/inbox.md — the contributor inbox: let people you trust email articles into tomorrow's paper (Gmail/iCloud app-password setup)
- ROADMAP.md — what shipped, what's next
- CHANGELOG.md — release history
- CONTRIBUTING.md — how to help
Platform notes
- macOS / Linux — recommended. Install
morning-paper[pretty]; you may need system libraries for WeasyPrint (brew install pango gdk-pixbufon macOS, pango/cairo packages on Linux). - Windows — the CLI works; the
portablefallback is the more reliable path today, andtypewritervia WeasyPrint is best-effort.
Run morning-paper doctor after install: renderer: typewriter ready means
you are on the real print path.
Development
git clone https://github.com/dmthepm/morning-paper.git
cd morning-paper
pip install -e ".[dev]"
python -m pytest tests/
morning-paper doctor
Community
- Main Branch: skool.com/main
- Issues: github.com/dmthepm/morning-paper/issues
- Post your paper: Discussions
License
MIT
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 morning_paper-0.5.0.tar.gz.
File metadata
- Download URL: morning_paper-0.5.0.tar.gz
- Upload date:
- Size: 245.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d365c02da9c42b9639a5782730c0ec414b207623076aa501ea82d34b8689b342
|
|
| MD5 |
2111905cf3a80c4aaec446ef41fc97d2
|
|
| BLAKE2b-256 |
c3052d7da1d4f7c4a97e9a1f3682b8675a6a6c0d4d1485e09f0bb77287a80b71
|
Provenance
The following attestation bundles were made for morning_paper-0.5.0.tar.gz:
Publisher:
publish.yml on dmthepm/morning-paper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
morning_paper-0.5.0.tar.gz -
Subject digest:
d365c02da9c42b9639a5782730c0ec414b207623076aa501ea82d34b8689b342 - Sigstore transparency entry: 1796118921
- Sigstore integration time:
-
Permalink:
dmthepm/morning-paper@de110c351c905c90761e0da6c6b8924216949c09 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/dmthepm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@de110c351c905c90761e0da6c6b8924216949c09 -
Trigger Event:
push
-
Statement type:
File details
Details for the file morning_paper-0.5.0-py3-none-any.whl.
File metadata
- Download URL: morning_paper-0.5.0-py3-none-any.whl
- Upload date:
- Size: 230.3 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 |
aac8fcf063ade18d8fe0ce22d3ad9f77b6b34299d8278ba4741ae4f17b80b5c9
|
|
| MD5 |
87edcc586a19162a59ad607358afe983
|
|
| BLAKE2b-256 |
222f93be4e2d04e2fc22831bcbd26d5e147a575df81caa5b3e18fdf86a55fc4c
|
Provenance
The following attestation bundles were made for morning_paper-0.5.0-py3-none-any.whl:
Publisher:
publish.yml on dmthepm/morning-paper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
morning_paper-0.5.0-py3-none-any.whl -
Subject digest:
aac8fcf063ade18d8fe0ce22d3ad9f77b6b34299d8278ba4741ae4f17b80b5c9 - Sigstore transparency entry: 1796119199
- Sigstore integration time:
-
Permalink:
dmthepm/morning-paper@de110c351c905c90761e0da6c6b8924216949c09 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/dmthepm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@de110c351c905c90761e0da6c6b8924216949c09 -
Trigger Event:
push
-
Statement type: