From FreshRSS for Claude
Search the user's unread FreshRSS articles for a specific topic, using semantic relevance over titles and summaries. Use when the user asks "what's in my feeds about X", "any news on X in my feeds", or invokes `/freshrss-search <topic>`. Requires the freshrss MCP server.
How this skill is triggered — by the user, by Claude, or both
Slash command
/freshrss-claude:freshrss-searchThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Semantically search the user's **unread** FreshRSS articles for a topic the user describes in free text, then surface the matches in a format that scales with hit count:
Semantically search the user's unread FreshRSS articles for a topic the user describes in free text, then surface the matches in a format that scales with hit count:
The skill does not apply a time window — it searches everything currently unread, on the assumption that if it's still unread, it's still in scope.
After presenting results, offer to drill deeper on a specific item by fetching its URL and summarizing the full article.
/freshrss-search <topic> (e.g. /feed-search what's happening with Iran, /feed-search AI regulation, /feed-search local DC news)/freshrss-search takes a free-text topic phrase as its argument. Interpret it as the user's topical intent — extract both literal keywords and the broader concept. Examples:
/freshrss-search Iran → literal mentions of Iran, plus related (Israel/Gaza, US strikes, oil, sanctions)/freshrss-search what's happening with the Supreme Court → SCOTUS rulings, nominations, related legal news/freshrss-search interesting AI critique → not "anything about AI" but specifically critical or skeptical piecesIf args is empty, ask the user what topic they want to search for. Don't guess.
If the schema for mcp__freshrss__get_unread_articles isn't loaded yet:
ToolSearch with select:mcp__freshrss__get_unread_articles.
Call it with:
limit: 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: 300since_timestamp — we want everything unreadThe result will almost certainly exceed the inline tool-result cap. 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 2.
If len(articles) == 2000 exactly, that's the saturation signal — there may be more unread than you're seeing. Note this to the user at the end and consider bumping limit higher.
Run the loading script — it strips HTML from all summaries and outputs clean articles as JSON:
python skills/freshrss-search/scripts/load_articles.py "$path" > /tmp/freshrss_articles.json
Then load the result:
import json
with open("/tmp/freshrss_articles.json") as f:
articles = json.load(f)
Read every article's title + cleaned summary and judge relevance to the user's topic phrase. No server-side keyword pre-filter — Claude does the matching, so semantically-adjacent items (e.g. "ICE detention center" for a "immigration policy" query) are caught even when the exact keyword is absent.
Be generous-but-honest:
If the user's topic is vague or could mean multiple things, lean toward broader inclusion and let them refine.
Count your matches and the distinct feeds they came from. Run:
python skills/freshrss-digest/scripts/stats_header.py --articles {N} --feeds {M} "search · {topic}"
Include this output verbatim at the top of your response, then add a one-line note on the date range and which feeds contributed. This sets expectations and tells you which mode to use.
Every item mentioned must be linked via inline markdown.
### sub-headings if there's a natural split (e.g. "US strikes" vs. "diplomatic angle"), but don't force it. A flat list is fine for narrow topics.### heading per sub-theme within the topic. Bulleted items with bold lead-ins. One sentence per bullet, occasionally two./feed-digest's ⅓ — the user explicitly asked about this topic, so coverage matters more than ruthless curation).After the results, end with a one-liner like:
Want me to pull the full text of any of these and go deeper?
If the user picks one, use WebFetch (load via ToolSearch with select:WebFetch if needed) against the article URL and summarize the full piece. The skill itself stops at presenting results — drill-deeper is a follow-on action triggered by the user.
If the semantic filter returns zero unread matches, don't just say "nothing found." Offer to broaden:
Nothing matching "{topic}" in your unread feeds. Want me to search read articles too?
If yes, load mcp__freshrss__search_articles via ToolSearch and call it with the user's topic phrase (or a keyword extracted from it) as the query. Present those results in the same mode-A/mode-B format. Note in the output that these are previously-read articles.
If matches are very sparse (1–3 items) but exist, present them and add the same offer to broaden — sparse matches often signal a slightly-too-narrow read of the topic.
tools-json-output-and-since-timestamp branch — no ast.literal_eval needed./freshrss-digest, this skill does not offer mark-as-read by default. Topic-search matches are usually things the user wants to read; clearing them would be counterproductive. If the user explicitly asks to mark them read or to star them, do so via mcp__freshrss__mark_as_read or mcp__freshrss__star_article.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