ども!最近 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_runs や get_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"}
--json と jq を使って、失敗したジョブだけを抽出しています。全ジョブの情報を取得する必要はなく、失敗したものだけに絞ることでトークンを節約しています。このあたりの工夫は 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<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 <run-id>` |
| PR チェック | 「PR #42 のチェック状況」 | `gh pr checks <pr-number>` |
| ログ分析 | 「CI失敗してるから見て」 | `gh run view --log --job` |
ユーザーの一言からどのモードを実行するかを、このテーブルで Claude に判断させています。
トークン効率のルール
ここが SKILL.md で一番重要なパートです。ただ手順を書くだけなら誰でもできますが、トークンを無駄遣いしないルール を入れることでスキルの実用性が大きく変わります。
**必ず守ること:**
- `--log` は必ず `--job <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 <run-id> --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}'
### Step 3: 失敗ジョブのログ取得
gh run view <run-id> --log --job <job-id>
### Step 4: エラー分析と報告
Run 全体 → 失敗ジョブ → 失敗ジョブのログ、と段階的に絞り込んでいく設計です。最初から全部のログを取るのではなく、必要なものだけに辿り着くようにステップを分けています。この段階的な絞り込みがトークン効率のルールと連動していて、各ステップで情報量を削ることで Claude に渡すデータを最小限にしています。
レポートテンプレート
## Failure Analysis
**Run:** #<run-id> - <workflow-name>
**Branch:** <branch>
**Failed Jobs:**
| Job | Error Summary |
|-----|--------------|
| <job-name> | <error-summary> |
**Root Cause:**
<分析結果>
**Suggested Fix:**
<修正方針>
出力フォーマットを統一しておくと、毎回同じ形式で結果が出るので読み方が一定になります。「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..."

