Claude Code GitHub Actionsを用いてエラーの初期分析効率化を目指す – ENECHANGE Developer Blog

こんにちは!ENECHANGE EV Devチームの片田です。

今回は、開発フローの効率化という観点から、Claude Code GitHub Actionsを活用したアラート分析の自動化について、実際に取り組んだ内容をご紹介します。

GitHubActionsのyamlファイルのサンプルや出力結果も載せているのでぜひ参考にしていただけると嬉しいです!

プロジェクトのアラート解析の現状

私が所属するEV充電アプリ開発プロジェクトでは、エラー発生時にAIを活用した初期分析を組み込んだ以下の調査フローを運用しています。

  1. アラートをSentryからSlackへ通知
  2. 通知された内容をもとにClaudeCodeのスラッシュコマンドとして用意した調査用プロンプトを手動実行
  3. 初期調査をSentryMCPを用いて出力
  4. 調査開始

詳細は以前に利廣さんが投稿した記事でもこのフローが紹介されているので、詳細が気になる方はぜひ読んでみてください!

tech.enechange.co.jp

※ 記事はCursorを活用してますが、チームとしてClaudeCodeに乗り換えたので現在はClaudeCodeのスラッシュコマンドを使用してます。

Claude Code GitHub Actionsを活用できそう

このフローにより、初期調査でのあたりをつけやすくなり、調査スピードが向上しました。

しかし、運用を続ける中で以下のような課題が見えてきました。

  • 調査結果はClaudeCode上に表示されるので、コマンド実行したメンバーでしか確認できない
    • 共有が手間といえば手間(どこにどうやって貼るのかルールを設定したりする必要がある)
  • ハルシネーションが起きていた時、共有していない場合はその確認者が気づくしかない
    • 第3者の目が行き届かない
  • URLを引っ張ってきてスラッシュコマンドを実行して、その結果を待つのが多少だけどロス

そこで、Claude Code GitHub ActionsがMaxプランでも利用可能になったことを知り、このフローの自動化に取り組むことにしました。

Claude Code GitHub Actionsを使った分析

今回はこのような構成で、アラートの初期分析をSlackに自動投稿できるようにしてみました。

今回のアーキテクチャ

手順

  1. Sentryにアラートが発生
  2. Slackにアラート通知
  3. Webhookでアラート情報をLambdaに送信
  4. LambdaがGitHub Actionsをトリガー
  5. Claude Code GitHub Actionsを実行
  6. Sentry MCPで経由でSentryから詳細情報を取得
  7. SentryMCPから連携された情報とコードベースからClaudeでエラー調査・分析実行
  8. 調査結果をSlackに投稿

これにより、確認者が個別にスラッシュコマンドを実行する必要がなくなり、前述の課題を解決できると考えました。

今回はSentryアラート通知やSlackへの送信方法は割愛させていただきます。
Claude Code GitHub Actionsの実装にフォーカスして記載します。

Claude Code GitHub Actionsを使ってみる

実装にあたっては、Claude Code Actionの公式リポジトリのsetup.mdusage.mdを参考にしました。(ドキュメントにはClaude Code GitHub Actionsって書いてあるんですけど、リポジトリはClaude Code Actionなんですよね。呼び方迷う)

betaからv1への移行時期だったこともあり、最新の公式ドキュメントが最も有用な情報源となりました。

github.com

作ってみたActionsのyamlはこんな感じです。

sentry-alert-initial-analyze.yml
name: Sentry Alert Initial Analyze

on:
  repository_dispatch:
    types: [sentry_alert]

jobs:
  claude:
    if: github.event.action == 'sentry_alert'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set Event ID
        id: event_id
        run: |
          echo "value=${{ github.event.client_payload.event_id }}" >> $GITHUB_OUTPUT

      - name: Set current datetime as env variable
        env:
          TZ: "Asia/Tokyo"
        run: echo "CURRENT_DATETIME=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV

      - name: Run Claude Code with Sentry MCP
        id: claude
        uses: anthropics/claude-code-action@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          prompt: |
           
            Sentryエラー解析用コマンド

           
            エラーの詳細は以下のSentryで報告されたevent先に記載されています。
            MCPサーバーを使って、エラーの詳細を取得し分析してください。
            ${{ steps.event_id.outputs.value }} がSentryのEventIDになります。

            このeventを解析して、以下のテンプレートにあてはまるように報告書を作成してください。
            ただし、時間はCET基準なのでJSTに変換して出力してください。

            Sentry MCPを使用する際は `mcp__sentry__get_issue_details` 機能のみを使用してください。
            **それ以外は使用しないでください。**

            `organizationSlug: "***"`になります。

            テンプレート
            ```
           
            (何をすると)(どうなる)

           
            (何が)(何へ)影響しているから
            (調査中)

           
            (発生時間帯)
            (対象件数)
            (調査中)

           

           

           

           

           

           

           
            ```
         
         
         
         
          claude_args: |
            --max-turns 5
            --mcp-config '{"mcpServers": {"sentry": {"command": "npx", "args": ["@sentry/mcp-server@latest", "--access-token", "${{ secrets.SENTRY_ACCESS_TOKEN }}", "--host", "energy-cloud.sentry.io"], "env": {}}}}'
            --allowedTools "mcp__sentry__whoami,mcp__sentry__find_organizations,mcp__sentry__get_issue_details,mcp__sentry__get_trace_details"
        env:
          SENTRY_EVENT_ID: ${{ steps.event_id.outputs.value }}

      - name: Send Slack Notification
        if: steps.claude.conclusion == 'success'
        uses: slackapi/slack-github-action@v2.1.1
        with:
          webhook: ${{ secrets.SENTRY_ERROR_SLACK_WEBHOOK }}
          webhook-type: incoming-webhook
          payload: |
            {
              "username": "Sentry Alert Bot",
              "icon_emoji": ":mending_heart:",
              "blocks": [
                {
                  "type": "header",
                  "text": {
                    "type": "plain_text",
                    "text": "エラーの解析が完了したよ"
                  }
                },
                {
                  "type": "section",
                  "fields": [
                    {
                      "type": "mrkdwn",
                      "text": "*Event ID:* ${{ steps.event_id.outputs.value }}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*実行時刻: ${{ env.CURRENT_DATETIME }}"
                    }
                  ]
                },
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": ""
                  }
                }
              ]
            }

      - name: Send Slack Notification (Failure)
        if: steps.claude.conclusion == 'failure'
        uses: slackapi/slack-github-action@v2.1.1
        with:
          webhook: ${{ secrets.SENTRY_ERROR_SLACK_WEBHOOK }}
          webhook-type: incoming-webhook
          payload: |
            {
              "username": "Sentry Alert Bot",
              "icon_emoji": ":exclamation:",
              "blocks": [
                {
                  "type": "header",
                  "text": {
                    "type": "plain_text",
                    "text": "❌ エラー解析が失敗しました"
                  }
                },
                {
                  "type": "section",
                  "fields": [
                    {
                      "type": "mrkdwn",
                      "text": "*Event ID:* ${{ steps.event_id.outputs.value }}"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*失敗時刻: ${{ env.CURRENT_DATETIME }}"
                    }
                  ]
                },
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "Claude Codeによるエラー解析が失敗しました。詳細は以下のリンクから確認してください。"
                  }
                },
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": ""
                  }
                }
              ]
            }

実装時に特に注意した点は以下の通りです

  • --allowedTools で mcpに関する権限も許可するようにする
    • この権限を見ずにmcpサーバー呼び出しをして権限がなくてターン数を消費するので、mcp__sentry__get_issue_detailsのみ実行することを明記する
  • organizationSlugはプロンプトに直接記載する
    • Sentry MCPによるアラート検索時にEventIDorganizationSlugを使用するが、Sentry WebHookのペイロードにはorganizationSlugは直接持ってない(URLに入っていそうだが単体ではない)ため
    • ※ サンプルではマスキングしています

実行結果

期待通りの結果を得ることができました!

上の投稿がSentryによるアラート通知(手順②)、下の投稿がGitHub Actionsによる調査結果の投稿(手順⑧)です。

Slack投稿結果

解析結果投稿の「解析結果を確認」リンクから、実行されたActionsのページに遷移し、サマリで詳細な解析結果を確認できます。

Actions実行結果

サマリの末尾に ✅Final Result として結果が表示されています。
たまに記載が省略されている部分がありますが、サンプルエラーを出力していることによるもので、本番環境では期待する結果が返ってきてました。

サマリ結果
## ✅ Final Result

エラー詳細を取得しました。以下、報告書を作成いたします。

## エラー報告書

### 事象
Flutterアプリケーションを使用すると、JavaScriptレイヤーで「Object [object Object] has no method 'updateFrom'」というTypeErrorが発生する

### 原因
Sentryのビューポーリング機能(views.js)内で、存在しないメソッド'updateFrom'を呼び出そうとしているから
(詳細調査中)

### 影響範囲
**発生時間帯**: 2025年9月2日 15:23(JST初回) ~ 2025年9月18日 18:56(JST最終)
**対象件数**: 19件発生
**影響ユーザー数**: 1名

#### どのバージョンから発生している不具合なのか
調査中(バージョン情報がイベントに含まれていない)

#### 現行最新バージョンでも発生する不具合なのか
2025年9月18日にも発生しているため、最新バージョンでも発生している可能性が高い

### 再現手順
1. アプリを起動
2. 特定の画面操作時(http://example.com/foo へのアクセス時)
3. Sentryのビュー更新処理が実行される際にエラーが発生

### 暫定対策(思いつけば)
- Sentryのバージョンアップデート、またはSentry SDKの再インストール
- エラーハンドリングの追加実装により、アプリのクラッシュを防ぐ

### 恒久対策(思いつけば)
1. Sentry SDKのバージョンを最新版に更新
2. Flutter側でSentryの初期化処理を見直し
3. JavaScript側のビューポーリング処理でupdateFromメソッドの存在確認を追加

### エラー該当箇所
***/***/***/***.js
- 389行目でwindow.setTimeoutを呼び出す際にエラーが発生
- collection.updateFromメソッドが未定義

### Githubリポジトリの該当箇所
本エラーはSentry SDK内部のJavaScriptコードで発生しているため、アプリケーション側のコードというよりは:
- `pubspec.yaml`でのSentry依存関係のバージョン指定
- Sentryの初期化コード(おそらく`lib/application/firebase/`または`lib/presentation/app/`配下)

を確認・修正する必要があります。

これから改善したいこと

当初の課題であった「ClaudeCodeの解析結果が限定的な範囲でしか共有できない」問題は解消されましたが、さらなる改善の余地があります。

過去の類似エラー調査の実現

同様のエラーの過去事例を調査したいのですが、現状ではSentryMCPによるイベント検索にOPENAI_API_KEYが必要で、一旦コスト見合いで実施してないです。

OAuth認証を使用した検索も可能のようですが、GitHubActions環境での認証フローの構築が課題となっています。

Slack内での完結した情報共有

GitHubへの遷移を不要にするため、調査結果をSlack内で直接確認できるよう改善したいと考えています。

長文のサマリをそのまま投稿するとアラート通知が埋もれてしまうため、スレッド機能を活用した投稿方式の実装を予定しています。

最後に

今回は、エラー分析という開発の日常的な作業でのAI活用について書かせていただきました。小さな効率化の積み重ねが、結果的に開発体験の向上につながっていることを実感しています。
また、Claude Code GitHub Actionsを使ってみましたが、公式リポジトリのexamplesをみると定期実行させたりなど面白そうな使い方があるのでぜひ色々試してみたいですね。

次回の投稿はエクスペリエンス部長の草間さんになります!

また、9/22は会社として有給推奨日なので、投稿もお休みさせてもらいます。
次の投稿は9/24になります!お楽しみに!


元の記事を確認する

関連記事