gh CLI × Claude Code で GitHub Actions 失敗ログをチャットで即解決

ども!最近 GitHub Actions の Workflow を新規で書くことが増えている龍ちゃんです。Bicep のデプロイパイプラインとか、ブログのビルドチェックとか、地味に CI 周りをいじる機会が多いんですよね。

GitHub Actions のログ確認で作業が途切れる問題

CI をいじってると避けられないのが「CI が落ちたときの確認作業」。VS Code の GitHub Actions 拡張機能を入れてれば、どのステップが落ちたかはサイドバーのツリーで確認できます。ただ、拡張機能が教えてくれるのは 「どこが落ちたか」 まで。

「なぜ落ちたのか」をテキストレベルで確認する手段 が足りないんですよね。エラーログの中身を確認しようとすると、ブラウザで GitHub Actions の Run ページを開いて、ジョブを展開して、ログをコピーして…というエディタとブラウザの反復横跳びが発生します。コードの修正を Claude Code と進めてる最中だったら、作業の流れもそこで切れてしまう。

僕がほしかったのは、「なぜ落ちたか」のログを VS Code 内でテキストとして取得できる仕組み でした。テキストさえ手に入れば、「どう直すか」は Claude Code が分析してくれます(人間もやるよ…)。そこで、Claude Code の Skills(SKILL.md)と GitHub CLI(gh コマンド) を組み合わせて、CI のログ取得から分析までを VS Code 内で完結させるスキルを作りました。この記事ではスキルの使い方と作り方を解説します。SKILL.md やデモ用 Workflow の全文は付録に載せているので、すぐ試したい人はそちらもどうぞ。

gh-workflow スキルで何が変わるか

/gh-workflow スキルを入れると、Claude Code のチャットで「CI 失敗してるから見て」と打つだけで、失敗した Run の特定 → ログの取得 → 原因分析 → 修正方針の提示まで一気に進みます。SKILL.md に gh CLI の手順を書いておくだけで、Claude がログ取得から分析まで全部やってくれる仕組みです。

なお、GitHub Actions 拡張機能は「どこが落ちたか」のツリー確認や YAML 編集支援が得意で、このスキルは「なぜ落ちたか」のログ取得と分析が得意です。置き換えではなく補完関係なので、両方入れておくのがおすすめです。

なぜ gh CLI + スキルを選んだか

CI のログを VS Code 内で取得する方法は他にもあります。GitHub MCP Server の Actions toolset を使えば、list_workflow_runsget_job_logs といったツールで同等のことが実現できます。機能的には十分ですが、MCP はツールの戻り値が大きくなりがちで、トークン消費が膨らみやすいというのはわりとあるあるな話です。また、Claude Code の組み込みツール(WebSearch / WebFetch)で GitHub の情報を取りにいくという手もなくはありません。

その上で gh CLI + SKILL.md を選んだのは、僕の環境に合っていたからです。

  • CLI があるなら CLI で叩きたい。
    これは完全に好みの話ですが、サービスが公式 CLI を出しているなら、僕は CLI を選びがちです。MCP だとツールの戻り値をスキル側でコントロールしにくいけど、CLI なら --json--jq で出力形式を自在に絞れる。SKILL.md に書く手順も Bash コマンドそのままなので、トークン効率のルールをスキル側で設計しやすいのが大きいです
  • プロジェクトで利用実績があった。
    Bicep との統合でシークレット登録に gh CLI を使っていたので、認証周りは設定済みだった
  • 認証が gh auth で済む。
    devcontainer の postCreateCommand に入れておけば、環境構築時に自動で認証できる
  • SKILL.md 一枚で完結する。
    Markdown ファイルを .claude/skills/gh-workflow/SKILL.md に置くだけで動く。Skills は description だけが常時コンテキストに入り、本文は呼び出し時のみロードされるので、普段の会話を圧迫しない

選択肢が複数ある中で gh CLI を選んだのは優劣の話ではなく、自分の環境と好みに合っていたからです。

gh CLI × Claude Code で CI ログを確認する(デモ)

ここからは実際のデモです。前提として、gh CLI がインストール済みで認証が完了している必要があります。

認証方法について: とりあえず試すなら gh auth login でブラウザ認証するのが一番手軽です。ただし OAuth はスコープが広くなりがちなので、運用するなら PAT(Personal Access Token)で最小限のスコープに絞るのがおすすめです。Fine-grained PAT なら対象リポジトリと Actions の読み取り権限だけに制限できます。

# PAT を使った認証
echo "<your-pat>" | gh auth login --with-token

このリポジトリにデモ用の Workflow を2つ用意しました。

  • demo-success.yml: ファイル構造のチェックと YAML バリデーションを行う2ジョブ構成の CI パイプライン
  • demo-failure.yml: 3ジョブ構成で、Test ジョブが意図的に失敗する Workflow(テスト失敗のログを再現)

SKILL.md は4モード対応(クイックステータス / Run 詳細 / PR チェック / ログ分析)ですが、今回はデモ用 PR がないので3モードで見ていきます。

クイックステータス — 「CI 確認して」

一番シンプルなモードです。「CI 確認して」と打つと、スキルが gh run list を実行して直近の Workflow 実行状況を取得します。

completed  failure  Demo - Failure Workflow  main  workflow_dispatch  22430458939  22s  2026-02-26T06:20:53Z
completed  success  Demo - CI Pipeline      main  workflow_dispatch  22430440934  21s  2026-02-26T06:20:13Z
completed  success  Demo - CI Pipeline      main  workflow_dispatch  22430416062  46s  2026-02-26T06:19:12Z
completed  failure  Demo - CI Pipeline      main  workflow_dispatch  22430368912  48s  2026-02-26T06:17:20Z

この生データを、スキルのレポートテンプレートに従って整形します。

## Workflow Status

| # | Workflow | Branch | Status | Conclusion | Triggered |
|---|---------|--------|--------|------------|-----------|
| 1 | Demo - Failure Workflow | main | completed | failure | workflow_dispatch |
| 2 | Demo - CI Pipeline | main | completed | success | workflow_dispatch |
| 3 | Demo - CI Pipeline | main | completed | success | workflow_dispatch |
| 4 | Demo - CI Pipeline | main | completed | failure | workflow_dispatch |

ブラウザを開かなくても、今の CI の状況がチャット上で確認できます。

Run 詳細 — 「この Run の詳細を見て」

成功した Run の中身を確認したいこともあります。「この Run、ジョブの実行時間どのくらいだった?」みたいなとき、Run ID を指定すると gh run view <run-id> で詳細を取得します。

✓ main Demo - CI Pipeline · 22430440934
Triggered via workflow_dispatch about 4 minutes ago

JOBS
✓ Code Check in 6s (ID 64947983939)
✓ Config Validate in 7s (ID 64947996283)

ジョブごとの実行時間とステータスが見えるので、Workflow の構成を変えた後に「ちゃんと速くなったか」を確認するのに使ったりします。

ログ分析 — 「CI 失敗してるから見て」

ここがメインの見せ場です。「CI 失敗してるから見て」と打つと、スキルが以下のステップを自動で実行します。

Step 1: 失敗した Run を特定する

gh run list --branch main --status failure --limit 5
completed  failure  Demo - Failure Workflow  main  workflow_dispatch  22430458939

Step 2: 失敗したジョブを特定する

gh run view 22430458939 --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}'
{"id": 64948053027, "name": "Test"}

--jsonjq を使って、失敗したジョブだけを抽出しています。全ジョブの情報を取得する必要はなく、失敗したものだけに絞ることでトークンを節約しています。このあたりの工夫は SKILL.md の解説セクションで詳しく説明します。

Step 3: 失敗したジョブのログを取得する

gh run view 22430458939 --log --job 64948053027
Test  Run integration tests  Running integration tests...
Test  Run integration tests
Test  Run integration tests  FAILED: test_pipeline.py::test_full_pipeline
Test  Run integration tests    AssertionError: Expected status code 200, got 503
Test  Run integration tests    File: tests/test_pipeline.py, line 42
Test  Run integration tests      assert response.status_code == 200
Test  Run integration tests
Test  Run integration tests  1 passed, 1 failed in 3.42s
Test  Run integration tests  ##[error]Process completed with exit code 1.

--log には必ず --job を付けています。これがないと全ジョブのログが流れてきてトークンを大量に消費するので、失敗したジョブだけに絞るのが鉄則です。

Step 4: Claude が分析してレポートを出す

ログを取得したら、Claude がエラー内容を読み取って原因分析と修正方針をまとめます。

## Failure Analysis

**Run:** #22430458939 - Demo - Failure Workflow
**Branch:** main
**Failed Jobs:**

| Job | Error Summary |
|-----|--------------|
| Test | integration test で AssertionError(期待 200、実際 503) |

**Root Cause:**
test_pipeline.py の test_full_pipeline テストで、API レスポンスのステータスコードが
期待値 200 に対して 503 (Service Unavailable) を返している。

**Suggested Fix:**
- テスト対象の API サーバーが起動しているか確認
- urllib3 のバージョン互換性を確認(requests 2.31.0 は urllib3&lt;3 を要求)

「CI 失敗してるから見て」の一言で、ここまで出てきます。手作業だと Run を探して、ジョブを開いて、ログを読んで…とやっていた調査が全部自動で走り、Claude がそのまま分析に入ります。コードの修正をしていた会話の流れのまま「じゃあこう直しましょう」と続けられるのがポイントです。

このデモではテスト失敗を再現するために作った Workflow を使っています。demo-failure.yml は echo で pytest 風のエラー出力を再現して exit 1 する構成で、実際のプロジェクトではここに本物のテスト結果が出ます。

SKILL.md の設計 — トークン効率とログ分析の工夫

ここからは「どうやって作ったか」の話です。スキルの実体は .claude/skills/gh-workflow/SKILL.md という Markdown ファイル1枚(全文は付録参照)。自分のプロジェクトでも同じような仕組みを作りたい人向けに、中身をパートごとに見ていきます。

メタデータ(--- で囲まれたヘッダー部分)

---
name: gh-workflow
description: |
  This skill should be used when the user asks to "CI確認して", "Workflow確認",
  "CIの状態を見て", "ワークフローのログを見て", "CI失敗してるから直して",
  "PRのチェック状況は", "/gh-workflow",
  or needs to check GitHub Actions workflow status or analyze CI logs.
allowed-tools: Bash, Read
---

description にスキルの起動条件を書いておくと、Claude がユーザーの発言を見て自動的にこのスキルを呼び出します。「CI確認して」のような日本語のトリガーも列挙できます。allowed-tools: Bash, Read で、このスキルが使えるツールを制限しています。

Skills は description だけが常時コンテキストに入っていて、本文はスキルが呼び出されたときにだけロードされるので、普段の会話には影響しません。

モード判定

| モード | トリガー例 | 主なコマンド |
|--------|-----------|-------------|
| クイックステータス | 「CI確認して」 | `gh run list` |
| Run 詳細 | 「Run #123 を見て」 | `gh run view &lt;run-id>` |
| PR チェック | 「PR #42 のチェック状況」 | `gh pr checks &lt;pr-number>` |
| ログ分析 | 「CI失敗してるから見て」 | `gh run view --log --job` |

ユーザーの一言からどのモードを実行するかを、このテーブルで Claude に判断させています。

トークン効率のルール

ここが SKILL.md で一番重要なパートです。ただ手順を書くだけなら誰でもできますが、トークンを無駄遣いしないルール を入れることでスキルの実用性が大きく変わります。

**必ず守ること:**

- `--log` は必ず `--job &lt;job-id>` と併用する(全ジョブログは膨大でトークンを大量消費する)
- `gh run watch` は使用禁止(リアルタイム出力でトークンを大量消費する)
- `gh pr checks --watch` は使用禁止(同上)
- JSON 出力 + jq で必要なフィールドのみ取得する

--log--job なしで実行すると、全ジョブのログが一気に流れてきます。CI のログは長くなりがちなので、これをそのままコンテキストに入れるとトークンがあっという間になくなります。--job で失敗したジョブだけに絞るのが鉄則です。

gh run watch を禁止しているのも同じ理由です。リアルタイム出力がずっと流れ続けるとトークンを食い尽くします。進行中の Run は「今の状態を確認する」だけにして、完了を待ちません。

JSON + jq のルールは、gh run view --json jobs --jq '.jobs[] | select(.conclusion == "failure")' のように必要なフィールドだけ抽出するためのものです。構造化データで取れるものは構造化データで取ります。

ログ分析モードの設計意図

デモセクションで「何が起きるか」を見ましたが、ここでは「なぜこの設計にしたか」を補足します。SKILL.md に以下の手順を書いておくと、Claude はこの順番で gh CLI を実行します。

### Step 1: 失敗した Run の特定
gh run list --branch $(git branch --show-current) --status failure --limit 5

### Step 2: 失敗したジョブの特定
gh run view &lt;run-id> --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}'

### Step 3: 失敗ジョブのログ取得
gh run view &lt;run-id> --log --job &lt;job-id>

### Step 4: エラー分析と報告

Run 全体 → 失敗ジョブ → 失敗ジョブのログ、と段階的に絞り込んでいく設計です。最初から全部のログを取るのではなく、必要なものだけに辿り着くようにステップを分けています。この段階的な絞り込みがトークン効率のルールと連動していて、各ステップで情報量を削ることで Claude に渡すデータを最小限にしています。

レポートテンプレート

## Failure Analysis

**Run:** #&lt;run-id> - &lt;workflow-name>
**Branch:** &lt;branch>
**Failed Jobs:**

| Job | Error Summary |
|-----|--------------|
| &lt;job-name> | &lt;error-summary> |

**Root Cause:**
&lt;分析結果>

**Suggested Fix:**
&lt;修正方針>

出力フォーマットを統一しておくと、毎回同じ形式で結果が出るので読み方が一定になります。「Root Cause を見て、Suggested Fix を見る」というパターンに慣れれば、確認作業がさらに速くなります。

改善の余地

gh CLI には --log-failed という失敗ステップのみ取得するオプションもあります。SKILL.md にはまだ組み込んでいませんが、--log --job と組み合わせればさらにログを絞り込めるので、今後の改善候補です。

もう一つ気になっているのが、ログが大量になるケースです。--job で絞っても、ジョブ自体のログが長いとトークンを圧迫する可能性があります。たとえばログを取得してファイルに保存だけしておくとか、失敗したログをテキストファイルとして書き出す CLI ツールを作るとか、いろいろ模索できそうだなと思っています。まだやってないですけどね。

まとめ

ざっくり振り返ると、Before / After はこうなりました。

Before: CI が落ちたら、ブラウザで Run を探して、ジョブを開いて、ログをコピーして、Claude に貼って、文脈を説明する。コードの修正中だったら作業の流れが切れる。

After: 「CI 失敗してるから見て」と打つ。スキルが gh CLI でログを集めて、Claude が分析して修正方針を出す。コードの修正中でも会話の流れはそのまま。

これを実現しているのは、.claude/skills/gh-workflow/SKILL.md という Markdown ファイル1枚です。特別なインフラもサーバーも不要で、プロジェクトにファイルを1つ追加するだけで動きます。

GitHub Actions 拡張機能とは補完関係で使うのがおすすめです。YAML の編集支援や「どこが落ちたか」の確認は拡張機能が得意で、「なぜ落ちたか」のログ取得と分析はスキル + Claude が得意です。

SKILL.md は他のプロジェクトでもそのまま使えます。gh CLI のコマンドを自分のプロジェクトに合わせて書き換えるだけで、同じ仕組みが動きます。トークン効率のルール(--log には --job 必須、watch 禁止、JSON + jq で絞り込み)はどのプロジェクトでも共通なので、テンプレートとして参考にしてもらえると思います。

ほなまた〜

シリーズ記事

記事内容
概要編 — ブラウザなし GitHub 操作を実現する問題提起と解決策の全体像
この記事(CI 編)失敗ログの取得から原因分析まで
Gist 編 — Gist 操作をチャット1行で完結させるGist の検索・保存・更新

付録

SKILL.md 全文

.claude/skills/gh-workflow/SKILL.md の内容です。

---
name: gh-workflow
description: |
  This skill should be used when the user asks to "CI確認して", "Workflow確認",
  "CIの状態を見て", "ワークフローのログを見て", "CI失敗してるから直して",
  "PRのチェック状況は", "/gh-workflow",
  or needs to check GitHub Actions workflow status or analyze CI logs.
allowed-tools: Bash, Read
---

# GitHub Actions Workflow Status & Log Analysis

gh CLI を使って GitHub Actions の Workflow ステータス確認・ログ分析を行います。

## Mode Selection

ユーザーの指示から以下の4モードを自動判定して実行する。

| モード | トリガー例 | 主なコマンド |
|--------|-----------|-------------|
| クイックステータス | 「CI確認して」「Workflowの状態を見て」 | `gh run list` |
| Run 詳細 | 「Run #123 を見て」「この Run の詳細」 | `gh run view <run-id>` |
| PR チェック | 「PR #42 のチェック状況」「PRのCI」 | `gh pr checks <pr-number>` |
| ログ分析 | 「CI失敗してるから見て」「エラーログ確認」 | `gh run view --log --job` |

## Token Efficiency Rules

**必ず守ること:**

- `--log` は必ず `--job <job-id>` と併用する(全ジョブログは膨大でトークンを大量消費する)
- `gh run watch` は使用禁止(リアルタイム出力でトークンを大量消費する)
- `gh pr checks --watch` は使用禁止(同上)
- JSON 出力 + jq で必要なフィールドのみ取得する

---

## Mode 1: クイックステータス

現在のブランチまたはリポジトリの Workflow 実行状況を一覧表示する。

### Step 1: Run 一覧の取得

```bash
# 現在のブランチの最新10件
gh run list --branch $(git branch --show-current) --limit 10

# 全ブランチの最新10件(ブランチ指定なし)
gh run list --limit 10
```

### Step 2: 結果を報告テンプレートで表示

## Mode 2: Run 詳細

特定の Run ID の詳細情報を取得する。

### Step 1: Run の詳細取得

```bash
# Run の詳細表示
gh run view <run-id>

# JSON で構造化データを取得
gh run view <run-id> --json status,conclusion,jobs,createdAt,updatedAt,headBranch,event
```

### Step 2: ジョブごとのステータスを整理して報告

## Mode 3: PR チェック

PR に紐づくチェック状況を確認する。

### Step 1: PR チェックの取得

```bash
# PR のチェック状況
gh pr checks <pr-number>

# 現在のブランチの PR チェック(PR 番号不明時)
gh pr checks
```

### Step 2: チェック結果を報告テンプレートで表示

## Mode 4: ログ分析

失敗した Workflow のログを取得・分析する。

### Step 1: 失敗した Run の特定

```bash
# 現在のブランチで失敗した Run を検索
gh run list --branch $(git branch --show-current) --status failure --limit 5
```

### Step 2: 失敗したジョブの特定

```bash
# Run 内のジョブ一覧を JSON で取得
gh run view <run-id> --json jobs --jq '.jobs[] | {name, status, conclusion}'
```

### Step 3: 失敗ジョブのログ取得

```bash
# 特定ジョブのログのみ取得(必ず --job を指定)
gh run view <run-id> --log --job <job-id>
```

**重要:** `--log` は必ず `--job <job-id>` と併用する。`--job` なしだと全ジョブのログが出力されトークンを大量消費する。

### Step 4: エラー分析と報告

ログからエラー箇所を特定し、原因と修正方針を報告する。

## Status / Conclusion Reference

| 値 | 種類 | 意味 |
|----|------|------|
| `queued` | status | キュー待ち |
| `in_progress` | status | 実行中 |
| `completed` | status | 完了 |
| `waiting` | status | 承認待ち |
| `success` | conclusion | 成功 |
| `failure` | conclusion | 失敗 |
| `cancelled` | conclusion | キャンセル済み |
| `skipped` | conclusion | スキップ |
| `timed_out` | conclusion | タイムアウト |
| `action_required` | conclusion | アクション要求 |
| `neutral` | conclusion | 中立(情報のみ) |
| `stale` | conclusion | 古い結果 |

## JSON Output Patterns

よく使う構造化データ取得パターン:

```bash
# Run 一覧を JSON で取得
gh run list --limit 10 --json databaseId,displayTitle,status,conclusion,headBranch,createdAt,event

# Run 内のジョブ詳細
gh run view <run-id> --json jobs --jq '.jobs[] | {id: .databaseId, name, status, conclusion, startedAt, completedAt}'

# 失敗ジョブのみ抽出
gh run view <run-id> --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}'

# PR チェックの詳細(JSON)
gh pr checks <pr-number> --json name,state,description,detailsUrl
```

## Report Template

以下のテンプレートを使って結果を報告する。

### ステータス一覧

```
## Workflow Status

| # | Workflow | Branch | Status | Conclusion | Triggered |
|---|---------|--------|--------|------------|-----------|
| 1 | <name>  | <branch> | <status> | <conclusion> | <event> |
```

### 失敗分析

```
## Failure Analysis

**Run:** #<run-id> - <workflow-name>
**Branch:** <branch>
**Failed Jobs:**

| Job | Error Summary |
|-----|--------------|
| <job-name> | <error-summary> |

**Root Cause:**
<分析結果>

**Suggested Fix:**
<修正方針>
```

## Important Notes

- **gh CLI 未認証の場合**: `gh auth status` で認証状態を確認し、未認証ならユーザーに通知
- **リポジトリ外で実行した場合**: エラーをユーザーに通知
- **大量のログ出力**: 必ず `--job` で絞り込み、それでも長い場合は主要なエラー行のみ抽出
- **進行中の Run**: ステータスが `in_progress` の場合、完了を待たずに現在の状態を報告(`watch` は使わない)

デモ用 Workflow

demo-success.yml

2ジョブ構成の CI パイプライン。ファイル構造のチェックと YAML バリデーションを行います。

name: Demo - CI Pipeline

on:
  workflow_dispatch:

jobs:
  check:
    name: Code Check
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Check file structure
        run: |
          echo "Checking project files..."
          test -f pyproject.toml && echo "OK: pyproject.toml"
          test -f CLAUDE.md && echo "OK: CLAUDE.md"
          echo "All checks passed."

  validate:
    name: Config Validate
    runs-on: ubuntu-latest
    needs: check
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Validate YAML configs
        run: |
          echo "Validating workflow files..."
          ls .github/workflows/*.yml | wc -l | xargs -I{} echo "Found {} workflow files"
          echo "Validation complete."

demo-failure.yml

3ジョブ構成で、Test ジョブが意図的に失敗する Workflow。echo で pytest 風のエラー出力を再現しています。

name: Demo - Failure Workflow

on:
  workflow_dispatch:

jobs:
  setup:
    name: Setup
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Verify environment
        run: |
          echo "Environment check..."
          echo "OS: $(uname -s)"
          echo "Setup completed."

  test:
    name: Test
    runs-on: ubuntu-latest
    needs: setup
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Run unit tests
        run: |
          echo "Running unit tests..."
          echo "test_fetch_article ... PASSED"
          echo "test_parse_html    ... PASSED"
          echo "Unit tests passed."

      - name: Run integration tests
        run: |
          echo "Running integration tests..."
          echo ""
          echo "FAILED: test_pipeline.py::test_full_pipeline"
          echo "  AssertionError: Expected status code 200, got 503"
          echo "  File: tests/test_pipeline.py, line 42"
          echo "    assert response.status_code == 200"
          echo ""
          echo "1 passed, 1 failed in 3.42s"
          exit 1

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: test
    steps:
      - name: Deploy application
        run: echo "Deploying..."
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です