GitHub Trend Radar is a small, transparent, and auditable Agent Skill. Run it manually to collect a GitHub daily or weekly Top 10, explain each repository in plain language, investigate selected projects, and gradually personalize recommendations from explicit user feedback.
It does not schedule notifications, star or fork repositories, install trending code, or interpret silence as dislike.
Current version: 0.6.1. Source: yuzilan/github-trend-radar. See CHANGELOG.md for release history.
- Feature overview
- Recommended installation
- Three-minute start
- Teaching and correcting preferences
- Ranking
- Local data, metadata cache, and privacy
- Advanced usage
- Update and remove
- Troubleshooting
- Development
| Feature | What it does |
|---|---|
| Daily and weekly discovery | Manually reads GitHub Trending daily and weekly pages |
| Programming-language filter | Finds Python, Rust, JavaScript, and other language-specific trends |
| Objective Top N | Ranks public attention signals without personal preferences |
| Personalized Top N | Adds relevance from preferences the user explicitly expressed |
| Plain-language briefs | Explains purpose, highlights, audience, maturity, and limitations |
| Repository deep dives | Investigates architecture, modules, setup, license, maintenance, and issues |
| Preference learning | Distinguishes investigation, explicit interest, and actual use |
| Exclude and restore | Excludes an exact repository or named topic and can restore it later |
| Forget and reset | Removes active preferences; full reset requires confirmation |
| Inspect, import, and export | Shows learned state and safely moves profiles with feedback history |
| Local metadata cache | Reduces repeated GitHub API requests |
| Historical comparison | Marks repeats and evidence-backed movement when snapshots allow it |
| Diagnostics and retention | Checks the environment read-only and previews cleanup of rebuildable data |
You need:
- Codex or another client that supports Agent Skills;
- Node.js /
npxto run the Skills CLI; - Python 3.9 or newer.
The runtime uses only the Python standard library. No third-party Python packages are required.
For normal use, install globally so different projects and new tasks can discover the same skill:
npx skills add yuzilan/github-trend-radar --skill github-trend-radar --globalOmit --global for a project-local trial:
npx skills add yuzilan/github-trend-radar --skill github-trend-radarCreate a new task and ask naturally. You may invoke $github-trend-radar explicitly or simply ask for today's GitHub Top 10.
If the current task was already open before installation, start a new one so the client can discover the newly installed skill.
$github-trend-radar Show today's GitHub Top 10. Give me an objective Top 10 and a personalized Top 10, and explain each project in plain language.
On the first run there is no preference evidence. The personalized list is labeled as a cold start and initially matches the objective list. This is expected.
Summarize this week's GitHub Top 10. Explain what each repository does, why it is interesting, who it suits, and what caveats matter.
Daily and weekly refer to GitHub Trending's daily and weekly pages; they are not independently reconstructed calendar-period statistics.
Show only Python projects from this week's GitHub Trending list.
Show the first five Rust projects from today's list.
The language is normalized and safely URL-encoded as part of the GitHub Trending path, so names such as C# and Visual Basic cannot corrupt the period query. If GitHub does not recognize it or returns incomplete markup, the skill fails clearly rather than substituting another leaderboard.
The default is Top 10, but other sizes are supported:
Show only the five projects most worth my attention today.
Give me this week's Top 20 with short descriptions.
A normal report includes:
- collection time, daily / weekly period, and language filter;
- an objective Top N unaffected by personal preferences;
- a separately labeled personalized Top N;
- what each recommended repository does;
- its most interesting or useful aspect;
- who it is suitable for;
- maturity, license, maintenance state, or material limitations;
- why it was recommended;
- direct repository links with source attribution near factual claims;
- repeat appearances or movement only when historical snapshots support them.
Exclusions affect only personalized recommendations. If an excluded repository still ranks highly on the objective list, its factual one-line position remains and is marked excluded, but it does not receive a full recommendation card.
Continue by position or repository name:
Investigate number 3. Explain the problem first, then cover architecture, main modules, setup, and current limitations.
Research owner/repository. Focus on whether it is actively maintained, its license, and notable open issues.
A deep dive does not merely expand the earlier synopsis. The skill rechecks the repository README, official documentation, metadata, releases, and relevant public information. It distinguishes:
- verified facts directly supported by repository or official material;
- maintainer claims that have not been independently verified;
- analysis or inference derived from the available evidence.
Investigating a repository does not install or run it. Unless separately requested, the skill never executes unfamiliar repository code, installs its dependencies, or runs setup scripts.
- Strong preferences require explicit feedback.
- One deep-dive request is only a weak interest signal.
- Silence and lack of follow-up do not mean dislike.
- Excluding one repository never excludes its whole category.
- Topic exclusions use only a category the user explicitly named.
- Every active weight and exclusion remains inspectable, restorable, and forgettable.
| User intent | Stored signal | Active effect |
|---|---|---|
| “Investigate this repository” | detail |
Repository and up to three narrow topics gain weak interest +0.5 |
| “I am interested in this” | interested |
Repository and up to three narrow topics gain +2 |
| “I tried it and will keep using it” | tried |
Repository and up to three narrow topics gain +3 |
| “I like local-first tools” | like-topic |
The explicitly named topic gains +3 |
| “Not interested in this repository” | exclude-repo |
Only that exact repository is hard-excluded |
| “I do not want low-code platforms” | exclude-topic |
Only the explicitly named topic is hard-excluded |
| “Restore this repository” | restore-repo |
Removes the repository exclusion; history remains |
| “Restore this topic” | restore-topic |
Removes the topic exclusion; history remains |
| “Forget this repository” | forget-repo |
Removes its active weight and repository exclusion |
| “Forget my Python preference” | forget-topic |
Removes the topic's active weight and exclusion |
| “Reset all preferences” | reset-profile |
Clears active state only after immediate confirmation |
Positive repository and topic weights are capped at 10. Repeated questions cannot grow them without limit, and the same feedback event is not recorded twice for one user turn.
What have you learned about my GitHub recommendation preferences? List repositories, topics, exclusions, and recent feedback.
The response shows positive topic weights, exact repository weights, repository exclusions, topic exclusions, and recent feedback events.
- Restore removes an exclusion but keeps an existing positive weight.
- Forget removes current weight and the matching exclusion for one repository or topic.
- Reset clears every active preference and exclusion and requires immediate confirmation.
Forget and reset deliberately retain the append-only feedback.jsonl audit history. Historical entries no longer drive recommendations; the active state comes from profile.json.
Export my GitHub recommendation profile and complete feedback history to JSON.
The export contains active state, complete feedback, and an export timestamp. Existing files are not overwritten unless the user explicitly approves it.
The objective list uses public attention signals only. Personal interests and subjective README quality never enter this score:
| Signal | Default weight |
|---|---|
| Period star gain shown by GitHub Trending | 45% |
| Original GitHub Trending position | 25% |
| Relative growth | 15% |
| Presence in both daily and weekly lists | 10% |
| Star velocity since a comparable local snapshot | 5% |
If no previous snapshot exists, snapshots are less than 15 minutes apart, or no repository gained stars, the last component is omitted and the remaining weights are renormalized. Equal metric values receive equal percentile scores.
Objective heat measures current attention. It is not a software-quality or security score and is not an official GitHub ranking.
Explicitly excluded repositories and topics are removed first. Remaining candidates use:
75% objective heat + 25% interest match
Interest match uses the larger of an exact repository weight and the average of matched topic weights, divided by the fixed cap of 10. It is not rescaled against the strongest candidate that day. A single detail event at 0.5 therefore produces an interest match of 5, not 100.
Top 10 normally reserves one exploration position for a high-objective candidate outside the first personalized entries. This reduces recommendation lock-in. A Top 1 request never receives an exploration override.
See references/ranking-and-feedback.md for the full formula and feedback rules.
When ~/Documents/Codex/ exists, the default is:
~/Documents/Codex/github-trend-radar-data/
Other environments use:
~/.github-trend-radar/
Override the location with GITHUB_TREND_RADAR_HOME or any script's --data-dir. The default state is shared across working directories, so preferences do not disappear when switching projects.
| File | Contents | Rebuildable? |
|---|---|---|
profile.json |
Active weights and exclusions | User state; do not delete casually |
profile.json.bak |
Previous profile backup | Used for repair |
feedback.jsonl |
Append-only feedback events | User audit data |
feedback.jsonl.bak |
Previous feedback before an import replacement | Temporary recovery aid |
repository-metadata.json |
Public topics, license, and maintenance metadata | Yes |
snapshots/*.json |
Validated leaderboard observations | Can accumulate again |
latest-daily-ranking.json |
Latest daily ranking | Yes |
latest-weekly-ranking.json |
Latest weekly ranking | Yes |
Profile updates use a file lock, atomic replacement, and one previous backup to protect concurrent writes. A corrupt profile causes a clear failure; it is not silently replaced with an empty profile.
By default, the skill interleaves daily and weekly candidates and enriches up to 25 with GitHub topics, license, archive state, and maintenance metadata:
- at most four concurrent requests;
- a default 24-hour cache lifetime;
- no repeated API request on a valid cache hit;
- cache hit, API request, and error counts stored in the snapshot;
--enrich-limit 0to disable enrichment;--refresh-metadatato rebuild the cache.
The cache contains only rebuildable public information. Rebuilding it never changes user preferences.
Topics use a small, conservative, inspectable alias map. For example, ai-agents becomes ai-agent, devtools becomes developer-tools, and llms becomes llm. When a conversion occurs, the feedback event retains topic_aliases for auditing. The skill does not use fuzzy model guesses to merge unrelated categories.
maintenance.py prune handles only rebuildable snapshots and public metadata cache entries. It previews by default and deletes only with --apply; it never removes profile.json or feedback.jsonl. Defaults are 180 days for snapshots and 90 days for metadata. This is a manual tool and never runs in the background.
The skill works without GITHUB_TOKEN, although unauthenticated GitHub API limits are lower. When present, the token is read only from the process environment and is never written to snapshots, caches, profiles, logs, or repository files.
GitHub Trending pages, repository READMEs, issues, releases, and API fields are untrusted third-party data rather than agent instructions. Remote text cannot override the skill's rules, request a token or unrelated local data, trigger tools, contact people, or expand task scope.
Normal users do not need these commands; the agent follows SKILL.md and runs them as needed. This section is for debugging, auditing, and manual reproduction.
Expand the complete command tutorial
In these examples, <skill-dir> is the installed skill directory.
python3 <skill-dir>/scripts/profile.py locationUse --data-dir /path/to/data to preview an override.
python3 <skill-dir>/scripts/profile.py initThis creates default state only when needed. It does not silently clear an existing valid profile.
python3 <skill-dir>/scripts/fetch_trending.py --period both --limit 25The command prints the snapshot JSON path. Fetching both is recommended even when presenting only one period because it allows cross-period presence to be measured.
Common examples:
# Daily only
python3 <skill-dir>/scripts/fetch_trending.py --period daily --limit 25
# Weekly Python list
python3 <skill-dir>/scripts/fetch_trending.py --period weekly --programming-language python
# Disable API enrichment
python3 <skill-dir>/scripts/fetch_trending.py --period both --enrich-limit 0
# Rebuild public metadata cache
python3 <skill-dir>/scripts/fetch_trending.py --period both --refresh-metadataFetch arguments:
| Argument | Meaning |
|---|---|
--data-dir PATH |
Override the default data directory |
--period daily|weekly|both |
Period to fetch; default both |
--limit N |
Candidate count per period; default 25 |
--programming-language NAME |
GitHub Trending language filter |
--language NAME |
Compatible alias for the previous argument |
--enrich-limit N |
API enrichment budget; default 25, use 0 to disable |
--metadata-cache PATH |
Custom metadata-cache file |
--metadata-ttl-hours HOURS |
Cache lifetime; default 24 hours |
--refresh-metadata |
Ignore existing cache and fetch again |
--history-dir PATH |
Custom snapshot-history directory |
--output PATH |
Custom snapshot output file |
Pass the path printed by the fetch command to --snapshot:
python3 <skill-dir>/scripts/rank_trending.py \
--snapshot /path/to/snapshot.json \
--period daily \
--top 10The default output is latest-daily-ranking.json or latest-weekly-ranking.json; the command prints its path.
Ranking arguments:
| Argument | Meaning |
|---|---|
--data-dir PATH |
Data directory |
--snapshot PATH |
Required snapshot to rank |
--profile PATH |
Use a different profile file |
--period daily|weekly |
Required period to rank |
--top N |
Result count; default 10, values are floored at 1 |
--output PATH |
Custom ranking JSON output |
python3 <skill-dir>/scripts/profile.py show --events 10--events controls the number of recent feedback events returned.
# Weak interest
python3 <skill-dir>/scripts/profile.py record --signal detail --repo owner/name --topics ai python
# Explicit interest
python3 <skill-dir>/scripts/profile.py record --signal interested --repo owner/name --topics ai
# Actual use
python3 <skill-dir>/scripts/profile.py record --signal tried --repo owner/name --topics developer-tools
# Explicit topic preference
python3 <skill-dir>/scripts/profile.py record --signal like-topic --topics local-first
# Exclude or restore a repository
python3 <skill-dir>/scripts/profile.py record --signal exclude-repo --repo owner/name
python3 <skill-dir>/scripts/profile.py record --signal restore-repo --repo owner/name
# Exclude or restore a topic
python3 <skill-dir>/scripts/profile.py record --signal exclude-topic --topics low-code
python3 <skill-dir>/scripts/profile.py record --signal restore-topic --topics low-code
# Forget active repository or topic preference
python3 <skill-dir>/scripts/profile.py record --signal forget-repo --repo owner/name
python3 <skill-dir>/scripts/profile.py record --signal forget-topic --topics pythonUse --note "text" to attach a short event note. Repository names are lowercased; topics are normalized and deduplicated.
Without confirmation, reset fails:
python3 <skill-dir>/scripts/profile.py record --signal reset-profileConfirm explicitly to clear active state:
python3 <skill-dir>/scripts/profile.py record --signal reset-profile --confirm-resetFeedback history remains intact.
python3 <skill-dir>/scripts/profile.py export --output /path/to/github-trend-profile.jsonAn existing file is not overwritten. Use --force only after overwrite has been explicitly approved:
python3 <skill-dir>/scripts/profile.py export \
--output /path/to/github-trend-profile.json \
--forcePreview a merge without writing anything:
python3 <skill-dir>/scripts/profile.py import \
--input /path/to/github-trend-profile.json \
--dry-runApply the default merge after review:
python3 <skill-dir>/scripts/profile.py import \
--input /path/to/github-trend-profile.jsonMerge takes the greater weight from each profile, unions exclusions and notes, and deduplicates complete feedback events. Re-importing the same export therefore does not repeatedly raise interest. A complete replacement requires explicit confirmation:
python3 <skill-dir>/scripts/profile.py import \
--input /path/to/github-trend-profile.json \
--mode replace \
--confirm-replaceReplacement keeps one .bak for the previous profile and feedback file. Imported strings are data, never agent instructions.
The command refuses to run without confirmation:
python3 <skill-dir>/scripts/profile.py purge-history --confirm-purgeThis empties feedback.jsonl and removes its old backup without changing active weights or exclusions in profile.json. The skill provides no undo for the purged history; export first if it must be retained.
python3 <skill-dir>/scripts/doctor.pyIt checks Python, the data directory, profile, backup, feedback log, metadata cache, GitHub Trending parsing, and GitHub API limits. It changes no data and never prints the token. Use --offline without network and --json for machine-readable output.
python3 <skill-dir>/scripts/maintenance.py status
python3 <skill-dir>/scripts/maintenance.py pruneThe second command is a preview. After checking its exact paths and entries, apply it explicitly:
python3 <skill-dir>/scripts/maintenance.py prune \
--snapshot-days 180 \
--metadata-days 90 \
--applySnapshots whose dates cannot be read are skipped rather than deleted speculatively.
python3 <skill-dir>/scripts/profile.py repairThis replaces the active profile with profile.json.bak. Inspect the error and backup first; repair is not an ordinary retry and must not run silently.
npx skills update github-trend-radar --global --yesUpdating the skill does not clear profiles or history in the external data directory.
npx skills remove github-trend-radar --global --yesRemoval also leaves external user state intact. Before deleting that data, run profile.py location, verify the exact directory, and create a backup. Never delete a guessed path.
Confirm that installation completed without an error, then create a new task. An already-open task may not reload a newly installed skill. You can also invoke $github-trend-radar explicitly.
GitHub has no official Trending API, so this project reads the public Trending page. Network failures, changed markup, or incomplete responses fail clearly rather than producing a partial report or silently substituting a recently-created-repositories search.
Run python3 <skill-dir>/scripts/doctor.py first to distinguish local-state, Trending parser, and GitHub API-limit problems.
The Trending page may still work, but topics, licenses, or maintenance metadata can fail. Retry later, configure GITHUB_TOKEN locally, or temporarily pass --enrich-limit 0. Never put a token in a command example, README, or repository file.
The cache contains only rebuildable public repository information. Run the next fetch with --refresh-metadata; this does not change preferences or feedback.
The script stops and reports the path. Inspect profile.json.bak, then run profile.py repair only after confirming what will be restored. The backup may not include the most recent write.
First ask what has been learned, then restore, forget, or exclude the exact repository or topic. Skipping a project does not train the profile because silence is not interpreted as negative feedback.
This is intentional. The objective list preserves public facts; exclusion prevents the repository from receiving a personalized recommendation card.
This is the cold start. Interest affects ranking only when current candidates match recorded repositories or topics.
This skill currently implements and validates daily and weekly only. It does not claim support for a mode the current code has not verified.
python3 -m unittest discover -s tests -v
ruff check scripts tests
python3 scripts/release_check.py --strict --tag v0.6.1Tests cover fail-closed HTML parsing, language URL encoding, cache hits, interleaved enrichment, topic aliases, interest scaling, the Top 1 exploration boundary, exclusions, forgetting, reset confirmation, import/export, history purge, derived-data cleanup, read-only diagnostics, concurrent feedback, backup repair, and release metadata. GitHub Actions also verifies Python 3.11 on Linux, macOS, and Windows and runs a weekly live parser smoke test against the current Trending page.
See CONTRIBUTING.md for development and release steps and SECURITY.md for private vulnerability reporting. Licensed under the MIT License.