From FreshRSS for Claude
Produce a digest of recent unread articles from the user's FreshRSS feeds. Use when the user asks for a digest of their feeds, "what's new in my feeds", "summarize the posts from the last N days/week", or invokes `/freshrss-digest`. Requires the freshrss MCP server.
How this skill is triggered — by the user, by Claude, or both
Slash command
/freshrss-claude:freshrss-digestThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Produce a summary of recent unread articles from FreshRSS. The format depends on **how many articles** fall in the window:
Produce a summary of recent unread articles from FreshRSS. The format depends on how many articles fall in the window:
After the digest, offer to mark all articles in the window as read.
/freshrss-digest (with or without a time argument)/freshrss-digest takes an optional free-text time-frame argument. Examples:
/freshrss-digest → default 7 days/freshrss-digest 3d / 3 days / last week / 24h / yesterday / 2w / last monthIf args is empty, use 7 days.
Parse the argument to a duration and shell out for the timestamp — don't compute by hand:
# macOS
date -v-7d +%s # 7 days ago
date -v-24H +%s # 24 hours ago
date -v-2w +%s # 2 weeks ago
# Linux
date -d '7 days ago' +%s
Remember the window size — you'll reuse it in step 3.
If the schema for mcp__freshrss__get_unread_articles isn't loaded yet:
ToolSearch with select:mcp__freshrss__get_unread_articles.
Call it with:
since_timestamp: the value from step 1limit: 2000 (the client pages internally via the Google Reader continuation token, so this is a per-call ceiling on results, not a per-HTTP-request cap)max_summary_length: 300A week of feeds usually exceeds the inline tool-result cap (~25KB). The harness saves the full result to a file and shows a preview with a path. Note the path — you'll pass it to the script in step 3.
Do not retry with a smaller limit to fit inline — you'll just get fewer articles. If the script reports "filtered from 2000" exactly, that's the saturation signal: there may be more in the window than you're seeing, and you should either bump limit higher or warn the user.
Run the processing script — it filters by published (not crawl time), prints a top-10 survey to stderr, and outputs filtered+stripped articles as JSON:
python skills/freshrss-digest/scripts/process_articles.py "$path" "$cutoff" > /tmp/freshrss_filtered.json
Then get the full per-feed breakdown:
python skills/freshrss-digest/scripts/survey_articles.py /tmp/freshrss_filtered.json
To browse article titles, URLs, and summaries (grouped by feed, or --by-time for chronological):
python skills/freshrss-digest/scripts/list_articles.py /tmp/freshrss_filtered.json
Use the survey output to:
ot leaked older articles (stderr from process_articles.py shows "filtered from N")python skills/freshrss-digest/scripts/stats_header.py /tmp/freshrss_filtered.json "digest · {timeframe}"
Include this output verbatim at the top of your response, before the digest.
Every item mentioned by name must include its URL via inline markdown links.
Goal: a navigable index. Every post appears, every post is linked.
### headings (Politics, AI/tech, Local, Music, etc.). Use whatever buckets fit the data — don't force categories.Goal: signal. Aim to mention roughly ⅓ of len(recent) by name (e.g. 100 posts → ~33 items; 60 → ~20). The rest are silently dropped.
### heading per theme. Bulleted items with bold lead-ins. One sentence per bullet, occasionally two.ot leakedIf len(articles) > len(recent) — i.e., client-side filtering had to discard articles older than the window — add a one-line note at the bottom of the digest.
After printing the digest, ask the user if they want to mark the items as read. The offered scope is everything in the window — all recent article IDs, whether or not they appeared in the digest by name.
Use AskUserQuestion with a simple yes/no, or just ask in plain prose. Example phrasing:
Mark all N articles in this window as read in FreshRSS?
If yes, call mcp__freshrss__mark_as_read with article_ids=[a["id"] for a in recent] (load the schema first via ToolSearch if needed). The tool now returns {"ok": true} on success; confirm to the user.
If the user says no or doesn't respond clearly, leave the items unread.
ast.literal_eval needed) since the tools-json-output-and-since-timestamp branch.since_timestamp windows.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub edsu/freshrss-claude --plugin freshrss-claude