RSSHub route authoring
SkillWeb & browsingAuthor PR-ready RSSHub routes, namespace.ts, route handler, Radar rules and PR description, that survive code review. Distilled from 2,727 route PRs. Use when asked to write, fix or review an RSSHub route, add an RSS feed for a website via RSSHub, contribute a route to DIYgod/RSSHub, or when working with cheerio selectors, cache.tryGet, parseDate, Radar rules, or the RSSHub PR template. Trigger on RSSHub, RSS route, RSS feed for X, 给 X 做 RSS 订阅, namespace.ts, DataItem. Do not use for deploying RSSHub, debugging runtime errors, tuning cache/config, or non-RSSHub scraping.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the RSSHub route authoring skill
What this skill tells your AI
The instructions your AI receives, as published by aboutrss/rsshub-route-authoring-skill in SKILL.md and read by ahel’s review.
Produces route code that can be merged into DIYgod/RSSHub.
Two rules decide almost everything:
- Every defensive construct needs a number.
.first(),.last(),.trim(),?? '', a customUser-Agent, a fallback date, a pagination parameter — prove it with a count or delete it. - Read the project's own rules first. They supersede anything remembered from training
data, and they change over time. In this order:
-
AGENTS.mdin the working directory — the contributor guide, 49 numbered rules -
.github/prompts/pr_review_rules.mdin the RSSHub repo — the 26 rules the auto-review bot enforces:gh api repos/DIYgod/RSSHub/contents/.github/prompts/pr_review_rules.md -
https://docs.rsshub.app/joinus/ — the narrative docs
-
Workflow
0. Environment
- Work inside an RSSHub checkout (a fork is fine). Nothing here works standalone.
- Install dependencies, then start the dev server on port 1200:
pnpm ifollowed bypnpm dev. pnpmis the package manager. Install it however suits your platform —npm i -g pnpm,brew install pnpm,winget install --id pnpm.pnpm,scoop install pnpm, or the standalone install script. If your shell cannot executepnpmdirectly (a common case is a script execution policy on Windows PowerShell), invoke the binary by its full name instead —pnpm.cmdon Windows.- Verify the toolchain before writing code: an incomplete install surfaces as an unrelated
Cannot find module …during typecheck and blocks every commit.
1. Load the rules
-
AGENTS.mdin the working directory — it is the authoritative rule set -
https://docs.rsshub.app/joinus/ — the narrative docs
-
The auto-review bot's own rule list lives at
.github/prompts/pr_review_rules.mdin the RSSHub repo — fetch it when you need authoritative wording:gh api repos/DIYgod/RSSHub/contents/.github/prompts/pr_review_rules.mdIt currently holds 26 rules and its numbering changes over time, so match rules by substance rather than by number.
-
If
docs.rsshub.appis unreachable from your environment, fetch the Markdown source from the docs repository withgh apiinstead of the rendered site
2. Confirm the route does not already exist
Search lib/routes/ for the domain before writing anything. If a namespace exists, add to it
rather than creating a variant.
3. Analyse the source
- Prefer an API over HTML; prefer HTML over Puppeteer.
- Confirm the page is server-rendered before reaching for a browser.
- Fetch the first page only — never expose pagination parameters, and never add a custom
limit(RSSHub has a built-in one). - Decode non-UTF-8 responses (
iconv-litefor GBK and similar). - Check for a structured payload before parsing markup:
__NEXT_DATA__/__NUXT__,application/ld+json, or a WordPress REST API at/wp-json/wp/v2/…. - Check whether the site already publishes an equivalent feed. If it does, say so before
writing the route — see
references/anti-patterns.md§0.
4. Write namespace.ts and the route file
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: '<site display name>',
url: 'www.example.com', // no protocol
lang: '<language code>', // e.g. en, ja, zh-CN
};
import type { Data, Route } from '@/types';
import ofetch from '@/utils/ofetch';
export const route: Route = {
path: '/<route>/:param?',
categories: ['<one category>'],
example: '/<namespace>/<route>/<concrete-value>',
name: '<route name — must not repeat the namespace name>',
maintainers: ['<your github handle>'],
radar: [{ source: ['www.example.com/<path>'], target: '/<route>' }],
handler,
};
async function handler(): Promise<Data> {
// …
}
A namespace directory without namespace.ts is not registered at all — it is mandatory.
5. Build items
- Absolute links:
new URL(href, baseUrl).href - Wrap detail fetches in
cache.tryGet, caching the whole returned object pubDateviaparseDate, normalised withtimezone(…, <utc offset>)when the source omits timezone information; nevernew Date(); never an event time (an exhibition opening, a match kickoff) used as the publish timedescriptionholds body content only — no duplicated title/author/date,<br>not\n- Build markup with JSX +
renderToString; embed source HTML withraw()fromhono/html; neverdangerouslySetInnerHTML
6. Radar
Inline in Route['radar'] — never a separate radar.ts. source has no protocol and keeps
the same subdomain as the namespace url; target matches the route path and omits
parameters the source URL does not contain.
7. Verify with evidence
This is the step that gets skipped, and it is the one that causes the most review churn. Run
scripts/verify-selectors.mjs against the real page and record:
- how many elements each selector matches per item → justifies or kills
.first()/.last() - how many items have padded text → justifies or kills
.trim() - that every link is absolute and unique
Then run scripts/pre-submit-check.mjs, and confirm the feed renders at
http://localhost:1200<example>.
8. Submit
Commit as feat(route): …, push, and open the PR by passing the body as a file:
gh pr create --title "feat(route): add <site> <what> route" --body-file /tmp/pr-body.md
Never let the description travel through a rendered view — the template contains a routes
fence that collides with any fence wrapped around it, and the result is broken markdown. The
title is checked by CI and must be lower-case conventional-commit form; Feat: and
feat:add … both fail it. Check both before opening the PR:
node scripts/pre-submit-check.mjs --title "feat(route): add <site> <what> route"
Before using references/pr-template.md, compare it with the template GitHub injects into
the new PR form — the official template changes over time, and the injected one is
authoritative. See references/pr-template.md for the title rules and the four-backtick
fallback when a human has to copy the body by hand.
Opening the PR starts the automated phase; it does not end your work. Continue with step 9.
9. Finish the automated phase
This phase is entirely mechanical, so run it yourself rather than handing back to the user:
-
Wait for the checks, then read them:
gh pr checks gh pr view --comments -
Fix whatever they report: a
Failed ❌against any path in theroutesblock, or a rule cited by the auto-review pass. -
Commit as a new commit — never amend once a review exists — and push again.
-
Repeat.
How to tell you are done — and why you must then stop pushing — is in
references/review-response.md. Read it there. Do not improvise a test for "clean": the
bot's wording has changed more than once and the details matter.
Guardrail: cap the loop and then ask the user. Three fix-and-push cycles is a reasonable default. If the bot is still citing a rule by then, you are guessing rather than fixing, and each further push re-runs the entire suite and buries the maintainer's own notifications — which is precisely what the milestone rule exists to prevent.
A clean automated pass is not a review. Waiting for a maintainer happens on their schedule, so
that is where a single session ends. Cleaning up once the PR is settled — deleting the branch,
keeping the fork — is also in references/review-response.md.
Before committing
Walk the pre-submit checklist in references/anti-patterns.md, and check
references/engineering-traps.md for LF line endings, TypeScript annotations, and branch
setup.
After the PR: feedback (opt-in only)
This skill is built from real review feedback, so new feedback is genuinely useful. But:
Never file anything without asking the user first. Do not open issues, do not open pull requests, do not query this repository's issues, and do not make network calls on the user's behalf unless they explicitly ask you to.
Offer feedback at two points only — and never in between.
- When the automated phase ends. Only if the auto-review bot cited something that is
absent from the rule catalogue in
references/anti-patterns.md. A finding the skill already documents is the catalogue working as intended, not a gap — asking about it interrupts a phase you are meant to finish unaided. - Once the PR is settled — merged or closed. By then a maintainer may have raised
something, and human feedback is the highest-value signal this skill gets. Reread
gh pr view --commentsfirst; the interesting comments are the human ones, not the bot's.
Do not offer feedback while the automated loop is still running. Finish it first.
When you do offer it, the choice is: write it to a local file (e.g.
observations/<date>-<topic>.md), report it upstream, or skip it. Only report if they pick
that, and say first that the issue will be public and filed under their GitHub account.
For how to report — templates, whether it clears the evidence threshold, and what happens to
your issue afterwards — follow CONTRIBUTING.md. That file owns the procedure; do not restate
it. Never edit references/anti-patterns.md directly.
References
references/anti-patterns.md— 1,987-PR corpus: what gets flagged, with countsreferences/review-response.md— CI checks, decoding comments, answer templates, after the PR is settledreferences/engineering-traps.md— line endings, TS annotations, branch setupreferences/examples.md— copy-paste templates for the API / HTML / Puppeteer strategiesreferences/pr-template.md— PR template and how to fill it (verify before use)tools/— the pipeline that produced the corpus; for skill maintainers, not for agents
Signals
- GitHub stars
- 20
- Last commit
- Sep 2026
ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Item type
- skill
- Key
rsshub-route-authoring-skill- Source
- github.com/aboutrss/rsshub-route-authoring-skill