Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions github-profile-stats-deploy/SKILL.ja.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
name: github-profile-stats-deploy
description: >
Vercelにデプロイした自前のGitHubプロフィール統計カード(github-readme-stats、
github-readme-streak-stats、あるいはそれらに類するPHP/Node製フォーク)を
セットアップする手順と、壊れた時に直す手順。ユーザーが自分のGitHub統計/
ストリークカードを自前デプロイしたい時、プロフィールREADMEのカードが
「Failed to retrieve contributions」「.env was not found」「Missing token
in config」を表示している時、対象フォークのVercelデプロイが「No more than
12 Serverless Functions」で失敗する時、対象フォークのGitHub Actionsデプロイ
が落ちた時、統計カードプロジェクト用のVERCEL_TOKEN/VERCEL_ORG_ID/
VERCEL_PROJECT_IDの設定について聞かれた時、プロフィールの統計/ストリーク
カードが壊れている・死んでいると言われた時に使う。当てずっぽうで直そうと
せず、以下の該当する手順を順番通りに進めること — ここで起きる不具合は
だいたい既知の原因を持っていて、エラーメッセージの見た目だけでは分からない
ことが多い。
---

# GitHubプロフィール統計カード — セットアップと障害対応

このスキルは2つの手順をまとめたものだ:何もない状態から統計カードを立ち上げる手順と、既にデプロイ済みのカードが壊れた時に直す手順。各ステップには、そのステップに関係する注記だけを添えてある。詳しい説明は`references/`配下に逃がしてあり、該当ステップの注記から個別にリンクしているので、その注記が指す時だけ読みに行けばいい。手順を通しで読む段階では先回りして全部読む必要はない。

## 手順A: ゼロから統計カードをセットアップする

1. **使いたい統計カード生成元を自分のアカウントにフォークする。** 例: contributions/言語比率カードなら`anuraghazra/github-readme-stats`、ストリークカードなら`DenverCoder1/github-readme-streak-stats`。両方要らなければ片方だけでいい。互いに依存関係はない。

2. **GitHub Personal Access Tokenを作る。** スコープは`repo` + `read:user`。作成場所は`https://github.com/settings/tokens/new`。
> 有効期限は無期限か長めにしておくこと。期限切れがこの手のカードが壊れる原因のダントツ1位で、しかも壊れ方が分かりにくい。詳細は`references/secrets-and-tokens.md#L6-22`。

3. **各フォークをVercelに別々のプロジェクトとしてインポートする**(Vercelダッシュボード → Add New → Project → 対象リポジトリを選択)。確認方法: それぞれ独自の`*.vercel.app`ドメインが割り当たり、初回デプロイが走ること(この時点ではまだトークンを登録していないのでエラー表示になるのが正常)。

4. **そのプロジェクトの環境変数にPATを登録する。**
> 変数名はフォーク元のソースコードが決めているもので、**フォークによってバラバラ**。決め打ちせず実際の変数名を確認してから登録すること。詳細は`references/secrets-and-tokens.md#L24-50`。

保存後は再デプロイし、実際に動いているか確認する:
```bash
curl -s "<自分のプロジェクト>.vercel.app/<カードのパス>?username=<自分のユーザー名>" | grep -o "Total Contributions\|Failed to retrieve"
```

5. **ビルド自体が失敗する場合**、特に「No more than 12 Serverless Functions can be added to a Deployment on the Hobby plan」のようなエラーが出た場合:
> これはトークンやコードとは無関係な、既知のVercelプラットフォーム側のバグ。`vercel.json`の直し方と、必要ならGitHub Actions経由のデプロイへの切り替え方が`references/vercel-deploy-bug.md`にある(`#L20-41`と`#L43-86`)。

6. **READMEからカードをどう参照するか決める**: Vercelの実URLを直接`<img src="https://your-project.vercel.app/…">`で埋め込むか、定期実行でサーバー側からfetchして静的SVGとしてコミットするか。
> ライブURLの方がセットアップは簡単だが、実体のデプロイを直した後も、間に挟まる複数のキャッシュ層のせいで何時間も古いエラーが表示され続けることがある。なぜそうなるかと、それを避けたい場合の定期fetch+コミット構成の最小形は`references/cache-layers.md`を見ること。

静的SVG方式を選ぶ場合、最小構成は: 各プロジェクトのライブSVG出力をキャッシュバスター付きクエリでfetchしてファイルに書き込むスクリプトと、それを定期実行(数時間おき+オンデマンド実行用の`workflow_dispatch`)してコミットするワークフローの2つ。

7. **`README.md`にカードを埋め込む** — 手順6で選んだ方式に応じて、ライブURLか静的ファイルの相対パスのどちらか。確認方法: github.com上でプロフィールページの表示を実際に見る(rawファイルだけでなく。コミット直後はGitHub自体のページキャッシュで少し遅れて反映されることもある)。

## 手順B: 既にデプロイ済みのカードが壊れた時に直す

1. **今実際に何が配信されているかを確認する。** 静的SVG方式で運用しているなら、READMEが実際に表示しているのは*コミット済みのファイル*なので、そちらを見る:
```bash
gh api repos/<owner>/<repo>/contents/<svgへのパス> --jq '.content' | base64 -d | grep -oE "<text[^>]*>[^<]*</text>"
```
ライブURL方式で運用しているなら、デプロイURLを直接curlする。

2. **エラー文言を読んで、既知の3パターンのどれに当てはまるか切り分ける**(変数が存在しない・変数が空・変数はあるが上流API呼び出しが失敗、の3つで、それぞれ直し方が違う。トークンの値そのものが悪いのは3パターン目だけ)。マッチさせるべき文言の具体例、決めつける前の確認方法、それぞれの直し方は`references/diagnosing-errors.md`にまとめてある。

3. **デプロイ自体がビルドの時点で失敗している場合**(エラーを表示するところまでも行っていない場合)は`references/vercel-deploy-bug.md`を見ること。これはプラットフォーム側の問題であって、トークンの問題として直そうとすると時間を無駄にする。

4. **環境変数やSecretsを変更したら、必ず再デプロイした上で、実際に配信されている中身を確認すること — ビルドやActionが緑になっただけで安心しない。** ビルド成功はコードがコンパイルできた証拠でしかなく、カードが正しく表示される証拠にはならない。確認コマンドは`references/diagnosing-errors.md#L63-76`。静的SVG方式で運用している場合は、次のスケジュール実行を待たずに生成ワークフローを一度手動実行し、修正を即座にREADMEへ反映させること。
115 changes: 115 additions & 0 deletions github-profile-stats-deploy/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
name: github-profile-stats-deploy
description: >
How to set up self-hosted GitHub profile stat cards (github-readme-stats,
github-readme-streak-stats, or similar PHP/Node forks) deployed on Vercel
and embedded in a GitHub profile README, and how to diagnose and fix them
when they break. Use this skill whenever the user wants to deploy their
own instance of a GitHub stats/streak card, when a profile README's stat
card shows an error like "Failed to retrieve contributions", ".env was not
found", or "Missing token in config", when a Vercel deployment for one of
these forks fails with "No more than 12 Serverless Functions", when a
GitHub Actions deploy for one of these forks fails, when the user asks
about setting up VERCEL_TOKEN/VERCEL_ORG_ID/VERCEL_PROJECT_ID for a stat
card project, or when the user says a profile stats/streak card is broken
or dead. Work through the relevant procedure below in order rather than
guessing at a fix — most failures here have a specific, previously-known
cause that isn't obvious from the error message alone.
---

# GitHub profile stats cards — setup & troubleshooting

This covers two related procedures: setting up a self-hosted stat card from
nothing, and fixing one that's already deployed but broken. Each step below
carries only the note relevant to that step; deeper explanations live in
`references/` and are linked from the step that needs them — read the
reference file only when that step's note tells you to, not up front.

## Procedure A: set up a stat card from scratch

1. **Fork the stat-card generator(s) you want** into your own GitHub account
— e.g. `anuraghazra/github-readme-stats` for a contributions/languages
card, `DenverCoder1/github-readme-streak-stats` for a streak card. You
can deploy one or both independently; they don't depend on each other.

2. **Create a GitHub Personal Access Token.** Scopes: `repo` + `read:user`.
Create it at `https://github.com/settings/tokens/new`.
> Prefer no expiration or a long one — an expired token is the most
> common cause of these cards breaking later, and it fails in a
> non-obvious way. See `references/secrets-and-tokens.md#L6-22`.

3. **Import each fork into Vercel as its own project** (Vercel dashboard →
Add New → Project → pick the repo). Confirm it worked: each project gets
its own `*.vercel.app` domain and runs an initial deployment (it's
expected to render an error at this point, since no token is registered
yet).

4. **Register the PAT as that project's environment variable.**
> The variable name is decided by the fork's own source code and is
> **not** consistent across forks — confirm the actual name before
> guessing. See `references/secrets-and-tokens.md#L24-50`.

Redeploy after saving, then confirm the card actually works:
```bash
curl -s "<your-project>.vercel.app/<card-path>?username=<your-username>" | grep -o "Total Contributions\|Failed to retrieve"
```

5. **If the deployment fails to build at all**, especially with an error
like "No more than 12 Serverless Functions can be added to a Deployment
on the Hobby plan":
> This is a known Vercel platform bug unrelated to your token or code.
> See `references/vercel-deploy-bug.md` for the `vercel.json` fix and,
> if needed, a GitHub-Actions-based deploy workaround
> (`references/vercel-deploy-bug.md#L20-41` and `#L43-86`).

6. **Decide how the README will reference the card**: a live `<img
src="https://your-project.vercel.app/…">`, or a static SVG fetched
server-side on a schedule and committed to the repo.
> A live URL is simpler to set up but can show a stale error for hours
> after you've already fixed the underlying deployment, because of
> caching layers between the origin and the viewer. See
> `references/cache-layers.md` for why, and for the shape of a
> scheduled fetch-and-commit setup if you'd rather avoid that class of
> bug entirely.

If you go with the static-SVG approach, the minimum viable version is:
a script that fetches each project's live SVG output (with a
cache-busting query param) and writes it to a file, plus a scheduled
workflow (e.g. every few hours, and `workflow_dispatch` for on-demand
runs) that runs the script and commits the result if it changed.

7. **Embed the card in `README.md`** — either the live URL or the static
file's relative path, per your choice in step 6. Confirm by viewing the
rendered profile page on github.com (not just the raw file — GitHub's
own page cache can also lag briefly after a fresh commit).

## Procedure B: fix a card that's already deployed but broken

1. **Check what's actually being served right now.** If you're running a
static-SVG setup, check the *committed file's* content — that's what the
README actually displays, not the live Vercel URL:
```bash
gh api repos/<owner>/<repo>/contents/<path-to-svg> --jq '.content' | base64 -d | grep -oE "<text[^>]*>[^<]*</text>"
```
If you're running a live-URL setup, curl the deployment URL directly
instead.

2. **Read the error text and match it to one of three known causes**
(missing variable, empty variable, or a failed upstream API call — each
needs a different fix and only one of them is actually about the token
value being wrong). See `references/diagnosing-errors.md` for the exact
wording to match on, how to verify each cause before acting on it, and
the fix for each.

3. **If the deployment itself won't build** (rather than building but
rendering an error), see `references/vercel-deploy-bug.md` — this is a
platform-level issue, not a token problem, and trying to fix it as if it
were a token problem wastes time.

4. **After changing any environment variable or secret, redeploy and verify
the actual served content — don't trust a green build/Action alone.**
A successful build only proves the code compiled, not that the card
renders correctly. See `references/diagnosing-errors.md#L63-76` for the
verification command, and if you're running the static-SVG setup, also
trigger that generation workflow once so the fix reaches the README
immediately instead of waiting for its next scheduled run.
59 changes: 59 additions & 0 deletions github-profile-stats-deploy/references/cache-layers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Why static SVGs beat a live `<img src="https://….vercel.app/…">`

Referenced from SKILL.md's setup step 6.

Embedding the Vercel deployment URL directly as a README `<img>` works, but
it fails in a way that's unusually hard to diagnose: the fix can be
completely correct and the card can *still* show the old error for hours
afterward, because the error got cached somewhere between the origin and
the viewer's eyes.

## The three independent cache layers

Many stat-card APIs (including the common `github-readme-stats` /
`github-readme-streak-stats` forks) set a long `Cache-Control` header on
their responses — e.g. `public, max-age=86400` (24h) — so repeat visitors
don't hammer the GitHub API on every page load. That's reasonable for a
*correct* response, but it applies just as much to an *error* response.
Once a broken response (say, from an expired token) gets cached, three
layers can each independently hold on to it:

1. **Vercel's own edge cache**, which honors the response's Cache-Control
and can keep serving the cached error for up to the stated max-age even
after you've fixed the underlying deployment.
2. **GitHub's `camo` image proxy** — every external image embedded in a
README is served through `camo.githubusercontent.com`, not the origin
directly. `camo` also respects the origin's Cache-Control, and in
practice can hold entries even longer than the stated max-age.
3. **The visiting browser's own HTTP cache.** If a viewer already loaded
the broken image once, revisiting the same URL can be served straight
from local disk cache without even a revalidation request to the
network, showing the old error indefinitely from that browser's point
of view.

Fixing the token only fixes what layer 1 serves to *new* cache entries.
Layers 2 and 3 keep whatever they already cached until their own TTL
expires — independently of each other and of the origin. Actively purging
`camo`'s cache (`curl -X PURGE https://camo.githubusercontent.com/…`) only
clears layer 2; layers 1 and 3 are untouched, so the same error can
resurface.

## The fix: don't let the README point at a cacheable live endpoint at all

Fetch the SVG **server-side**, on a schedule (e.g. a GitHub Actions workflow
running every few hours), and commit the result as a plain file in the repo
that hosts the README. Point the README's `<img>` at that committed file's
relative path instead of the live Vercel URL.

This sidesteps all three layers at once: a file committed to a repo isn't
served through `camo` (it's already same-origin as far as GitHub is
concerned) and carries none of the origin API's long-lived Cache-Control.
The only "staleness" left is bounded and expected — the gap between
schedule runs — not an indefinite, cache-layer-dependent one.

One more detail worth building into the fetch step: add a cache-busting
query parameter (e.g. a timestamp) to the URL your scheduled job fetches
from, so layer 1 (Vercel's own edge cache) can't hand your fetcher a stale
cached response either — you want the freshest possible data at generation
time, since whatever you commit now will sit there until the next
scheduled run regardless.
Loading
Loading