You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix: cut ci-status API polling and make the intake labeler wait out a rate limit #855
The claude-code-plugins repository spends its whole GITHUB_TOKEN core bucket in under an hour. Run 39732240888's headers read remaining=0 used=5000 limit=5000, with the reset at 06:16:20Z. Lanes then fail at about XX:09-11, just before each reset.
pr-require-checks aggregate-results (ci-status): about 77 runs/hr. A static estimate puts it at about 15-30 calls per run, roughly 1,150-2,300/hr, likely the top consumer. Its waits poll the sibling runs every 10 s during a 90 s rerun wait, and every 5 s during a 30 s yield.
intake-label-needs-triage: its github-script step fails at once on a rate-limit 403. Run 39732372419 failed this way, so a new issue never got its floor needs-triage label.
Proposal
In intake-label-needs-triage.yml's github-script step, on a 403/429, wait once the way gh-api.sh does: retry-after if set, else the reset time when remaining is 0, else 60 s. Cap the wait inside the job timeout, then fail with the reset time in the message.
Add an api-calls count line to gh-api.sh, the way claude-code-plugins' budgetedFetch prints api-calls rest=N, so each run reports what it spent.
Using those numbers, cut aggregate-results' polling: list the sibling runs once per wait step, or back off between polls instead of polling at a fixed 10 s/5 s.
Acceptance
A rate-limited intake run waits and applies the label once the bucket resets.
ci-status runs report their API call count.
After the polling change, per-run calls drop by a measured amount.
One more intake cut belongs here, from the claude-code-plugins GITHUB_TOKEN budget work on 2026-10-25.
The repository owner set the plan for GITHUB_TOKEN at GitHub's documented 1,000 requests/h per repository (REST rate limits: "The rate limit for GITHUB_TOKEN is 1,000 requests per hour per repository."). Measured core use in claude-code-plugins is about 4,470/h across the two hourly counters seen in its headers. On 10-24 one counter was refused at used=5000 (run 40113473063).
Intake is among the top spenders and cannot be cut from the caller. claude-code-plugins calls intake-triage.yml@215cec5 (v0.65.10, intake-triage.yml:204 there) and intake-label-needs-triage.yml@5e18f3d (v0.58.0, intake-label-needs-triage.yml:108). The estimate for intake triage is 430-600 core calls/h at about 17 runs/h. That figure is an estimate (UNVERIFIED): these reusables post no api-budget notice, so the caller cannot measure them.
Proposed cut: fold the needs-triage label job into the triage run and read each issue once, rather than reading it in both workflows. Estimated saving 60-150 core/h (UNVERIFIED). The trade-off is that labels land at the end of triage instead of at once.
Also asked: have both reusables emit the same api-budget notice the caller's log-api-budget action writes (token=… limit= remaining= used= resource=), so the saving can be measured before and after.
Sources: the attribution study (rows 1 and 3, "Cuts" row 3), and the call-reduction research, verified 2026-10-25: read github.event instead of re-fetching, and use per_page=100.
One more change in the same budget area, raised from claude-code-plugins on 2026-10-25: check-key-credit (#882, v0.65.8) can't be reused by lanes that run far more often than the review lanes.
The aim is to let claude-code-plugins' issue lane, pr-unblock (5 legs) and pr-refine skip the API-key leg after a credit stop and go straight to the subscription leg, as the review lanes already do. That saves about 5 runner jobs per run while credits are out, plus the second reusable-workflow call. Lines read at v0.65.8 in .github/actions/check-key-credit/gate.cjs:
:35const MODEL_STEP = "Claude review"; is hard-coded, so another lane's model step is never matched.
:36const MAX_JOB_READS = 3; caps the reads at the 3 newest runs. Skipped runs use up those reads without settling anything.
:66-74jobNamed() matches job.name === name || job.name.endsWith(" / " + name), so a caller with several jobs named run matches more than one.
:89 decides "in window" by membership in the listed run ids (windowIds.has(...)). work-resolve-issue.yml has about 1,007 runs per 24 h, 94 of the last 100 skipped, so a carried record falls out of the list after about 2.4 h, not the configured 6 h.
Proposed change, with defaults that keep today's review-lane behavior:
Drop conclusion == "skipped" runs before the read cap. The run listing already carries conclusion, so this needs no extra call.
Judge the window by the origin run's created_at, not by list membership.
Add inputs for the model-step name and the exact key-job name.
Changes 1 and 2 likely help the review lanes too. Once this is released, claude-code-plugins pins it, with the record step in the read runner's run job after act-key, where #882 itself places it.
Activity
kyle-sexton commentedon Oct 25, 2026
One more intake cut belongs here, from the claude-code-plugins GITHUB_TOKEN budget work on 2026-10-25.
The repository owner set the plan for GITHUB_TOKEN at GitHub's documented 1,000 requests/h per repository (REST rate limits: "The rate limit for
GITHUB_TOKENis 1,000 requests per hour per repository."). Measured core use in claude-code-plugins is about 4,470/h across the two hourly counters seen in its headers. On 10-24 one counter was refused atused=5000(run 40113473063).Intake is among the top spenders and cannot be cut from the caller. claude-code-plugins calls
intake-triage.yml@215cec5(v0.65.10,intake-triage.yml:204there) andintake-label-needs-triage.yml@5e18f3d(v0.58.0,intake-label-needs-triage.yml:108). The estimate for intake triage is 430-600 core calls/h at about 17 runs/h. That figure is an estimate (UNVERIFIED): these reusables post no api-budget notice, so the caller cannot measure them.Proposed cut: fold the needs-triage label job into the triage run and read each issue once, rather than reading it in both workflows. Estimated saving 60-150 core/h (UNVERIFIED). The trade-off is that labels land at the end of triage instead of at once.
Also asked: have both reusables emit the same api-budget notice the caller's
log-api-budgetaction writes (token=… limit= remaining= used= resource=), so the saving can be measured before and after.Sources: the attribution study (rows 1 and 3, "Cuts" row 3), and the call-reduction research, verified 2026-10-25: read
github.eventinstead of re-fetching, and useper_page=100.kyle-sexton commentedon Oct 25, 2026
One more change in the same budget area, raised from claude-code-plugins on 2026-10-25:
check-key-credit(#882, v0.65.8) can't be reused by lanes that run far more often than the review lanes.The aim is to let claude-code-plugins' issue lane, pr-unblock (5 legs) and pr-refine skip the API-key leg after a credit stop and go straight to the subscription leg, as the review lanes already do. That saves about 5 runner jobs per run while credits are out, plus the second reusable-workflow call. Lines read at
v0.65.8in.github/actions/check-key-credit/gate.cjs::35const MODEL_STEP = "Claude review";is hard-coded, so another lane's model step is never matched.:36const MAX_JOB_READS = 3;caps the reads at the 3 newest runs. Skipped runs use up those reads without settling anything.:66-74jobNamed()matchesjob.name === name || job.name.endsWith(" / " + name), so a caller with several jobs namedrunmatches more than one.:89decides "in window" by membership in the listed run ids (windowIds.has(...)).work-resolve-issue.ymlhas about 1,007 runs per 24 h, 94 of the last 100 skipped, so a carried record falls out of the list after about 2.4 h, not the configured 6 h.Proposed change, with defaults that keep today's review-lane behavior:
conclusion == "skipped"runs before the read cap. The run listing already carriesconclusion, so this needs no extra call.created_at, not by list membership.Changes 1 and 2 likely help the review lanes too. Once this is released, claude-code-plugins pins it, with the record step in the read runner's run job after
act-key, where #882 itself places it.