TL;DR: Authenticate every GitHub API request with the key in the Authorization header so the higher authenticated rate limit applies, and add backoff as the limit gets close. The silent drop to 60 requests per hour for unauthenticated calls is documented behavior, and a sourcing loop that forgets the header keeps hitting it. After the fix, the loop reads the rate-limit headers and slows down before getting cut off.

```text
agent's GitHub token got rate-limited mid-sourcing  -  the unauthenticated fallback dropped to 60 req/hr without anyone noticing
```

1. Check the current rate-limit status with the rate-limit endpoint using the key. Expected: the response shows the authenticated quota and how much remains.
2. Confirm the key is actually being sent: inspect the request headers in the sourcing code. Expected: the Authorization header is missing on the failing calls, which is why they counted against the anonymous quota.
3. Set the header on every request and re-run a small batch. Expected: the remaining quota reflects the authenticated limit, not 60 per hour.
4. Add handling for the rate-limit response: read the retry-after value, pause, and resume. Expected: the loop pauses instead of failing when it gets close to the limit.

## Use this when
- GitHub sourcing throughput collapses to a trickle mid-run
- Rate-limit headers show the 60-per-hour anonymous quota despite having a key
- A key rotation or config change recently touched the sourcing code

## Not for this skill when
- The limit being hit is the higher authenticated limit (then the fix is pacing, not auth)
- Requests fail with 401, which means the key itself is invalid or revoked
- The sourcing uses the web UI rather than the API

## Variant phrasings
### GitHub API rate limit 60 per hour during sourcing despite having a key
### Sourcing loop lost its GitHub auth header and got throttled
### GitHub unauthenticated rate limit hit by agent

## Why it happens
GitHub applies two different quotas: a generous one for authenticated requests and 60 per hour for anonymous ones. If the Authorization header is dropped (wrong env var after a deploy, a code path that builds requests without it, a key rotation that emptied the config), every call silently counts as anonymous. The loop keeps running at a crawl and nobody notices until the sourcing queue backs up.

## Edge cases
- Secondary rate limits: even authenticated requests can get 403s for concurrency patterns, so backoff should trigger on 403 as well as 429
- Keys with the wrong scopes return 404 instead of data on some endpoints: verify scopes, not just the quota
- Multiple workers sharing one key split the quota: either give each worker its own key or coordinate through a shared limiter

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_C-M2Y7Q79OAhcwdJx2b2Jg
