Skip to content
Content
Skill

/openpaper

Generate a personalized newspaper-style digest from any news sources. Use this skill whenever the user wants to read news, set up news sources, get a daily digest, curate articles, generate a newspaper, create a morning briefing, manage their reading preferences, or says things

From plugin
openpaper
163 skills

Claude Code

$ npx -y skills add falense/openpaper --skill openpaper --agent claude-code

SKILL.md

openpaper.SKILL.md
name: openpaper
description: >
  Generate a personalized newspaper-style digest from any news sources. Use this skill whenever the user wants to read news, set up news sources, get a daily digest, curate articles, generate a newspaper, create a morning briefing, manage their reading preferences, or says things like "make my paper", "what's new today", "add a news source", "show me the news", or "update my preferences". Also use when the user mentions OpenPaper, newspaper layout, or news curation. This skill handles the full pipeline: adding sources (writing fetchers), curating content, and rendering beautiful HTML newspaper editions.

OpenPaper

A personalized newspaper that knows only you will ever read it.

Three-stage pipeline: **Ingest** (fetch news) → **Curate** (select and rank) → **Present** (render a newspaper). You are the editor-in-chief.

Quick Reference

| Command | What it does | |---------|-------------| | "Make my paper" | Full pipeline: fetch → curate → render | | "Add a source" | Analyze a URL and write a fetcher | | "Show my preferences" | Display and edit preference profile |

Running Scripts

All scripts use `uv run --project`. Use `${CLAUDE_PLUGIN_ROOT}` if set (plugin mode), otherwise `.` (standalone mode):

uv run --project ${CLAUDE_PLUGIN_ROOT:-.} skills/openpaper/scripts/<script>.py <args>

Data Directory

All state lives in `.openpaper/` relative to the working directory:

.openpaper/
├── sources/           # one .py per source (+ _base.py auto-deployed)
├── preferences.md     # user interests and feedback
├── incoming/          # raw fetched articles (JSON)
├── saved/             # archived articles from past editions
├── editions/          # rendered HTML newspapers
├── cache/             # HTTP cache for fetchers
└── seen.txt           # dedup log

First Run — Setup Wizard

When `.openpaper/` doesn't exist:

1. Create the data directory

mkdir -p .openpaper/sources .openpaper/incoming .openpaper/saved .openpaper/editions .openpaper/cache

2. Add news sources

Say: "What do you want to read? Give me URLs, RSS feeds, or just topics." Then wait for the user's reply.

Deploy the shared base module:

cp ${CLAUDE_PLUGIN_ROOT:-.}/skills/openpaper/scripts/fetcher_base.py .openpaper/sources/_base.py

For each source: 1. **Analyze** — visit the URL, determine type (RSS, HTML, JS-rendered, API) 2. **Write a fetcher** — create `.openpaper/sources/<name>.py`. Read `references/fetcher-guide.md` for the interface spec and `_base.py` templates. 3. **Test** — `uv run .openpaper/sources/<name>.py --cache-dir /tmp/openpaper-test-<name>` > **Cache trap:** Always test with `/tmp/`, NOT `.openpaper/cache/`. Using the real cache pollutes `seen.txt` dedup. 4. **Show** the user what it found

3. Set preferences

Create `.openpaper/preferences.md` by chatting with the user about:

  • Topics of interest and how much
  • Articles per edition (default: 14, up to 18)
  • Location (for weather)
  • Markets data wanted?

Keep under 2000 characters. Example:

# My Reading Preferences

## Interests
- Technology and AI (very interested)
- Software engineering (interested)
- Open source (some interest)

## Sources
Hacker News is my primary source.

## Reading Profile
~14 articles. Include weather for Oslo.

## Feedback

4. Generate first edition

Run the full pipeline and open in browser.

Making a Paper

Stage 1: Ingest

uv run --project ${CLAUDE_PLUGIN_ROOT:-.} skills/openpaper/scripts/fetch_all.py --data-dir .openpaper

Discovers all fetchers in `.openpaper/sources/`, runs in parallel, deduplicates against `seen.txt`, fetches content, writes new articles to `.openpaper/incoming/`.

Stage 2: Curate

> **Gate:** Only begin after Stage 1 completes and weather/markets data is collected. Curation needs the full candidate pool.

Read `references/curation-guide.md` for the full process. Summary:

1. **Inspect the pool:**

  • `uv run --project ${CLAUDE_PLUGIN_ROOT:-.} skills/openpaper/scripts/pool.py --data-dir .openpaper stats`
  • `uv run --project ${CLAUDE_PLUGIN_ROOT:-.} skills/openpaper/scripts/pool.py --data-dir .openpaper list --sort points`
  • `uv run --project ${CLAUDE_PLUGIN_ROOT:-.} skills/openpaper/scripts/pool.py --data-dir .openpaper show <slug>`

2. **Read** `.openpaper/preferences.md` 3. **Score and rank** articles against user interests 4. **Select** articles (typically 10-18), enforce topic/source diversity 5. **Assign editorial weight** — lead (1), major/lg (2-3), mid/md (3-5), briefs (4-8) 6. **Summarize in parallel** — spawn one subagent per article via `parallel()`:

parallel([
  () => agent("Summarize this lead article: <JSON>. Write 3-4 paragraphs, deck, photo_caption..."),
  () => agent("Summarize this lg article: <JSON>. Write 2 paragraphs..."),
  () => agent("Write a brief for: <JSON>. Return bold + one sentence..."),
  ...
])

7. **Assemble edition YAML** — see `references/edition-schema.md` for the schema

Write the YAML to `.openpaper/editions/draft.yaml`.

Stage 2.5: Archive

1. `mkdir -p .openpaper/saved/<date>-<edition_name>` 2. Move selected article JSONs to the archive 3. Delete remaining from `.openpaper/incoming/`

Stage 3: Present

uv run --project ${CLAUDE_PLUGIN_ROOT:-.} skills/openpaper/scripts/render.py --data-dir .openpaper --edition .openpaper/editions/draft.yaml

Then preview:

uv run --project ${CLAUDE_PLUGIN_ROOT:-.} skills/openpaper/scripts/serve.py --data-dir .openpaper --latest

Open in browser. Say: "Here's your paper — let me know what you think."

Adding a Source

1. Visit the URL (screenshot or fetch) 2. Determine type: RSS, HTML, JS-rendered, API 3. Read `references/fetcher-guide.md` for the contract and `_base.py` templates 4. Write `.openpaper/sources/<name>.py` 5. Test with `/tmp/` cache dir (not the real one) 6. Show results to the user

**Key rules:**

  • RSS/API first, Playwright for
Read more
@falense
Ships withopenpaper

A personalized newspaper that knows only you will ever read it. OpenPaper is a Claude Code plugin that turns any collection of news sources into a single-reader daily newspaper.

Stars on GitHub

Momentum

stars in total
16
Star history of falense/openpaper on GitHub, a chart by star-history.com

Other skills on openpaper.

improve

improve

Create a structured GitHub issue from a session reflection or improvement idea using the gh CLI. Use this skill when the user…

@falense@falenseInstall Skill
reflect

reflect

Reflect on the current Claude Code session — review what went well, what didn't, and extract actionable takeaways. Use this skill…

@falense@falenseInstall Skill

More skills from other plugins.

prompt-lookup

prompt-lookup

Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use…

@gh-f@gh-fInstall Skill
ppt-master

ppt-master

AI-driven presentation workflow for generating editable PPTX decks and slides, reconstructing page visuals, creating reusable…

@hugohe3@hugohe3Install Skill
morph-ppt

morph-ppt

Use this skill when the user wants a .pptx with smooth cross-slide animation — PowerPoint Morph transitions, Keynote-style…

officecli13d33k
@iofficeai@iofficeaiInstall Skill

Questions about openpaper.

Which coding agents can use openpaper?
openpaper installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.