6月の頭、いつものように朝の通知を眺めていたら、クレジット残量がもう半分を切っていました。月が変わってまだ3日です。心当たりはすぐに付きました。前の晩に依存パッケージの自動更新PRが12本まとめて飛んできて、その全部でコードレビューのワークフローが走っていたのです。
私は個人開発で複数のアプリのリポジトリを抱えていて、そのCIに Claude Code のレビューを組み込んでいます。これまではサブスクリプションの枠内で動いていたので、走った回数を細かく気にしてはいませんでした。ところが 6/15 の課金変更で、その前提が変わります。ここでは、CIを止めずに消費だけを抑えるために私が入れた3層のガードを、動くワークフローと一緒に共有します。
6/15 に何が変わるのか — CI は「サブスクの内側」から外れる
2026年6月15日から、Claude Agent SDK・headless の claude -p・Claude Code GitHub Actions ・サードパーティ製エージェントは、サブスクリプションの上限とは別枠の月次クレジットへ移行します。クレジットはプランごとに付与され(おおむね $20 / $100 / $200 相当の枠)、full API レートで消費され、そして繰り越されません 。
ここで効いてくるのが「繰り越されない」という性質です。月末に余らせても損ですが、月初に使い切ると、その月はもうCIで自動レビューが回りません。サブスク時代は「走りすぎても定額」でしたが、これからは走った分がそのまま枠を削ります。
変更の全体像と、どの工程を headless のまま残すかという判断は6/15 の Claude Code 課金変更で headless 実行はどう変わるのか に整理しました。本記事はそのうち、見落とされがちな GitHub Actions に絞って掘り下げます。
消費の正体は「走った回数 × 1回の重さ」
クレジットの消費は、突き詰めると2つの掛け算です。
走った回数 :何回ワークフローが起動したか
1回の重さ :1回あたり何トークン読み書きしたか
崩れていたのは前者でした。私のリポジトリでは on: pull_request と on: push の両方でレビューが走り、しかも依存更新ボットのPRやドキュメントだけの修正、下書き(draft)PRまで例外なく対象にしていました。月のCI起動のうち、人間のコードレビューとして意味があったのは半分以下だったのです。
後者も無視できません。数千行の巨大なリファクタリングPRが来ると、diff全体をコンテキストに積むため、1回で通常の何十倍ものトークンを消費します。回数を絞っても、この「重い1回」が月の枠を一気に削ることがあります。
そこで、実行条件で回数を削り(第1層)、1回の上限を決め(第2層)、消費を可視化する(第3層)という順で手を入れました。
第1層:いつ走らせるか — 実行条件で回数を削る
最初に効いたのは、起動条件そのものを絞ることでした。GitHub Actions 側だけで完結し、Claude を呼ぶ前に弾けるので、ここで落としたPRはクレジットを1トークンも使いません。
私が入れた条件は4つです。第一に、push トリガーをやめて pull_request に一本化します。第二に、コードに関係のないパス(ドキュメントや設定)だけの変更は対象から外します。第三に、下書きPRとボットが作ったPRはスキップします。第四に、concurrency で、同じPRに新しいコミットが積まれたら古いrunを打ち切ります。
name : claude-review
on :
pull_request :
types : [ opened , ready_for_review , synchronize ]
paths :
- "src/**"
- "app/**"
- "lib/**"
- "**/*.ts"
- "**/*.tsx"
- "**/*.swift"
- "**/*.kt"
# 同じPRに新しいコミットが来たら、進行中のレビューを打ち切る
concurrency :
group : claude-review-${{ github.event.pull_request.number }}
cancel-in-progress : true
permissions :
contents : read
pull-requests : write
jobs :
gate :
runs-on : ubuntu-latest
# 下書きPR・ボットのPR・[skip-ai] ラベル付きは走らせない
if : >-
github.event.pull_request.draft == false &&
github.actor != 'dependabot[bot]' &&
github.actor != 'renovate[bot]' &&
!contains(github.event.pull_request.labels.*.name, 'skip-ai')
outputs :
proceed : ${{ steps.size.outputs.proceed }}
steps :
- uses : actions/checkout@v4
with :
fetch-depth : 0
- id : size
name : diff のサイズで足切り
run : |
BASE="${{ github.event.pull_request.base.sha }}"
HEAD="${{ github.event.pull_request.head.sha }}"
CHANGED=$(git diff --numstat "$BASE" "$HEAD" -- \
':(exclude)**/*.lock' ':(exclude)**/*.snap' \
| awk '{added+=$1; removed+=$2} END {print added+removed}')
echo "changed lines: ${CHANGED:-0}"
# 1500 行を超える巨大PRはレビューしない(人間に分割を促す)
if [ "${CHANGED:-0}" -gt 1500 ]; then
echo "proceed=false" >> "$GITHUB_OUTPUT"
else
echo "proceed=true" >> "$GITHUB_OUTPUT"
fi
paths フィルタは pull_request イベントでは「変更ファイルの中に一致するものが1つでもあるか」で判定されるため、ドキュメントだけのPRは job 自体が起動しません。ラベルによる手動の skip-ai を用意しておくと、レビュー不要だと分かっているPRを人間の判断で外せます。
この4条件を入れただけで、月のCI起動回数はおよそ6割減りました。減ったのはほとんどが「ボットの依存更新」と「下書きへの細かいpush」で、人間のレビュー体験は何も損なわれていません。
第2層:1回をどこまで重くするか — diff とモデルの上限
回数を絞っても、残った1回が重ければ枠は削れます。第2層では、1回あたりの上限を2つ決めました。
ひとつは、上のゲートjobに入れた diff のサイズ上限 です。1,500行を超えるPRはレビューせず、代わりに「分割してほしい」というコメントだけ残します。巨大PRはレビューの精度も落ちるので、クレジットの面でも品質の面でも分割を促すほうが合理的だと考えています。
review :
needs : gate
if : needs.gate.outputs.proceed == 'true'
runs-on : ubuntu-latest
permissions :
contents : read
pull-requests : write
steps :
- uses : actions/checkout@v4
with :
fetch-depth : 0
- name : Claude Code レビュー
uses : anthropics/claude-code-action@v1
with :
anthropic_api_key : ${{ secrets.ANTHROPIC_API_KEY }}
# モデルを明示的に固定する。上位モデルへの自動アップグレードで
# クレジットが想定外に溶けるのを防ぐ
claude_args : "--model claude-sonnet-4-6 --max-turns 6"
prompt : |
このPRの diff だけをレビューしてください。リポジトリ全体の探索は不要です。
観点は「明確なバグ」「セキュリティ上の懸念」「破壊的変更」の3点に絞り、
それぞれ該当箇所の行を引用して簡潔に指摘してください。
問題がなければ「LGTM」とだけ返してください。
too-large :
needs : gate
if : needs.gate.outputs.proceed == 'false'
runs-on : ubuntu-latest
permissions :
pull-requests : write
steps :
- name : 分割を促すコメント
uses : actions/github-script@v7
with :
script : |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: "このPRは変更が大きいため自動レビューをスキップしました。1,500 行以下に分割いただけると、レビュー精度とCIコストの両面で助かります。"
});
もうひとつは モデルの固定 です。サブエージェントやフォールバックが暗黙のうちに上位モデルへ上がると、同じ作業でもクレジットの溶け方が変わります。CIでは精度と費用の釣り合うモデルを --model で明示的に指定し、自動アップグレードに任せないことを私は推奨します。さらに --max-turns で1回あたりの往復回数に天井を付けておくと、想定外のループでの暴走も止められます。
管理側からモデルを固定する enforceAvailableModels の使い方はenforceAvailableModels で実行モデルを固定する設計 に詳しくまとめてあります。CIだけでなく開発者のローカル実行も一緒に縛りたい場合はこちらが効きます。
prompt で「diff だけを見る・観点を3点に絞る」と指示しているのも費用対策です。リポジトリ全体を探索させるとトークンが跳ね上がるため、CIのレビューでは見る範囲を意図的に狭めています。
第3層:いくら使ったかを毎回見えるところに残す
回数と上限を決めても、実際にいくら使っているかが見えなければ、月の半ばで「あと何回回せるか」を判断できません。第3層では、各runの消費をジョブサマリに残しました。
Claude Code Action は実行ログに使用トークンを出力します。これを拾ってGitHub の $GITHUB_STEP_SUMMARY に書き出すと、PRごとの消費が Actions の画面に残ります。
- name : トークン消費をサマリに記録
if : always()
run : |
# 直近の run ログから入出力トークンを抽出する(出力形式に合わせて調整)
IN=$(grep -oE '"input_tokens":[0-9]+' claude-output.json | grep -oE '[0-9]+' | paste -sd+ | bc)
OUT=$(grep -oE '"output_tokens":[0-9]+' claude-output.json | grep -oE '[0-9]+' | paste -sd+ | bc)
# Sonnet クラスの概算単価で円換算(自分の単価に置き換える)
# 入力 $3 / 出力 $15 per MTok、1ドル=155円と仮定
COST=$(echo "scale=2; (${IN:-0}/1000000*3 + ${OUT:-0}/1000000*15) * 155" | bc)
{
echo "### Claude レビュー消費"
echo "- 入力トークン: ${IN:-0}"
echo "- 出力トークン: ${OUT:-0}"
echo "- 概算コスト: 約 ${COST} 円"
} >> "$GITHUB_STEP_SUMMARY"
数字が画面に残ると、運用の感覚が一気に変わります。私の場合、1回のPRレビューはおおむね20〜40円程度に収まっていて、巨大PRをゲートで弾いた効果が金額としても確認できました。月の前半で消費が想定を超えていれば、skip-ai ラベルの運用を一時的に厳しくする、といった調整も数字を見て決められます。
月単位でこの消費をならし、月初に枯らさず月末に余らせない配分の考え方は繰越なし月次クレジットのバーンレート配分 に書きました。CI単体ではなく、自動運用全体でクレジットを配りたい場合の続きとして読んでいただけます。
fork PR とクレジットの落とし穴
ここで本番運用の注意点を1つ共有します。外部コントリビューターからの fork PR では、pull_request イベントにシークレットが渡りません。つまり ANTHROPIC_API_KEY が空になり、レビュー job は失敗します。
これを「動かないから」と pull_request_target に変えるのは危険です。pull_request_target は base リポジトリの権限とシークレットを持った状態で fork のコードを扱うため、悪意あるPRにシークレットを抜かれる典型的な経路になります。私自身は、外部PRでは自動レビューを走らせず、メンテナがラベルを付けたときだけ信頼済みワークフローで走らせる運用にしています。
gate :
# 自分のリポジトリ内のPR、または明示的に許可ラベルが付いた場合のみ
if : >-
github.event.pull_request.head.repo.full_name == github.repository ||
contains(github.event.pull_request.labels.*.name, 'ai-review-approved')
App Store や Google Play に出すアプリのリポジトリでは、シークレットの扱いを誤ると署名鍵の漏洩にも繋がりかねません。クレジット節約のためにセキュリティを緩めるのは本末転倒なので、ここは堅く倒すことを優先しています。
数字で見えた変化と、次の一手
3層を入れた後、最初の1か月で月のCI起動回数はおよそ6割減り、クレジットの消費は月末まで予測できる範囲に収まりました。レビューが必要なPRはこれまで通り全部カバーできていて、減ったのはボットと下書きへの空振りだけです。巨大PRをゲートで弾いたことで、1回の最大消費も読めるようになりました。
もしこれから手を付けるなら、第1層の gate job をまず1つ入れることをお勧めします。paths と draft 判定、ボット除外、concurrency の4点はGitHub Actions 側だけで完結し、Claude を一切呼ばずに無駄な起動を止められます。可視化やモデル固定は、その後で順に足していけば十分です。同じように個人や少人数でCIを回している方の、月初に慌てない助けになれば嬉しいです。