temporary-id-safe-output について
safe output ジョブに一時 issue ID を導入するための開発スキルです。ID の生成、ワークフロージョブ間の対応表の受け渡し、参照解決、他の処理を止めない失敗処理を扱います。
主な機能
- 01一時 ID の生成と検証
- 02一時 ID と issue 番号の対応付け
- 03ワークフロー依存関係と環境変数の設定
- 04テキスト内の一時 ID 参照の置換
- 05警告による解決失敗の処理
活用シーン
- 01作成直後の親 issue にサブ issue をリンク
- 02safe output ジョブへの一時 ID 対応の追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ github/ gh-aw --skill temporary-id-safe-outputインストール後、Claude Code で/temporary-id-safe-outputを入力して読み込まれたか確認します。
詳細
安全な出力ジョブへの一時 ID サポートの追加
安全な出力ジョブで一時 ID をサポートするには、この実装計画を使用してください。一時 ID を使用すると、実際の課題番号が確定する前に、エージェントが同じ実行内で新しく作成された課題を参照できます。
問題の説明
エージェントが親課題を作成し、同じ実行内ですぐにサブ課題をリンクする場合、create_issue が完了するまで実際の課題番号はわかりません。一時 ID を使うことで、実行時に解決されるプレースホルダーを通じてこの問題を解消できます。
一時 ID の形式
一時 ID は aw_[A-Za-z0-9]{3,8} のパターンに従います。
aw_は、エージェント型ワークフローの一時 ID を示す固定プレフィックスですXXXXXXXXは、3〜8 文字の英数字(A-Za-z0-9)です
例:aw_abc、aw_abc123、aw_Test123
実装コンポーネント
1. 共有モジュール:temporary_id.cjs
場所:pkg/workflow/js/temporary_id.cjs
このモジュールは、一時 ID を処理するための共有ユーティリティを提供します。
// Core functions
generateTemporaryId() // Generate new temporary ID
isTemporaryId(value) // Check if value is a temporary ID
normalizeTemporaryId(tempId) // Normalize to lowercase for map lookups
loadTemporaryIdMap() // Load map from GH_AW_TEMPORARY_ID_MAP env var
resolveIssueNumber(value, map) // Resolve value to issue number (supports temp IDs)
replaceTemporaryIdReferences(text, map) // Replace #aw_XXX references in text
2. 生成ジョブ:create_issue
create_issue ジョブは、他のジョブが利用できる一時 ID マップを出力します。
Go の変更(pkg/workflow/create_issue.go):
- 変更不要です。すでに
temporary_id_mapを出力しています。
JavaScript の変更(pkg/workflow/js/create_issue.cjs):
- 作成した各課題の一時 ID を生成します
temporary_id -> issue_numberのマップを作成しますcore.setOutput("temporary_id_map", JSON.stringify(map))でマップを出力します
3. コンシューマージョブ:一時 ID サポートの追加
一時 ID の解決が必要な安全な出力ジョブごとに、以下を実施します。
ステップ 1:Go ジョブビルダーを更新する
pkg/workflow/<job_name>.go で:
- ビルド関数に
createIssueJobNameパラメーターを追加します。
func (c *Compiler) build<JobName>Job(data *WorkflowData, mainJobName string, createIssueJobName string) (*Job, error) {
- 一時 ID マップを渡す環境変数を追加します。
if createIssueJobName != "" {
customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_TEMPORARY_ID_MAP: ${{ needs.%s.outputs.temporary_id_map }}\n", createIssueJobName))
}
- ジョブの
needs配列にcreate_issueを追加します。
needs := []string{mainJobName}
if createIssueJobName != "" {
needs = append(needs, createIssueJobName)
}
- 動的な
needsを使用するようにSafeOutputJobConfigを更新します。
return c.buildSafeOutputJob(data, SafeOutputJobConfig{
// ...
Needs: needs,
// ...
})
ステップ 2:コンパイラージョブを更新する
pkg/workflow/compiler_jobs.go で:
ジョブをビルドする際に createIssueJobName を渡します。
job, err := c.build<JobName>Job(data, mainJobName, createIssueJobName)
ステップ 3:JavaScript スクリプトを更新する
pkg/workflow/js/<job_name>.cjs で:
- 一時 ID ユーティリティをインポートします。
const { loadTemporaryIdMap, resolveIssueNumber } = require("./temporary_id.cjs");
main()の冒頭で一時 ID マップを読み込みます。
const temporaryIdMap = loadTemporaryIdMap();
if (temporaryIdMap.size > 0) {
core.info(`Loaded temporary ID map with ${temporaryIdMap.size} entries`);
}
resolveIssueNumber()を使用して課題番号を解決します。
const resolved = resolveIssueNumber(item.issue_number, temporaryIdMap);
if (resolved.errorMessage) {
core.warning(`Failed to resolve issue: ${resolved.errorMessage}`);
continue;
}
const issueNumber = resolved.resolved;
if (resolved.wasTemporaryId) {
core.info(`Resolved temporary ID '${item.issue_number}' to issue #${issueNumber}`);
}
ステップ 4:エージェント入力の検証を更新する
pkg/workflow/js/collect_ndjson_output.cjs で:
一時 ID を受け付けるフィールドに検証を追加します。
function isValidIssueNumberOrTemporaryId(value) {
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
return true;
}
if (typeof value === "string" && /^aw_[0-9a-f]{12}$/i.test(value)) {
return true;
}
return false;
}
この検証を parent_issue_number、sub_issue_number などのフィールドに使用します。
4. 失敗の処理
一時 ID の解決に失敗した場合、ジョブは以下のように動作する必要があります。
core.setFailed()で失敗させるのではなく、core.warning()で警告を記録します- 他の項目の処理を続行します
- ステップのサマリーに失敗内容を含めます
- 警告を伴って正常に完了します
これにより、以下が実現します。
- 部分的な成功が可能になります(リンクの一部が成功し、他は失敗する場合があります)
- 1 件の解決失敗によってワークフロー全体が致命的な失敗に陥るのを防ぎます
- ユーザーがステップのサマリーで警告を確認できます
使用例
ワークフロー設定
safe-outputs:
create-issue:
title-prefix: "[Parent] "
labels: [tracking]
max: 3
link-sub-issue:
max: 10
エージェントの出力
{"type": "create_issue", "temporary_id": "aw_abc123", "title": "Parent: Feature X", "body": "..."}
{"type": "link_sub_issue", "parent_issue_number": "aw_abc123", "sub_issue_number": 42}
{"type": "link_sub_issue", "parent_issue_number": "aw_abc123", "sub_issue_number": 43}
実行フロー
mainジョブ:エージェントが一時 IDaw_abc123を含む出力を生成しますcreate_issueジョブ:課題 #100 を作成し、{"aw_abc123": 100}を出力しますlink_sub_issueジョブ:- 一時 ID マップを読み込みます
aw_abc123→100を解決します- 課題 #42 と #43 を #100 のサブ課題としてリンクします
一時 ID をサポートするジョブ
| ジョブ | フィールド | ステータス |
|---|---|---|
link_sub_issue | parent_issue_number、sub_issue_number | ✅ 実装済み |
add_comment | issue_number(テキスト置換による) | ✅ 実装済み |
update_issue | issue_number | 🔄 追加可能 |
close_pull_request | - | N/A(PR 番号を使用) |
テスト
単体テスト
pkg/workflow/js/temporary_id.test.cjs に以下のテストを追加します。
- 有効な入力と無効な入力に対する
isTemporaryId() - 一時 ID と通常の番号に対する
resolveIssueNumber() - さまざまな JSON 入力に対する
loadTemporaryIdMap()
統合テスト
pkg/workflow/<job_name>_dependencies_test.go に、以下を検証するテストを追加します。
- 設定されている場合、ジョブの needs に
create_issueが含まれる GH_AW_TEMPORARY_ID_MAP環境変数が正しく設定されるcreate_issueへの依存関係がなくてもジョブが動作する
セキュリティに関する考慮事項
- 一時 ID は、単一のワークフロー実行内でのみ有効です
- マップは環境変数を介して渡されます(外部には公開されません)
- エージェントが一時 ID を偽造し、他のワークフローのイシューを参照することはできません
- 解決に失敗した場合はログに記録されますが、一時 ID マップの内容は公開されません
新しいジョブに対応するためのチェックリスト
- Go ジョブビルダーが
createIssueJobNameパラメーターを受け取るように更新する -
GH_AW_TEMPORARY_ID_MAP環境変数を追加する -
needs配列に、条件付きでcreate_issueを含めるように更新する -
compiler_jobs.goを更新し、createIssueJobNameを渡す - JavaScript スクリプトに一時 ID ユーティリティをインポートする
- イシュー番号のフィールドで
resolveIssueNumber()を使用する - 必要に応じて
collect_ndjson_output.cjsの検証を更新する - 解決ロジックの単体テストを追加する
- ジョブの依存関係に関する統合テストを追加する
- ドキュメントを更新する