FLINTERS BLOG
😊

Sentry → 原因分析 → 修正 PR を Markdown 1 枚で自動化する — GitHub Agentic Workflows

に公開

はじめに

こんにちは。FLINTERSの河内です。

Sentry で検出された例外について、Slack 通知を見て人間が GitHub Issue を起票し、原因をざっと当たり、優先度を付ける、というオペレーションは多くのチームで日常化しています。これを次のレベルまで自動化したくなります。

  • Sentry alert → GitHub Issue 自動起票
  • AI による原因分析(スタックトレースとリポジトリのソースコードを突き合わせる)
  • 重複判定(既存 issue と同じバグなら close)
  • 影響範囲ベースの優先度付け
  • 自明な修正は Pull Request (以降PR)まで自動作成

結論を先に書くと、 Markdown 1 枚(150 行程度)と Repository secret 2 本だけで、上記が全部実現できました。鍵は GitHub Agentic Workflows (gh-aw) と Sentry の公式 MCP server の組み合わせです。Anthropic API への直接契約を持っていないチームでも、GitHub Copilot subscription だけで動かせます。

この記事では、 production で動かし始めた構成と、踏んだ落とし穴をまとめます。最後に、自分の coding agent に渡せばガイド付きで再現できるプロンプトを置いておきます。


なぜ gh-aw か

最初は次の代替案も検討しましたが、それぞれの理由で外しました。

  • 自前 API 直叩き: 認証・retry・課金管理・サンドボックスを全部自分で作る必要があり重い
  • GitHub 公式の Claude Code Action: Anthropic API key が必須。現時点で利用可能な契約が無かった
  • Sentry Seer: 利用中のプランで Seer が使えなかった

gh-aw は Markdown で workflow を書けて、 Copilot subscription 経由で動き、書き込み制限・サンドボックス・出力検証が標準装備です。「Sentry alert → AI → GitHub に書き戻す」に必要な部品が最初からほぼ揃っているのが選んだ理由です。

Sentry Seer が使えるならどうか

契約上 Seer が使えるなら、原因分析と PR 提案が Sentry 側で完結するのでそちらの方が手数は少ない可能性があります(自分で workflow を書く必要がない)。

ただし Seer のカスタマイズは Advanced Settings での機能 ON/OFF や、各タスクのパラメータ調整(しきい値、プロジェクトスコープ、PR 数の上限など)が中心で、 triage の判断ロジックそのものを自然言語の prompt で書き換える設計ではない、と理解しています(参考: Seer ドキュメント / Performance triage with Claude Code + Sentry MCP)。

一方 gh-aw は Markdown 本文がそのまま agent への自然言語 prompt なので、「Priority 判定の前に必ずソースコードを読む」「Tier 2 重複は confidence 0.9 以上のときのみ」のような独自ポリシーを直接書き込めます。「triage の挙動を自前で細かく決めたい」「契約上の制約で Seer が選べない」あたりに該当するチームが、 gh-aw を選ぶ妥当性を感じる読者層だと思います。


アーキテクチャ全体像

Sentry: 新しい issue group が発生
   └─ Alert Rule → "Create GitHub Issue" action [label: sentry]
        └─ GitHub Issue 起票(本文: Sentry URL / short-id)
             └─ .github/workflows/sentry-triage.md が起動
                  └─ AI agent (Copilot CLI):
                       ├─ Sentry MCP: error context / stack frames を取得
                       ├─ Tier 1 重複判定: GitHub MCP で short-id 検索
                       ├─ ソースコードを読んで根本原因を推定
                       ├─ Tier 2 重複判定: 根本原因ベースで再検索
                       └─ safe-outputs:
                            ├─ add-comment       構造化 triage コメント
                            ├─ add-labels        duplicate のみ
                            ├─ close-issue       重複と判定したとき
                            └─ create-pull-request  修正が自明なとき

ポイントは次の 3 点です。

  • issue 起票は Sentry の標準機能に任せます(自前 webhook 受け口を作りません)
  • issue 本文は AI が改変しません(コメントとラベルでのみ表現することで可逆性を担保します)
  • 書き込みは safe-outputs の gated job 経由のみ(agent から GITHUB_TOKEN を直接触らせません)

必要な準備

1. GitHub Copilot subscription とトークン

  • Organization で Copilot Business / Enterprise を契約済みであること
  • fine-grained Personal Access Token(PAT) を発行し、Account permissions の Copilot Requests: Read を付けます
  • Repository secret として COPILOT_GITHUB_TOKEN に登録します

2. Sentry 側の設定

  • Sentry 側で Alert Rule を作成します
    • condition: When a new issue is created
    • action: Create a GitHub issue (GitHub Integration 経由)、label に sentry を指定
  • サイドバーの「開発者向けの設定」(英語 UI なら Settings → Developer Settings)→ Personal Tokens から read-only スコープの token を発行します
    • 付与した scope: event:read / org:read / project:read / team:read
    • @sentry/mcp-server の README には write 系 scope を含めた組み合わせも挙がっていますが、本記事では triage 用途では read だけで足りるという判断で write を一切付与していません。 prompt injection で agent が乗っ取られたときに Sentry 側を勝手に書き換えられない、という defense-in-depth を効かせるためです(gh-aw の job 分割と同じ発想)
  • Repository secret として SENTRY_ACCESS_TOKEN に登録します

3. ローカル CLI

gh extension install github/gh-aw

workflow を編集したあとは gh aw compile sentry-triage.lock.yml を再生成し、両方 commit します。


Sentry MCP の選定(stdio 版を採用)

gh-aw から Sentry の情報を引き出す経路として、Sentry が公式メンテする MCP server @sentry/mcp-server を使います。stdio で起動して、 Sentry の REST API を MCP tool として agent に提供する薄いラッパです。今回の用途で使う代表的な tool は次のあたりです。

  • find_issues / find_events: short-id や error type で Sentry issue / event を検索
  • get_sentry_resource: 指定 issue / event の詳細(type / message / stack frames / breadcrumbs / tags)を取得

SENTRY_ACCESS_TOKEN を env 経由で渡すだけで動きます。 0.x 系なので tool 名が version で renaming される点には注意(後述の落とし穴 #4)。

なお、 Sentry は同じ機能を remote MCP(https://mcp.sentry.dev/mcp)でも公開しています。が、こちらは OAuth でユーザー認証する仕様で、 gh-awmcp-servers から OAuth フローを通す素直な方法が(少なくとも執筆時点では)見当たりませんでした。そのため、本記事では stdio で起動する @sentry/mcp-server を npx 経由で agent コンテナ内に立てる構成を採用しています。 Personal Token を 1 つ secret に置くだけで済むので、運用も単純です。


Workflow ファイルの実体

.github/workflows/sentry-triage.md の frontmatter は次のようになります。

---
description: |
  Sentry alert で自動起票された GitHub Issue を triage する。
  Sentry MCP 経由で context を取得し、リポジトリのソースコードと突き合わせて
  根本原因を推定する。short-id および根本原因ベースで重複判定を行い、修正が
  自明な場合は best-effort で PR を作成する。
on:
  issues:
    types: [labeled]
  bots:
    - "sentry[bot]"
if: ${{ github.event.label.name == 'sentry' }}
permissions: read-all
network:
  allowed:
    - defaults
    - "*.sentry.io"
    - "sentry.io"
safe-outputs:
  add-comment:
    max: 1
  add-labels:
    max: 1
  close-issue:
    max: 1
  create-pull-request:
    max: 1
tools:
  github:
    toolsets: [issues]
mcp-servers:
  sentry:
    command: "npx"
    args: ["@sentry/mcp-server@0.32.0"]
    allowed: ["*"]
    env:
      SENTRY_ACCESS_TOKEN: ${{ secrets.SENTRY_ACCESS_TOKEN }}
timeout-minutes: 15
---

設定の意図は次のとおりです。

  • network.allowed*.sentry.io を入れています。これは Sentry MCP を通すための agent firewall 許可と、agent 出力中の URL を redact しないための URL sanitizer 許可の両方を兼ねます(後述)。
  • safe-outputsmax は agent が暴走したときの blast radius を直接制限します。add-comment.max: 1 なら 1 件しか書けません。
  • mcp-servers.sentry.allowed: ["*"] でワイルドカード許可にしています。Sentry MCP は version 間で tool 名が renaming される(例: get_issue_detailsget_sentry_resource)ので、個別列挙するとメンテナンスコストが大きくなります。安全境界は SENTRY_ACCESS_TOKEN の read-only スコープ(API 側 403)と prompt での明示禁止(Seer 系等)で担保しています。

本文(自然言語の手順書)は次の構造になります。

  1. Issue 本文取得 / Sentry short-id 抽出
  2. Tier 1 重複判定: short-id exact match で search_issues
  3. Sentry MCP で context 取得(type / message / stack frames / breadcrumbs / first-last seen / tags)
  4. ソースコード読み込み(top stack frame に対応するファイルを ${GITHUB_WORKSPACE} から読みます)
  5. 根本原因の特定と影響範囲の調査(外部 SDK 由来 / テストイベント / 実アプリのバグ / config / 依存サービス で分類)
  6. Tier 2 重複判定: error type / stack frame / キーワードで類似 issue を検索し、根本原因を比較。confidence ≥ 0.9 のときのみ重複扱い
  7. 構造化コメント投稿(事象 / 影響範囲 / 根本原因 / 推定優先度 / 修正方針)
  8. PR 候補判定: 「実アプリのバグ」かつ「localized な修正(1 ファイル概ね 10 行以内)」かつ「副作用なし」のときのみ create-pull-request

Priority の付け方は次のとおりです。

  • first-occurrence 評価が前提なので、件数・頻度は判定材料にしません(Sentry は新規 group の最初の発生で issue を起票するため、ほぼ必ず 1 件目です)
  • 代わりに、ソースコードを読んで把握した影響範囲で判定します
    • P0: production で auth / DB / 決済 / 起動 / コア API などが停止、データ破損リスク
    • P1: production で特定機能が利用不可、retry で吸収できない外部依存エラー
    • P2: 限定的影響、エッジケース、fallback / retry で吸収可能
    • 不明: テストイベント、staging only、評価不能
  • Priority はコメント本文に書くだけにします(GH Project の Priority field 連携などは初版では入れません。別 PAT が必要で運用が煩雑になるため)

踏んだ落とし穴

1. SENTRY_HOST env を渡すと MCP が起動しない

@sentry/mcp-serverSENTRY_HOST に hostname のみを期待します(https://sentry.io のような URL を渡すとパース失敗で MCP 接続に失敗します)。Sentry SaaS を使っているなら、そもそも env を渡さないのが正解です(default で sentry.io になります)。

2. URL サニタイザが Sentry リンクを (redacted) で潰す

gh-aw は agent の出力に対して sanitizeUrlDomains() を走らせ、network.allowed に無いドメインの URL を redact します。Sentry リンクをコメントに残したいなら network.allowed に Sentry のドメインを追加する必要があります(後述のセキュリティモデル節を参照)。

3. agent が curl に fallback する

Sentry MCP がうまく繋がらないと、agent が「直接 curl で API を叩く」に fallback しようとして firewall に弾かれます。これは prompt で明示的に禁止しておくと無駄な遷移が減ります。

直接 curl 等で Sentry API を叩かない(agent sandbox firewall でブロックされる)。MCP 経由で取得できる情報のみで判断する。

4. ホワイトリスト方式の MCP tool 列挙はバージョンで壊れる

mcp-servers.<name>.allowed で tool 名を個別列挙すると、Sentry MCP のバージョンを上げるたびに workflow が壊れます。allowed: ["*"] でワイルドカード許可にして、その代わり次の二段構えで安全性を担保します。

  • API 側の hard boundary: token を read-only スコープにします(write 系の tool は 403 で弾かれます)
  • prompt 側の soft boundary: 使わせたくない tool 名(例: analyze_issue_with_seer など Seer 関連)を prompt で明示的に禁止します

これで、新しい tool が追加されたときも見落としません。

5. 件数ベースの Priority 判定は使えない

Workflow ファイル節で書いたとおり、Sentry が GitHub issue を立てるのは新規 group の最初の発生時なので、判定時にはほぼ必ず 1 件しかありません。「P0: 1 時間に 100 件以上」のような件数ベースの基準を最初書いてしまったのですが、これは機能しないので、影響範囲ベースに切り替える必要があります。


gh-aw のセキュリティモデルを掘り下げる

ここからは設計の根拠の話です。実装だけ知りたい人は横展開用プロンプトまで飛ばして構いません。gh-aw は「LLM agent に書き込み権限を直接渡さない」という前提で構築された defense-in-depth のセキュリティモデルを持っており、 Sentry のように外部入力を AI に食わせる用途では、ここを押さえておくと設計判断が楽になります。

Sentry 用途特有の prompt injection リスク

Sentry が集めるのはアプリケーションの例外です。そして例外の中身は、しばしばユーザー入力に汚染されています。具体例で書くと、

  • raise ValueError(f"Invalid input: {user_input}") のように、 exception message にユーザーが送った文字列が直接入っている
  • breadcrumb に HTTP request の URL / headers / SQL クエリが残っている
  • tag や extra に user-agent や custom field の値が入っている

これらは全部、 Sentry が起票した GitHub issue の本文経由で agent のプロンプトに流れ込みます。攻撃者が意図的に例外を発生させれば、任意の文字列を agent のプロンプトに届けられる、ということです。

safe-outputs で許可されている操作の範囲内でも、 prompt injection で十分悪さができます。たとえば次のような攻撃経路が考えられます。

  • 重複判定の誤誘導:
    • 仕掛け: 攻撃者が別の issue にダミー本文(「この Sentry issue は #12345 と同じバグ」のような断定文)を仕込んでおく
    • 起動: 細工したクエリ文字列を含むリクエストで例外を起こし、 Sentry → GitHub issue 本文に injection 文字列を載せる
    • 結果: agent が Tier 2 重複判定で誤誘導され、無関係な重要 issue を duplicate として close
  • 修正 PR の悪用: exception message に「依存ファイルを更新せよ」のような指示を埋め込み、 agent にバックドア入りの PR を作らせる
  • triage コメント経由のフィッシング: 攻撃者の用意した URL をコメント本文に貼らせて、後で人間に踏ませる

つまり、 agent のプロンプト時点で injection を完全に防ぐのは原理的に難しい以上、「やられた前提で被害を限定する」発想が要ります。gh-aw の job 分割と safe-outputs allow-list、 URL sanitizer、 Threat Detection Job は、まさにこの種の攻撃を「やられても被害が出ない / 限定される」形に封じ込めるための設計です。 agent が injection で乗っ取られても、

  • そもそも safe-outputs で宣言した操作(add-comment / add-labels / close-issue / create-pull-request)以外は実行できない
  • network allow-list 外への通信もできないので、攻撃者が用意した外部サーバへのデータ流出も止まる
  • read-only token なので GITHUB_TOKEN を直接使った副作用も起こせない
  • 怪しいパッチや、本文に攻撃者ドメインの URL を含むコメントは Threat Detection Job / URL sanitizer が止める

という多層の防御が効きます。

セキュリティ設計の骨子は次の 4 原則とされています(参考: Under the hood: Security architecture of GitHub Agentic Workflows)。

  • defense in depth(多層防御)
  • don't trust agents with secrets(agent に秘密を渡さない)
  • stage and vet all writes(書き込みは段階化して検証する)
  • log everything(すべて記録する)

実装上、これは 1 回の workflow 実行を複数の job に分割し、それぞれに最小権限を割り当てることで実現されています。

Job の分割と権限分離

(参考: Security Architecture | GitHub Agentic Workflows の Permission Separation / Job Execution Flow セクション)

gh aw compile で生成される .lock.yml を読むと、1 本の Markdown workflow が次のような job 群に展開されているのが分かります。

Pre-Activation Job
  └─ trigger 条件 / role 権限 / stop-after デッドラインの検証

Activation Job
  └─ ワークフロー context の準備、event text の sanitization

Agent Job (read-only)
  ├─ permissions: read-all (書き込み権限なし)
  ├─ MCP server コンテナ起動
  ├─ AI engine 実行 (Copilot CLI / Claude / Codex)
  ├─ Secret Redaction step (if: always())
  └─ 出力を artifact として upload

Detection Job (権限なし、AI による脅威検出)
  └─ artifact をダウンロードして prompt injection / secret leak / 悪意あるパッチを判定
      ↓ 合格時のみ進む

Safe Output Jobs (用途ごとにスコープ限定の write 権限)
  ├─ add-comment job:        issues: write
  ├─ add-labels job:         issues: write
  ├─ close-issue job:        issues: write
  └─ create-pull-request job: contents: write, pull-requests: write

agent job 自体は permissions: read-all で動くので、GITHUB_TOKEN を直接使って issue を更新することはできません。agent ができるのは「こういう操作をしたい」という意図を構造化 JSON で artifact に書き出すところまでです。実際の書き込みは別 job が、ホワイトリスト化された SDK 呼び出しでのみ実行します。

これにより、agent が prompt injection で乗っ取られても、影響範囲は「artifact に変な JSON を書かせる」までに封じ込められます。

Secret Redaction と agent から secret が見えない仕組み

(参考: Security Architecture | GitHub Agentic Workflows の Secret Collection / Secret Redaction セクション)

gh-aw は workflow YAML をコンパイルする時点で secrets.* 参照を全部スキャンし、対象となる秘密値のリストを保持します。agent job の最後に if: always() で動く Secret Redaction step が、/tmp/gh-aw 配下の全ファイル(つまり agent が書き出したログや artifact 全部)を走査し、秘密値の文字列を abc***... の形式にマスクします。

ここで重要なのは、 agent プロセスから見える環境変数として secret が露出するのは MCP server プロセスの env として渡された場合だけ、という点です。下で書くように、Sentry MCP では SENTRY_ACCESS_TOKEN を MCP server コンテナの env としてだけ渡します。agent コンテナ自体の env には載らないので、agent が printenv を叩いても出てきません。

ただしドキュメントは正直に書いていて、 MCP gateway API key のような agent コンテナ内に注入される値については「強い境界ではない」(agent が任意コード実行できるなら抜き取れる)としています。ここの最終的な防御は agent job の read-only 権限です。

Agent Workflow Firewall (AWF) と URL sanitizer の二重役

(参考: Security Architecture | GitHub Agentic Workflows の Agent Workflow Firewall / URI Filtering セクション)

agent コンテナの外向き通信は、同じネットワーク namespace 内の Squid proxy を経由してしか出られません。network.allowed に列挙したドメイン以外はカーネルレベルでドロップされます。

network:
  allowed:
    - defaults      # TLS 証明書, JSON schema 配信先など
    - python        # PyPI 系
    - node          # npm, npmjs.com
    - "*.sentry.io" # 自分で追加するカスタムドメイン

ここで一つ注意点があります。network.allowed は agent firewall(外向きアクセス制御)と、agent 出力の URL sanitizer(コメントに残す URL の許可リスト)の両方を兼ねています。 agent が出力したテキスト中の URL は、sanitizeUrlDomains() というステップで network.allowed に無いドメインなら (redacted) に置換されます。

つまり Sentry リンクをコメントに残したいなら、ネットワーク到達性を許可するだけでなく、出力サニタイズの観点でも同じドメインを許可する必要がある、ということです。片方だけ許可する設定は無く、両方が同じ allow-list で制御されます。

これは prompt injection で「https://attacker.example/... をクリックしてください」のような誘導 URL を agent に書かせたとしても、 allow-list 外なので (redacted) になって無害化される、という防御を兼ねています。

Threat Detection Job

(参考: Security Architecture | GitHub Agentic Workflows の Threat Detection Job セクション)

agent job が完了して artifact が出たあと、Detection Job が次の 3 ファイルだけを受け取って AI で判定します。

  • agent_output.json — agent が要求した safe-output アクションの構造化記述
  • aw.patchcreate-pull-request 用のコード変更 patch
  • prompt.txt — agent に渡された system / user プロンプト

判定対象は「秘密のリーク」「悪意あるパッチ」「ポリシー違反(スコープ外操作)」で、合否の二値だけを返します。Detection Job は live なリポジトリ状態にはアクセスできず、artifact だけを見るので、ここで agent が暴走しても被害は出ません。

不合格になれば後続の Safe Output Jobs は全部スキップされ、書き込みは一切起きません。

Content Sanitization

外部から流れ込んでくるテキスト(issue タイトル、PR ボディ、コメント等)は、 agent に渡される時点で正規化されます。代表的な処理は次のとおりです(参考: Security Architecture | GitHub Agentic Workflows)。

  • @user mention をバッククォート囲み(誤通知防止)
  • fixes #123 のような自動リンク誘発キーワードをバッククォート囲み
  • HTML / XML タグの < >( ) に置換(例: <script>alert('xss')</script>(script)alert('xss')(/script)
  • 許可外ドメインの URL を (redacted) に置換
  • ANSI エスケープ等の制御文字を除去
  • 大きすぎる入力をトランケート(0.5MB / 65k 行が上限)

Sentry alert で起票された issue 本文をそのまま agent に食わせるとき、 stack trace 中の curl 風 URL や @mentions 風文字列が悪用される懸念がありますが、ここで吸収されます。

Compile-time validation

(参考: Security Architecture | GitHub Agentic Workflows の Configuration-Level Trust セクション)

gh aw compile は Markdown を .lock.yml に変換するときに、

  • frontmatter の JSON Schema 検証
  • GitHub Actions 式の allowlist チェック
  • action SHA の pin 化(actions/checkout@v4 ではなく commit hash 固定で書き出される)
  • actionlint / zizmor / poutine といったセキュリティスキャナの統合

を実行します。.lock.yml をレビュー対象に含めることで、frontmatter の変更が思わぬ permission 拡張に繋がっていないかを diff で目視できます。


課金面の注意: Premium Request を 1 実行で 2 消費する

これは見落としやすい点です。gh-aw の 1 回の実行で消費される Copilot premium request は実質 2 回分になります。

  • 1 回目: agent 本体の実行(Sentry MCP で context を取って原因を分析する部分)
  • 2 回目: Detection Job が AI で safe-outputs の安全性を判定する部分

Detection Job も内部では LLM 呼び出しなので、premium request を消費します。Sentry alert がバースト的に発生するプロジェクトでは、消費量の見積もりを 2 倍にしておく必要があります。

なお、GitHub Copilot は 2026 年 6 月 1 日から premium request 制を廃止して GitHub AI Credits ベースの usage-based billing に移行する予定です(参考: GitHub Copilot is moving to usage-based billing)。token 消費量ベースの課金になるため、今後は「実行 1 回あたり何 request」という単位ではなく、入出力 token + cached token で計算することになります。


現状と、これから観測したいこと

正直に書くと、 production 投入したばかりで定量データはまだありません。代わりに、これから何を見ていくつもりかを記しておきます。

  • 重複判定の精度(false positive で別バグを duplicate close していないか、 false negative で同じバグを何度も triage していないか)
  • Priority 推定の妥当性(人間がレビューしたときに合意できる割合)
  • 自動作成された PR のマージ率(提案として意味があったか、人間が書き直す結果になっているか)
  • 1 alert あたりの Copilot premium request 消費量(agent + Detection Job 合算)
  • gh-aw の破壊的変更に遭遇する頻度(technical preview なので覚悟しておく)

数字が揃ったら別記事で続報を書く予定です。


横展開用プロンプト

ここまでの内容を、お使いの coding agent(Claude Code / Cursor / Copilot CLI 等)に渡せば、リポジトリの状況に合わせてガイド付きで再現してくれるはずです。以下をコピーしてお使いください。

coding agent に渡すプロンプト(クリックで展開)
あなたは私のリポジトリで、Sentry alert → GitHub Issue 自動 triage(原因分析・重複判定・必要なら修正 PR 作成)を実装する作業を手伝う。GitHub Agentic Workflows (`gh-aw`, technical preview) と Sentry の公式 MCP server を使う。Anthropic API への直接契約は無く、GitHub Copilot subscription を使う前提。

## 全体像

Sentry alert → "Create GitHub Issue" action(label: `sentry`)→ `.github/workflows/sentry-triage.md` が起動 → AI agent が Sentry MCP / GitHub MCP / ソースコードを使って triage → safe-outputs で comment / label / close-issue / create-pull-request を発行。

## あなたが行うこと

以下の Phase を順に進めること。各 Phase 完了ごとに私に確認を取り、動作を見てから次の Phase に進む。

### Phase A: Sentry 側の準備(私が手作業で行う部分)

私に以下の確認を行うようガイドする:
1. Sentry の Alert Rule で "When a new issue is created" condition を設定し、action として "Create a GitHub issue" を選び、label に `sentry` を指定したか
2. Sentry のサイドバー「開発者向けの設定」(Settings → Developer Settings)→ Personal Tokens から、 read-only スコープ(`event:read` / `org:read` / `project:read` / `team:read`)の token を発行したか。 token を取得したら、 GitHub Repository secret に `SENTRY_ACCESS_TOKEN` として登録するため、次の `gh` コマンドを案内する:

   ```bash
   gh secret set SENTRY_ACCESS_TOKEN
   # プロンプトが出たら Sentry の Personal Token を貼り付けて Enter
   ```

   (`@sentry/mcp-server` の README には write 系 scope の組み合わせも挙がっているが、 triage 用途では read だけで十分なので write は付与しない)

3. GitHub Copilot Business / Enterprise 契約があるか確認し、 fine-grained PAT(Copilot Requests: Read)を発行する手順を案内する。発行したら次のコマンドで secret に登録するよう指示する:

   ```bash
   gh secret set COPILOT_GITHUB_TOKEN
   # プロンプトが出たら fine-grained PAT を貼り付けて Enter
   ```

なお、 `gh secret set` は対話入力のほか `--body` や stdin からも読めるが、 token を shell history に残さないため対話入力を推奨する。リポジトリ内で実行する想定。組織レベルや環境別に登録したい場合は `--org` / `--env` を案内する。

### Phase B: gh-aw の最小疎通

1. ローカルに `gh extension install github/gh-aw` をインストールする手順を案内する
2. `.github/workflows/sentry-triage.md` を作成。frontmatter は `on: issues.labeled` + `if: github.event.label.name == 'sentry'`、`engine: copilot`、`safe-outputs: { add-comment: { max: 1 } }` のみ。本文は「issue 番号にコメントを残す」だけの最小プロンプト
3. `gh aw compile sentry-triage` で `.lock.yml` を生成し、両方 commit する
4. 私に `sentry` label を手で付けて動作確認するよう依頼

### Phase C: Sentry MCP 連携

`mcp-servers` セクションを追加:

```yaml
mcp-servers:
  sentry:
    command: "npx"
    args: ["@sentry/mcp-server@<latest>"]
    allowed: ["*"]
    env:
      SENTRY_ACCESS_TOKEN: ${{ secrets.SENTRY_ACCESS_TOKEN }}
```

注意点(必ず私に伝える):
- `SENTRY_HOST` env は渡さない(hostname のみを期待するので URL を渡すとパース失敗。SaaS なら省略すれば default で sentry.io になる)
- `network.allowed` に `defaults`, `*.sentry.io`, `sentry.io` を追加する。これは agent firewall と output URL sanitizer の両方を兼ねる。Sentry リンクをコメントに残したいなら必須
- `allowed: ["*"]` を使う理由は、tool 名がバージョンで変わるため。安全境界は token の read-only スコープ(API 側 403)と prompt での明示禁止(Seer 系等)で担保する

本文プロンプトに以下を追加:
- Sentry MCP の available tool で issue を取得する(tool 名はバージョン依存なので動的に選ぶよう指示)
- 構造化コメントテンプレ(事象 / 影響範囲 / 根本原因 / 推定優先度 / 主要 stack / 修正方針 / Sentry リンク)
- 「直接 curl で Sentry API を叩かない」「Seer 系 tool を使わない」という禁止事項

### Phase D: ソースコード突き合わせ + 重複判定 + 修正 PR

`safe-outputs` を拡張:

```yaml
safe-outputs:
  add-comment: { max: 1 }
  add-labels: { max: 1 }              # duplicate のみ
  close-issue: { max: 1 }             # 重複と判定したときのみ
  create-pull-request: { max: 1 }     # 修正が自明な場合のみ
tools:
  github:
    toolsets: [issues]
```

本文プロンプトの手順:

1. Issue 本文から Sentry short-id(例: `MYAPP-3` 形式)と URL を抽出
2. Tier 1 重複判定: GitHub MCP `search_issues` で `"<short-id>" in:body is:issue is:open` を検索。自分以外でヒットしたら重複コメント + `duplicate` ラベル + close で終了
3. Sentry MCP で context 取得(type / message / environment / release / occurrences / affected users / first-last seen / tags / top stack frames / breadcrumbs)
4. ソースコード読み込み: top stack frame のうち自リポジトリ app コードに対応するファイルを `${GITHUB_WORKSPACE}` から読む。前後 20-40 行で context を把握
5. 根本原因の特定: 外部 SDK 由来 / テストイベント / 実アプリのバグ / config / 依存サービス / 分類不能 で分類。実アプリのバグなら null / 型 / 競合 / 誤った API 呼び出しなどの仮説と影響範囲を出す
6. Tier 2 重複判定: error type / stack frame / キーワードで類似 issue を `search_issues` で検索し、根本原因を比較。confidence >= 0.9 のときのみ重複扱い
7. 構造化コメント投稿
8. PR 候補判定: 以下を全て満たす場合のみ `create-pull-request`:
   - 実アプリのバグで修正箇所が特定できている
   - localized(typo / null チェック漏れ / 明らかな型ミス / import 漏れ等、1 ファイル概ね 10 行以内)
   - 副作用なしと確信できる
   満たさない場合はコメントの「修正方針」に方針提案だけ残す

Priority 判定の指示(重要):
- Sentry alert は新規 group の最初の発生で起票されるため、件数・頻度は判定材料にしない
- ソースコードを読んで把握した影響範囲で判定する(P0: 全停止 / データ破損リスク、P1: 特定機能不可、P2: 限定的影響、不明: テストイベント等)
- ラベルは付けず、コメント本文に Priority を書くだけ
- ソースコードを読まずに判定しない

## 私に守ってほしい運用方針

- workflow を変更したら必ず `gh aw compile` で `.lock.yml` を再生成し、両方 commit する
- 各 Phase ごとに別 PR、前 Phase が安定してから次へ

## 私が踏んだ落とし穴(先回りして避けてほしい)

1. `SENTRY_HOST` env に URL を渡すと MCP 起動失敗(hostname のみ)
2. `mcp-servers.sentry.allowed` で tool 名を個別列挙するとバージョン上げで壊れる(`["*"]` にする)
3. `network.allowed` に Sentry ドメインを入れ忘れると、コメント内 Sentry URL が `(redacted)` に潰される
4. agent が curl に fallback しようとするので prompt で明示的に禁止する
5. 件数ベースの Priority 基準は使えない(first-occurrence 前提なので影響範囲ベースに)
6. GH Project の Priority field 連携は最初は入れない(PAT 増えて運用が煩雑になる)

## 確認事項

開始前に、以下を私に確認する:
- リポジトリは GitHub Actions が有効か
- Sentry SaaS か self-hosted か(self-hosted なら `SENTRY_HOST` を hostname のみで渡す必要がある)
- Copilot subscription の状況
- 既存の workflow と secret の状況

まとめ

  • Sentry alert → GitHub Issue → AI triage → 必要なら修正 PR までを、自前 webhook も Anthropic 直契約も無しで実現できます
  • 鍵は gh-aw (Markdown workflow + safe-outputs gated job + AI threat detection) + Sentry MCP (stdio + read-only token) + Copilot subscription billing です
  • 落とし穴は主に「URL の扱い(SENTRY_HOSTnetwork.allowed と URL sanitizer の二重役)」「tool 名のバージョン依存」「first-occurrence 前提の Priority 判定」の 3 つです
  • 1 回の実行で premium request が 2 消費される点(agent + Detection Job)に注意

gh-aw はまだ technical preview なので、 frontmatter の構文や safe-outputs の挙動が今後変わる可能性は残っています。今回のユースケースでは、被害範囲が「自分のリポジトリの issue triage で誤動作する」程度に限定されるので、 preview のリスクを取ってでも先に乗る判断をしました。本番で人間が承認する前提のフロー(コメントとラベルが中心、PR は提案として人間がレビューする)にしてあるので、仮に挙動が変わっても気付ける構造になっています。同じユースケースで preview のリスクが許容できないなら、もう少し成熟するまで待つのが妥当です。

書き込み権限を agent から完全に剥がす job 分割設計と、AI による出力検証が標準で備わっている点で、自前で同じことをやろうとすると相当な実装量が必要になります。Sentry 自動 triage のような「外部入力を AI に食わせて GitHub に書き戻す」ユースケースは、これから増えるはずです。同じことをやりたいチームの参考になれば嬉しいです。

参考リンク

gh-aw 関連:

Sentry 関連:

Copilot 課金:

FLINTERS BLOG
FLINTERS BLOG

Discussion