GitHub ActionsでClaude Codeを動かしてパーミッションエラーに詰まった人向け。このガイドでは、実際に機能する3つのパターンを使って解決策を具体的に説明する。
根本原因はほぼ共通している。Claude Codeはインタラクティブな使用を前提に設計されている。ファイルの書き込みやBashコマンドの実行、センシティブな操作を行う前に確認を求めてくる。CI環境には「Yes」をクリックする人間がいない。ワークフローはハングし、タイムアウトし、謎めいたエラーで終了する。
何が起きているのかを整理して、乗り越える方法を見ていこう。
なぜCI環境でパーミッションエラーが起きるのか
ローカルで claude -p "何かやって" を実行する場合、Claude Codeのパーミッションシステムは意図通りに動く。アクションを実行する前に一時停止して、承認を待つ。これは機能として正しい。
GitHub Actionsでは、その同じ振る舞いが致命的な問題になる。ランナーにはインタラクティブなターミナルがない。ユーザー入力を待つプロンプトは、ジョブがタイムアウトに達するまで無限にブロックし続ける。
エンジニアがよく踏むエラーを具体的に挙げると:
パーミッションプロンプトがワークフローをハングさせる:
Bash command: npm install
Do you want to proceed?
> 1. Yes
> 2. No
ジョブはここから先に進まない。
インタラクティブモードの検出失敗:
Error: Cannot use interactive mode in a non-TTY environment
Use --output-format text for non-interactive output
ファイル編集の承認が必要:
Edit file: src/index.ts
This will modify the file. Approve?
3つとも根本原因は同じだ。Claude Codeのデフォルトモードはループ内に人間がいることを前提にしている。CIのためには、人間が来ないことを明示的に伝える必要がある。
パターン1:公式 claude-code-action を使う(多くのチームに推奨)
最もすっきりした解決策は、Anthropic公式の claude-code-action を使うことだ。非インタラクティブなセットアップを自動で処理してくれる。PRやIssueで @claude メンションを使いたい場合や、GitHubイベントで起動する自動化ワークフローを作る場合は、このアプローチを選ぶべきだ。
ステップ1:APIキーをリポジトリシークレットに追加する
リポジトリの Settings → Secrets and variables → Actions を開いて以下を追加する:
ANTHROPIC_API_KEY— console.anthropic.com で取得したClaude APIキー
ワークフローファイルにハードコードしてはいけない。GitHubはログ上でシークレットを伏字にしてくれるが、YAMLに直接書いてしまうとリポジトリの履歴に残る。
ステップ2:Claude GitHubアプリをインストールする
インストール先: https://github.com/apps/claude
アプリには Contents、Issues、Pull requests の読み書き権限が必要だ。これにより、Claudeが変更をプッシュしたり、PRにコメントしたり、Issueに応答したりできるようになる。
ステップ3:ワークフローファイルを作成する
# .github/workflows/claude.yml
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
permissions:
contents: write
pull-requests: write
issues: write
jobs:
claude:
runs-on: ubuntu-latest
# @claudeがメンションされた時だけ実行する
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
最小限の動く構成はこれだけだ。デプロイできたら、任意のPRやIssueコメントで @claude このIssueに書かれた変更を実装して とトリガーできる。
カスタムインストラクションの追加
プロジェクト固有の振る舞いを指定したい場合は、リポジトリルートに CLAUDE.md ファイルを置く。Claudeは毎回自動的に読み込む。ワークフローから直接インストラクションを渡すこともできる:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: "このPRをレビューして、セキュリティ上の問題があればフラグを立てて"
claude_args: "--max-turns 10 --model claude-sonnet-4-6"
claude_args パラメータはフラグをClaude Code CLIに直接渡す。ターン数の上限、モデルの選択、許可するツールの制御に使う。
パターン2:.claude/settings.json でツールを事前承認する
claude -p を直接実行する場合(アクション経由ではなく)、パーミッションプロンプトを避ける最もクリーンな方法は、リポジトリにチェックインした .claude/settings.json ファイルでClaudeが必要とするツールを事前承認することだ。
このアプローチはピンポイントの制御を提供する。全パーミッションチェックをスキップするのではなく、Claudeに何を許可するかを明示的にリストアップする。不必要なアクセスを開放せずにCIを安定して動かしたい場合に適した選択だ。
settings.jsonの基本構造
{
"permissions": {
"allow": [
"Bash(npm install)",
"Bash(npm run build)",
"Bash(npm run test)",
"Bash(npm run test:*)",
"Bash(git status)",
"Bash(git diff *)",
"Edit(/src/**)",
"Read(/src/**)",
"Read(/tests/**)"
],
"deny": [
"Bash(git push *)",
"Bash(rm -rf *)",
"Bash(curl *)"
]
}
}
ルールは順番に評価される: deny → ask → allow。最初にマッチしたルールが適用される。上位レベルのdenyルールは、下位レベルのallowルールで上書きできない。
ワイルドカードパターン
* ワイルドカードはスペースを含む引数全体にマッチする。知っておく価値のあるパターンをいくつか挙げる:
| ルール | マッチする対象 |
|---|---|
Bash(npm run *) | npm run build、npm run test:unit、任意のnpmスクリプト |
Bash(git * main) | git checkout main、git push origin main |
Edit(/src/**) | /src/ 配下の任意のファイル |
Read(.env) | カレントディレクトリの任意の深さにある .env |
重要: Bash(npm run build) はその完全一致コマンドにのみマッチする。Bash(npm run *) は任意の npm run 呼び出しにマッチする。必要な箇所では具体的に書くこと。
パーミッションモード
個別ルールとは別に、設定でデフォルトモードを指定できる:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git status)",
"Edit(/src/**)"
],
"defaultMode": "acceptEdits"
}
}
acceptEdits モードはファイル編集と、ワーキングディレクトリ内のパスに対する一般的なファイルシステムコマンド(mkdir、touch、mv、cp)を自動承認する。パーミッションシステムを完全に無効にせずにプロンプトを減らせる。
事前承認済みツールでClaudeを非インタラクティブに実行する
# .github/workflows/claude-ci.yml
name: Claude Code CI
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Run Claude Code review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
claude -p "このPRの変更を正確性と潜在的なバグの観点でレビューして。
発見した内容のサマリーを出力して" \
--output-format text \
--max-turns 5
--output-format text フラグはClaudeを非インタラクティブな出力モードに切り替える。TTYを持たないCI環境に対応している。
パターン3:隔離されたコンテナ向け bypassPermissions モード
ジョブが本番の認証情報もセンシティブなインフラへのアクセスも持たない完全に隔離されたコンテナで動く場合、bypassPermissions モードを使って全パーミッションプロンプトをスキップできる。
これは古いドキュメントでの --dangerously-skip-permissions に相当する。現在の推奨アプローチは .claude/settings.json で設定することだ:
{
"permissions": {
"defaultMode": "bypassPermissions"
}
}
またはコマンドラインから渡す:
- name: Run Claude Code
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
claude -p "失敗しているテストを修正して実装を更新して" \
--output-format text \
--max-turns 20
settings.jsonで bypassPermissions を設定すると、Claudeは承認待ちなしにコマンドを実行する。
bypassPermissionsがそれでもブロックするもの
バイパスモードが有効でも、Claude Codeは2つのサーキットブレーカーを維持する:
rm -rf /とrm -rf ~— ファイルシステムルートとホームディレクトリの削除は引き続きプロンプトが出る.git、.config/git、.claude、.vscode、.huskyおよび類似の設定ディレクトリへの書き込みは引き続きプロンプトが出る(これは既知のペインポイント — 後述のKnown Issuesを参照)
セキュリティのトレードオフ
bypassPermissions が適切なのは、環境自体が隔離を提供している場合に限る。実際には以下を意味する:
- 新規のGitHub Actionsランナーで動かす(エフェメラルで、ジョブごとにリセット)
- 環境に本番の認証情報が存在しない
- センシティブな外部サービスへのアクセスがない
- ワークフローの権限を必要最小限にスコープしている
ubuntu-latest 上のGitHub Actionsジョブは通常これらの条件を満たす。ランナーは新規VMで、ジョブ完了後に破棄され、どのシークレットにアクセスできるかを自分でコントロールできる。
満たさない例: バイパスモードを有効にして自分のフル認証情報が入った環境でローカルマシン上のClaudeを動かすケース。そこで人は痛い目を見る。
# .github/workflows/claude-autofix.yml
name: Claude Code Autofix
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
autofix:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Run automated fix
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
claude -p "npm testを実行して。テストが失敗していたら、失敗内容を分析して修正して。
変更があれば説明的なメッセージでコミットして" \
--output-format text \
--max-turns 15
- name: Push changes
run: |
git config --global user.name "Claude Code Bot"
git config --global user.email "[email protected]"
git push
おまけ:ANTHROPIC_API_KEYの設定とコスト管理
APIキーの保存
CIワークフローでAPIキーを置く場所はGitHub Secretsだけが許容される。キーは Settings → Secrets and variables → Actions → New repository secret に追加する。
ワークフロー内での参照方法:
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
またはアクションのinputとして:
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
多くのリポジトリでClaudeを動かしている組織では、シークレットをOrganizationレベルに置いてリポジトリを横断して選択的に共有できる。各リポジトリでキーを管理するより簡単だ。
CIでのコスト管理
GitHub Actions上のClaude Codeの実行は毎回APIトークンを消費する。アクティブなリポジトリでは積み重なる。主な制御手段:
--max-turns を設定する: ジョブあたりのClaudeのやり取り回数を上限で制御する。レビュータスクなら5〜10ターンで十分なことが多い。実装タスクなら15〜20ターン。上限を設定しなければ、必要以上に多くのターンを実行する可能性がある。
claude_args: "--max-turns 10"
ワークフローのコンカレンシー制限を使う: 複数のPRが同時にオープンした場合、全部でClaudeをトリガーしたくないかもしれない。
concurrency:
group: claude-${{ github.ref }}
cancel-in-progress: true
選択的にトリガーする: ジョブの if 条件でClaudeが実行されるタイミングを絞れる。@claude メンションパターンは便利で、明示的にリクエストされた時だけ実行され、プッシュのたびには実行されない。
ジョブタイムアウトを設定する: timeout-minutes を追加して暴走ジョブを防ぐ。
jobs:
claude:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
# ...
どのモデルを使うか
claude-code-action のデフォルトモデルはSonnetだ。コードレビュー、テスト修正、ドキュメント作成といったほとんどのCIタスクにはSonnetが適している。速くて、実行あたりのコストも管理しやすい。
最高品質の推論が必要な複雑なアーキテクチャ作業の場合:
claude_args: "--model claude-opus-4-8"
Opusはトークンあたりのコストがsonnetの約5倍かかる。品質の差がコストに見合うタスクに限定して使おう。
最新バージョンにおける --dangerously-skip-permissions の既知の問題
公式アクションを使わずClaude Codeを動かしていて、--dangerously-skip-permissions CLIフラグを使っている場合、2026年半ば時点で2つのバグに注意が必要だ:
v2.1.77より新しいバージョンでフラグが無視される可能性がある。 最近のリリースではバイパスモードが実質的に壊れているという報告がある — フラグを設定しているのに、Claudeがすべてのファイル編集とBashコマンドでプロンプトを出し続ける。ワークアラウンドはv2.1.77に固定するか、CLIフラグの代わりに .claude/settings.json で "defaultMode": "bypassPermissions" を使うことだ。
設定ディレクトリへの書き込みは引き続きプロンプトが出る。 バイパスモードが有効でも、~/.claude/ パスへの書き込みはバイパスモードがカバーしない別のパーミッションカテゴリをトリガーする。Claude Codeのリポジトリでバグとして追跡されている。ワークアラウンドは、CIの実行中にClaudeが自身の設定ディレクトリに書き込む必要がないようにすることだ — コードタスクであれば通常は問題ない。
公式の claude-code-action はこれらのエッジケースを内部で処理している。カスタムセットアップでこれらのバグに当たっている場合は、アクションへの切り替えを検討する価値がある。
適切なパターンの選び方
| 状況 | 推奨パターン |
|---|---|
チームがPRやIssueで @claude を使いたい | パターン1: claude-code-action |
| トリガー不要で全PRに自動レビュー | パターン1(prompt パラメータ付き) |
CIでカスタムの claude -p スクリプト、特定ツールが必要 | パターン2: settings.json allowlist |
| 完全隔離コンテナ、広範な自動化 | パターン3: bypassPermissions モード |
| Claudeが触れるものを最大限コントロールしたい | パターン2: 細粒度のallowlistルール |
ほとんどのチームはパターン1から始めるべきだ。CI環境のセットアップを正しく処理し、GitHubのパーミッションモデルとうまく連携し、Anthropicがメンテナンスしている。settings.jsonアプローチ(パターン2)は、よりカスタムなパイプラインを構築する場合に役立つ。パターン3は、真に隔離された環境で最大限の自律性が必要な場合向けだ。
関連記事
GitHub ActionsでClaude Codeをセットアップするなら、次の記事も読んでおくといい:
- Claude Code Best Practices: The Official and Community-Tested Guide for 2026 — CLAUDE.mdのセットアップ、フック、ワークフロー最適化を解説。CI構成に直接応用できる
- AGENTS.md in CI/CD: Automated Diff Review, Validation, and Drift Detection — AIエージェント設定ファイルをコードベースと同期し続けるためのGitHub Actionsの組み方
パーミッションシステムのドキュメントも code.claude.com/docs/en/permissions で直接読む価値がある — ワイルドカードパターンのリファレンスは、厳密なallowlistルールを書く際に特に参考になる。