
Github Stars
- 87 installs
- 614 repo stars
- Updated August 5, 2026
- openclaudia/openclaudia-skills
Helps with ai & agent building tasks.
About
github-stars is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- github-stars
- AI & Agent Building
- AI-coding skill
Github Stars by the numbers
- 87 all-time installs (skills.sh)
- +13 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #4,951 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openclaudia/openclaudia-skills --skill github-starsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 87 |
|---|---|
| repo stars | ★ 614 |
| Last updated | August 5, 2026 |
| Repository | openclaudia/openclaudia-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
github-stars
Fetch a repo's per-star timestamps from the GitHub API and render two ASCII charts in the terminal: stars by day and stars by hour (for the most recent day(s)). Useful for tracking a launch, a Show HN / Product Hunt spike, or DevRel growth.
Requirements
- The `gh` CLI installed and authenticated (
gh auth status). Unauthenticated calls hit a low rate limit and large repos fail mid-pagination. - Python 3.9+ (uses the stdlib
zoneinfofor correct DST handling).
How it works
The script calls gh api with the application/vnd.github.star+json Accept header, which adds a starred_at timestamp to each stargazer. It paginates through all stargazers, converts each timestamp to the target timezone, and buckets them by day and by hour.
Usage
The script lives next to this file. From the skill directory:
bash github-stars.sh <owner/repo | search-term> [--tz <IANA tz>] [--days N] [--hours-days N]- `<owner/repo>` — exact repo (e.g.
facebook/react). Skips the search. - `<search-term>` — a bare word (no
/) is resolved to the top repo by stars. - `--tz` — IANA timezone for all buckets. Default
America/Los_Angeles. Use e.g.UTC,America/New_York,Asia/Shanghai,Europe/Berlin. - `--days N` — how many recent days to show in the daily chart (default 14).
- `--hours-days N` — how many recent days to break out hourly (default 2).
Examples
# default: last 14 days daily + last 2 days hourly
bash github-stars.sh vercel/next.js
# resolve a search term, show UTC
bash github-stars.sh next.js --tz UTC
# zoom in: only today hourly, 7-day daily window
bash github-stars.sh facebook/react --days 7 --hours-days 1Sample output
owner/repo — 284 stars (with timestamps)
newest: 2026-06-15 02:03 PM PDT | now: 2026-06-15 02:11 PM PDT
STARS BY DAY (PDT)
2026-06-13 16 █████████
2026-06-14 69 ████████████████████████████████████████ ← peak
2026-06-15 22 █████████████
STARS BY HOUR — 2026-06-15 (PDT) total 22
06:00 5 ██████████████████████████████
07:00 2 ████████████
14:00 2 ████████████Caveats — surface these to the user when relevant
- 40,000-star cap: GitHub only returns
starred_atfor the first 40k stargazers. Past that, the hourly/daily breakdown is incomplete (the script warns). The plain total stays accurate. - Net, not gross: the stargazer list reflects stars currently in place. Un-stars don't appear, so a flat total between two checks can hide +1/−1 churn. If the live
stargazers_countdisagrees with the timestamp count, an un-star happened. - DST is handled automatically via
zoneinfo— don't hardcode UTC offsets.
Re-checking / live polling
Just run the script again — it re-fetches live each time. To watch a launch, re-run on an interval and report the delta; don't poll faster than every ~15 minutes (rate limits + politeness).
#!/usr/bin/env bash
# github-stars.sh — fetch a repo's stargazer timestamps and render
# by-day + by-hour star charts in the CLI.
#
# Usage:
# github-stars.sh <owner/repo | search-term> [--tz <IANA tz>] [--days N] [--hours-days N]
#
# Examples:
# github-stars.sh melandlabs/openloomi
# github-stars.sh openloomi --tz America/Los_Angeles --days 14 --hours-days 2
#
# Notes:
# - Needs `gh` authenticated (gh auth status).
# - GitHub only returns starred_at for the first 40,000 stargazers (API cap).
# - Default timezone is America/Los_Angeles (PT). Pass --tz for another.
set -euo pipefail
REPO=""; TZ_ARG="America/Los_Angeles"; DAYS=14; HOURS_DAYS=2
while [[ $# -gt 0 ]]; do
case "$1" in
--tz) TZ_ARG="$2"; shift 2;;
--days) DAYS="$2"; shift 2;;
--hours-days) HOURS_DAYS="$2"; shift 2;;
*) REPO="$1"; shift;;
esac
done
if [[ -z "$REPO" ]]; then
echo "usage: github-stars.sh <owner/repo | search-term> [--tz TZ] [--days N] [--hours-days N]" >&2
exit 1
fi
# Resolve a search term to a full owner/repo (top result by stars).
if [[ "$REPO" != */* ]]; then
echo "Searching GitHub for '$REPO'..." >&2
RESOLVED=$(gh api "search/repositories?q=$REPO&sort=stars&order=desc" \
--jq '.items[0].full_name' 2>/dev/null || true)
if [[ -z "$RESOLVED" || "$RESOLVED" == "null" ]]; then
echo "No repo found for '$REPO'." >&2; exit 1
fi
echo "Resolved to: $RESOLVED" >&2
REPO="$RESOLVED"
fi
CNT=$(gh api "repos/$REPO" --jq '.stargazers_count')
echo "Repo: $REPO total stars: $CNT" >&2
PAGES=$(( (CNT + 99) / 100 ))
if (( CNT > 40000 )); then
echo "WARNING: $CNT stars exceeds the 40,000 timestamp cap; only the earliest 40k have starred_at." >&2
PAGES=400
fi
TMP=$(mktemp)
trap 'rm -f "$TMP"' EXIT
echo "Fetching $PAGES page(s) of stargazer timestamps..." >&2
for p in $(seq 1 "$PAGES"); do
gh api -H "Accept: application/vnd.github.star+json" \
"repos/$REPO/stargazers?per_page=100&page=$p" --jq '.[].starred_at'
done > "$TMP"
REPO="$REPO" TZ_NAME="$TZ_ARG" DAYS="$DAYS" HOURS_DAYS="$HOURS_DAYS" python3 - "$TMP" << 'PYEOF'
import os, sys
from datetime import datetime, timezone
from collections import Counter
from zoneinfo import ZoneInfo
tz = ZoneInfo(os.environ["TZ_NAME"])
days_n = int(os.environ["DAYS"]); hours_days = int(os.environ["HOURS_DAYS"])
rows = [l.strip() for l in open(sys.argv[1]) if l.strip()]
dts = sorted(datetime.strptime(r, "%Y-%m-%dT%H:%M:%SZ")
.replace(tzinfo=timezone.utc).astimezone(tz) for r in rows)
if not dts:
print("No timestamped stars found."); sys.exit(0)
tzabbr = dts[-1].strftime("%Z") or os.environ["TZ_NAME"]
now = datetime.now(tz)
print(f"\n{os.environ['REPO']} — {len(dts)} stars (with timestamps)")
print(f"newest: {dts[-1]:%Y-%m-%d %I:%M %p} {tzabbr} | now: {now:%Y-%m-%d %I:%M %p} {tzabbr}\n")
def bar(n, mx, w=40):
return "█" * round(n / mx * w) if mx else ""
days = Counter(d.strftime("%Y-%m-%d") for d in dts)
recent = sorted(days)[-days_n:]
mx = max(days[d] for d in recent)
peak = max(recent, key=lambda d: days[d])
print(f"STARS BY DAY ({tzabbr})")
for d in recent:
tag = " ← peak" if d == peak else ""
print(f" {d} {days[d]:>4} {bar(days[d], mx)}{tag}")
for day in sorted({d.strftime('%Y-%m-%d') for d in dts})[-hours_days:]:
hrs = Counter(d.hour for d in dts if d.strftime('%Y-%m-%d') == day)
mx = max(hrs.values())
print(f"\nSTARS BY HOUR — {day} ({tzabbr}) total {sum(hrs.values())}")
for h in range(24):
if hrs[h]:
print(f" {h:02d}:00 {hrs[h]:>3} {bar(hrs[h], mx, 30)}")
PYEOF