issueトリアージのラベル操作をラッパースクリプトで安全化
Claude Codeのissueトリアージ自動化において、ラベル操作を専用の edit-issue-labels.sh スクリプトに集約し、AIが架空のラベルを適用するリスクを排除しました。あわせてトリアージプロンプトを /triage-issue コマンドとして独立したファイルに分離しています。
背景
これまでのトリアージワークフローでは、AIが gh issue edit --add-label を直接呼び出す設計でした。この設計では、AIが存在しないラベルを「発明」してしまう恐れがあり、プロンプト内に許可ラベルの一覧を静的に列挙することで対応していました。しかし、リポジトリのラベルが増減するたびにワークフローYAMLの更新が必要になるという課題がありました。
さらに、トリアージのロジック全体がワークフローYAMLのインラインプロンプトとして記述されており、69行にわたるプロンプト文字列がワークフロー定義に埋め込まれた状態でした。プロンプトの修正がYAMLの編集を意味するため、保守性の観点から分離が求められていました。
技術的な変更
今回の変更は、ラベル操作のバリデーションをランタイムに移行した点が核心です。新設の scripts/edit-issue-labels.sh は、ラベルを適用する前に gh label list でリポジトリの実在するラベルを取得し、指定されたラベルがその一覧に含まれるかを検証します。
スクリプトは --issue・--add-label・--remove-label の各引数をパースし、issue番号が数値であること、追加・削除のいずれかのラベルが指定されていることを確認してから操作を実行します。バリデーション失敗時は即座に exit 1 で終了するため、不正なラベルがGitHubに送信されることを防ぎます。
トリアージのプロンプトは .claude/commands/triage-issue.md として独立したコマンドファイルに抽出されました。ワークフロー側の変更は prompt: ブロックの削除と1行の差し替えのみで、インラインに展開されていた69行のプロンプトが外部ファイルへの委譲に置き換わっています。コマンドファイルの allowed-tools フロントマターには Bash(./scripts/edit-issue-labels.sh:*) が明示されており、ツールの使用許可をコマンド定義と同じファイルで管理できるようになっています。
また、変更後のコマンドでは gh label list をAIが自ら実行することも促しており、ラベル一覧の取得が「プロンプトへの静的な埋め込み」から「実行時のAPI呼び出し」に変わっています。
# Fetch valid labels from the repo
VALID_LABELS=$(gh label list --limit 500 --json name --jq '.[].name')
設計判断
ラベルバリデーションをAIのプロンプト制約ではなくスクリプト側の責務に移した点が、この変更の最も重要な設計判断です。
プロンプトで「このリストにあるラベルのみ使用せよ」と指示する方法はAIの従順性に依存しており、ラベル一覧の陳腐化リスクも抱えていました。ラッパースクリプトを介在させることで、バリデーションを確定的なコードで行えるようになり、AIの出力がどうであれ不正なラベルは適用されません。
allowed-tools でスクリプトの呼び出しを許可リストに限定する設計も、ツールの使用範囲をコマンド定義と一体で管理できるため、CI設定とは独立したセキュリティ境界を形成しています。
まとめ
プロンプト内の静的な制約をランタイムのバリデーションに置き換えたことで、ラベル操作の安全性がAIの挙動に依存しない確定的な保証に昇格しました。プロンプトの外部コマンド化と合わせて、トリアージ自動化の保守性と信頼性が同時に向上した変更です。