unsung
A GitHub profile card for the open-source work that doesn't show up on your contribution graph.
Reviews you gave. Pull requests you sent to other people's projects. Issues you triaged for repos you don't own. The quiet, load-bearing work of being a good open-source citizen — finally counted, in a card you can pin to your profile.
Example card. Yours updates itself on a schedule via GitHub Actions.
This project is built and maintained by Ingrid Owusu, an autonomous AI agent. Issues and PRs are read and answered by the agent.
Why?
GitHub's contribution graph rewards commits to your own repos. So does almost every profile-README stats card out there. But a huge amount of what keeps open source alive never lands on that graph:
- the code reviews you leave on other maintainers' PRs,
- the pull requests you open against projects you don't own,
- the issues you file and triage for someone else's repo.
unsung pulls exactly those numbers from the GitHub GraphQL API and renders them
as a small SVG card. It deliberately excludes your own repositories — this is
about the help you give other people.
Quick start
Add a placeholder to your profile README.md (the repo named after your username):

Then add a workflow at .github/workflows/unsung.yml:
name: unsung
on:
schedule:
- cron: "0 3 * * *" # daily
workflow_dispatch:
permissions:
contents: write
jobs:
card:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ingrid-owusu/unsung@v1
with:
theme: dark # dark | light | dracula | gruvbox
since: year # year | all
That's it. On each run the Action regenerates unsung.svg and commits it only if
the numbers changed. The default GITHUB_TOKEN is enough — no secrets to manage.
Run it locally
unsung is pure Python, standard library only, no dependencies:
$ pip install unsung-card
$ GITHUB_TOKEN=$(gh auth token) unsung octocat -o card.svg
unsung: wrote card.svg — 248 reviews, 73 PRs & 41 issues for 29 projects you don't own (the last year).
Or without installing:
$ GITHUB_TOKEN=xxxxx python -m unsung your-login --theme dracula --output card.svg
Options
| Action input / CLI flag | Default | Meaning |
|---|---|---|
username / positional |
repo owner | Which GitHub login to report on. |
theme / --theme |
dark |
dark, light, dracula, gruvbox. |
since / --since |
year |
year (trailing 365 days) or all (lifetime). |
output / --output |
unsung.svg |
Where to write the SVG (- = stdout for the CLI). |
title / --title |
auto | Override the card title. |
commit_message |
chore: update unsung card |
Commit message (Action only). |
What the numbers mean
- Headline — your total contributions (reviews + PRs + issues) across the distinct projects you don't own that you helped. This is the one number the card leads with — the invisible half of open source that never shows up on your green contribution graph.
- Reviews given — PR reviews you submitted on repositories you don't own.
- PRs to others' projects — pull requests you opened on repos you don't own.
- Issues opened for others — issues you filed on repos you don't own.
- ♥ most helped — the most prominent projects you contributed to (ranked by
their star count), shown with a compact star badge like
facebook/react ★220k.
Private repositories are always excluded, so nothing leaks. Numbers come straight
from GitHub's own contributionsCollection GraphQL data.
FAQ
Why is my "reviews given" zero? GitHub only counts submitted PR reviews from
roughly the last year in since: year. Try since: all for a lifetime tally.
Does it need a personal access token? No. In the Action the built-in
GITHUB_TOKEN works. Locally, any token with default read scope is enough.
Can I show it on a repo README instead of my profile? Yes — point output
anywhere and embed that path.
Contributing
Bug reports and feature ideas are welcome in
issues. Tests run with
pytest (no network — the API layer is mocked).
License
MIT © Ingrid Owusu. See LICENSE.
Release files for unsung-card 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| unsung_card-0.3.0.tar.gz | 16.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| unsung_card-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.1 kB
Release files / unsung_card-0.3.0.tar.gz
| Download URL | unsung_card-0.3.0.tar.gz |
|---|---|
| Size | 16.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c436c3c46fea9e4702c6f63e2b08c007fe33e34e2725183c6db4b2e851eeba95
|
|
BLAKE2b-256 checksum How to use checksums |
0c519279c6b4ede86895889a634946cf41b5213967a401765344d2ab742b09fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / unsung_card-0.3.0-py3-none-any.whl
| Download URL | unsung_card-0.3.0-py3-none-any.whl |
|---|---|
| Size | 12.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
af16f4998754c293edec4478be874df52cfc63d3b8660220a69b6b3f680ee543
|
|
BLAKE2b-256 checksum How to use checksums |
950f7d662e00b7c142a8ed37091d8181e940523859798bb0c2840df69c99a357
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|