Extract and enrich GitHub pinned repository data from profile pins HTML
Collect the GitHub projects a user contributed to, along with what they actually did in each.
A list of projects says nothing about the work that went into them.
This tool reports, per project, how many commits the user authored, how many of their pull requests were merged, how many pull requests they reviewed, how many issues they filed, when they were last active and which permission they hold.
That is what makes the list of projects contributed to rank and describe its entries instead of listing names.
Three sources are merged, because none of them is complete on its own.
user.repositoriesContributedTo is the closest thing GitHub offers to the question being asked.input/seed.json, in this tool’s own output format.input/profile-pins.html, optional.Every repository found is then enriched through one batched GraphQL query per eight repositories, at a cost of one rate-limit point each.
uv sync
Configure:
export DEFAULT_PREFIX=your-github-username
export GITHUB_TOKEN=ghp_xxx
The token is required, and it has to belong to DEFAULT_PREFIX: the GraphQL API rejects unauthenticated requests, and it reports the contribution role as the permission of the token’s own account.
A GitHub App token cannot stand in for it.
Seed it, optionally: copy a previous repos.json to input/seed.json, and export the pin picker’s HTML to input/profile-pins.html on a first run (Profile → Edit pins → DevTools → copy the list markup).
Run:
python -m src.main
Output: output/repos.json
Responses are cached in github_cache for a day, so a re-run right after is nearly instant while star counts and contribution counts still refresh daily.
docker build -t dargmuesli/contributed-to .
docker run --rm \
-e DEFAULT_PREFIX=your-username \
-e GITHUB_TOKEN=ghp_xxx \
-v "$(pwd)/input:/srv/app/input:ro" \
-v "$(pwd)/output:/srv/app/output" \
-v "$(pwd)/github_cache:/srv/app/github_cache" \
dargmuesli/contributed-to
from src.main import discover_contributed_repos, enrich_repos, fetch_user_id
login = "dargmuesli"
user_id = fetch_user_id(login)
projects = enrich_repos(discover_contributed_repos(login), login, user_id)
for project in projects:
repository = project["repository"]
contribution = project["contribution"]
print(f"{repository['name']}: {contribution['commits']} commits")
[{
"contribution": {
"commits": 6,
"issues": 15,
"last_activity_at": "2026-01-29",
"pull_requests_merged": 6,
"reviews": 5,
"role": "TRIAGE"
},
"repository": {
"description": "The full-stack Vue framework.",
"fork": false,
"name": "nuxt",
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/23360933?v=4",
"name": "nuxt",
"type": "Organization",
"url": "https://github.com/nuxt"
},
"stars": 60872,
"url": "https://github.com/nuxt/nuxt"
}
}]
commits counts commits authored on the default branch whose author is linked to the account, so read it as a lower bound: work merged into another branch, or committed under an unlinked email address, does not show up.
role is the permission the token’s account holds today (ADMIN, MAINTAIN, WRITE, TRIAGE, READ), which is a hint about the relationship rather than a record of it: READ does not mean nothing was contributed.
# Install development dependencies
uv sync
# Run tests
DEFAULT_PREFIX=testuser pytest
# Code quality
ruff format
ruff check --fix
mypy src tests