Not famous. Not abandoned. Just building.
A static site that surfaces open source projects that are alive but invisible — newborns, solo builders, projects that came back from the edge. Ranked by how much they deserve attention, not by star count.
Live: https://capuz.github.io/silentstars/?ref=githubrepo
- Astro + TypeScript (content collections)
- GitHub Actions (nightly discover → collect → build → deploy)
- GitHub Pages — zero cost, zero backend
Edit data/seed.txt and add one owner/repo per line:
# curated picks — always tracked regardless of vitality score
sindresorhus/execa
nicowillis/some-quiet-tool
Lines starting with # are ignored. Commit and push — the next nightly run picks it up.
Seed repos bypass the vitality threshold: they're always shown in the directory.
scripts/discover.ts queries the GitHub Search API each night and writes candidates
to data/discovered.json. scripts/collect.ts then merges both lists (seed + discovered),
deduplicates, and drops any discovered repo whose healthScore falls below the threshold.
Configure discovery in data/discovery.config.json:
{
"starsRange": { "min": 5, "max": 500 },
"pushedWithinDays": 90,
"maxCandidatesPerNight": 250,
"vitalityThreshold": 40
}| Field | Description |
|---|---|
starsRange |
Avoids empty repos (0–4) and already-famous ones (>500) |
pushedWithinDays |
Only considers repos pushed to recently |
maxCandidatesPerNight |
Hard cap — prevents exhausting the 30 req/min rate limit |
vitalityThreshold |
Discovered repos with healthScore below this won't appear in the directory |
Open an issue using the Submit a project template. The workflow validates the repo against the GitHub API, adds it to data/promoted.json with a 30-day window, and immediately runs the full collect → build → deploy → Bluesky post pipeline. No manual steps needed.
- Create a GitHub personal access token (read-only, public repos scope is enough).
- Export it:
export GITHUB_TOKEN=ghp_your_token_here - Run the pipeline:
npm run pipeline # discover + collect in sequence # or step by step: npm run discover # writes data/discovered.json npm run collect # merges sources → data/latest.json + src/content/projects/
npm install
npm run dev # http://localhost:4321/silentstars
npm run build # static output in dist/
npm run preview # serve dist/ locally| Weight | Dimension | Notes |
|---|---|---|
| 35% | Recency | Linear decay over 90d from last commit |
| 25% | Commit cadence | Consistency of commit intervals |
| 20% | Issue health | closedIssues ÷ totalIssues |
| 20% | PR health | mergedPRs ÷ totalPRs |
Bands: 🟢 Healthy 80–100 · 🟡 Stable 60–79 · 🟠 Quiet 40–59 · 🔴 At Risk <40
Repos with high signal and low reach rank highest. The directory is sorted by this.
signal = 0.25 × commitVelocity (commits in 90d, 30=max)
+ 0.20 × contributorWork (uniqueAuthors × commits90d / 100)
+ 0.20 × issueResolution (closedIssues ÷ total)
+ 0.20 × forkRatio (forks ÷ stars)
+ 0.10 × releaseCadence (releases in 90d, 3=max)
+ ageBonus (up to 0.3 if repo > 6 months old, linear up to 24m)
+ homepageBonus (0.05 if repo has a homepage URL)
reach = log10(stars + watchers + 10)
score = round((signal / reach) × 100), capped at 100
| State | Meaning |
|---|---|
thriving |
Commit in the last 30 days |
quiet |
Some activity, no recent release |
at_risk |
3–12 months with no commits + open issues/PRs |
newborn |
Created < 6 months ago, README + license + recent commit |
revived |
Was dormant > 6 months; back to active in the last 30 days |
watched |
Manually curated — always shown regardless of health score |
archived |
Officially archived or no commits in 18+ months — hidden from directory |
GitHub Actions runs on a nightly cron (0 3 * * * UTC):
collect: queries GitHub Search API → merges seed + discovered, computes metrics → commitsdata/latest.json+ content files.deploy:astro build→ GitHub Pages (also triggers on push tomain).post: posts the nightly highlight to Bluesky (BSKY_IDENTIFIER+BSKY_APP_PASSWORDsecrets required).
A separate post.yml workflow (workflow_dispatch only) lets you run the Bluesky post manually with dry_run: true for testing.
In the repo settings, set Pages source to GitHub Actions.