Note
This branch is Open Athena's deployment (gh.oa.dev): a live feed of GitHub engagement (stars + follows) across the Open-Athena + marin-community orgs, with Slack posting and a gated internal dashboard. Its commits on top of rw are, step by step, exactly what a fork of this project changes — instance config, feature enablement, branding, OG image. The base project lives on the rw branch — oa's Git ancestor, and a nice minimal "hello world" instance in its own right (watchy.rbw.sh).
Track GitHub stars + follows: a Cloudflare Worker collector, live-feed web dashboard, optional Slack posting, and a Python library/CLI.
See ryan-williams/.watchy for an example daily GHA that polls for stargazers and followers of a few orgs and repos.
Note: as of [GitHub's 2026-06-30 access restrictions][gh-changelog], the stargazers
API requires a token belonging to an admin or collaborator of each repo; watchy stars
can no longer fetch arbitrary repos' stargazers.
cfw/ contains a Cloudflare Worker that polls hourly and appends
star/unstar/follow/unfollow events to a D1 database (see
specs/d1-worker.md); watchy backfill seeds it from a
.watchy-style git history, and watchy sql queries it.
- Fetch stargazers for GitHub repositories
- Fetch followers for GitHub users or organizations
- Save data to simple text files (one username per line)
pip install watchy# Single repository
watchy stars owner/repo
# Multiple repositories
watchy stars owner/repo1 owner/repo2 another-user/repo3
# All repositories for a user/org
watchy stars username
watchy stars orgname
# Mixed targets
watchy stars owner/repo username orgname# Single user
watchy follows username
# Multiple users
watchy follows user1 user2 user3
# Mix users and orgs
watchy follows user1 orgname user2watchy always:
- saves usernames to text files under
.watchy/(configurable with$WATCHY_DIR) - prints usernames to stdout (first 5, ..., last 5 if >10 total)
- shows counts in log messages (to stderr)
File locations:
- Stargazers:
.watchy/github/stars/<owner>/<repo>.txt - Followers:
.watchy/github/follows/<user>.txt
Example output:
42 stargazers for owner/repo
alice
bob
charlie
david
emily
...
user38
user39
user40
user41
user42
watchy automatically loads GitHub tokens from:
--tokencommand line argumentGITHUB_TOKENenvironment variable.tokenfile in current directorygh auth token(GitHub CLI)
# Using environment variable
export GITHUB_TOKEN=your_personal_access_token
watchy stars owner/repo
# Using command line argument
watchy --token your_token stars owner/repo
# Using .token file
echo "your_token" > .token
watchy stars owner/repo
# Using GitHub CLI (if logged in)
gh auth login
watchy stars owner/repo # Automatically uses gh token# Add delay between requests when fetching multiple repos
watchy stars myorg -s 1.0 # 1 second delay between reposDerive star/unstar/follow/unfollow events from a .watchy-style data repo's
commit history, for import into the worker's D1 database:
watchy backfill > backfill.sql # walks $WATCHY_DIR (default .watchy)
watchy sql -f backfill.sql # importSee watchy backfill --help and specs/d1-worker.md for
re-run semantics (-u/--until, -S/--no-seed-state) and the stars vs. follows
event-emission policy.
watchy sql "SELECT kind, count(*) FROM events GROUP BY kind" # rows out as JSONL
watchy sql -l ... # local dev dbfrom watchy.github import GitHubClient
from watchy.storage import save_logins_to_txt
from pathlib import Path
# Create client (auto-detects token)
client = GitHubClient()
# Fetch stargazers
stargazers = list(client.get_stargazers("owner", "repo"))
logins = save_logins_to_txt(iter(stargazers), Path("stargazers.txt"))
# Fetch followers
followers = list(client.get_followers("username"))The Cloudflare stack (cfw/ worker + D1, www/ site) is designed to be pointed at any set of repos/orgs. The reuse model is fork (or branch) and commit your config (see specs/branch-model.md): cfw/wrangler.jsonc is the instance config, and each branch of this repo is a complete, deployable instance:
rw— the base project + the personal reference instance: watchy.rbw.sh.oa(this branch) — Open Athena's deployment (gh.oa.dev), a worked fork example: its commits on top ofrware, step by step, exactly what a fork changes (instance config → enable Slack + auth gate → rebrand → OG image).
To stand one up:
- Fork/branch; in
cfw/wrangler.jsoncsetaccount_idandTARGETS(stars: owners whose repos' stargazers to track;follows: users/orgs whose followers to track). wrangler d1 create watchy→ pastedatabase_id;wrangler d1 migrations apply watchy --remote.- Secrets:
WATCHY_TOKEN(GH token — must be a collaborator/admin of tracked repos for stargazer access, per GitHub's 2026-06 restriction). Fine-grained PATs are scoped to a single resource owner, so multi-org instances add per-owner overrides:WATCHY_TOKEN_<OWNER>(owner uppercased, non-alphanumerics →_, e.g.WATCHY_TOKEN_MARIN_COMMUNITY), falling back toWATCHY_TOKEN. Optional:SLACK_BOT_TOKEN+ theSLACK_*vars for per-event Slack posting and weekly summaries;SESSION_SECRET/ADMIN_EMAILSfor the auth-grant gate;ANTHROPIC_API_KEYfor actor-research replies. Every feature degrades cleanly when its vars are absent. pnpm buildinwww/(site assets are served by the worker itself), thenpnpm run deployincfw/. The*/5cron collects; events appear at the worker's URL.
Seed history with watchy backfill (from a .watchy-style git ledger) if you have one; otherwise the bootstrap stargazer pass captures original starred_at dates on its own.
# Install with dev dependencies
pip install -e .[dev]
# Lint
ruff check src/watchy/