scenario-unity-pipeline-automation について
scenario-unity-pipeline-automationは、再現可能なコンテンツパイプラインを構築するUnityのツール・ビルドエンジニア向けスキルです。決定的なインポート、シリアライズを介した編集、Addressablesのパッケージ化、テストを通したビルド、クリーンなチェックアウトからのCIを扱い、件数と再実行時の安定性を確認します。
主な機能
- 01決定的なアセットインポート規則
- 02アセットとプレハブのシリアライズ編集
- 03Addressablesのグループ化とコンテンツビルド
- 04ビルド前テストとリリースゲート
- 05プレイヤーのスモークテスト
- 06CIパイプラインの生成
活用シーン
- 01大量のFBXアセットのインポート自動化
- 02ロード条件に基づくコンテンツバンドルの構築
- 03コンテンツテストによるプレイヤーリリースの判定
- 04クリーンなCIチェックアウトからのビルド実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-unity-pipeline-automationインストール後、Claude Code で/scenario-unity-pipeline-automationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/ut_pipeline.pyscripts/AgentKit/Pipeline/AddressablesJobs.csArtDropJobs.csEditorEditJobs.csPipelineBuild.csPipelineChecks.csPipelineRules.csPropImportPostprocessor.csscripts/AgentKit/Pipeline/Tests/PipelineContentTests.csscripts/AgentKit/PipelineCli/AgentKit.PipelineCli.asmdefPipelineCliCommands.csscripts/Runtime/AgentAddressablesSmoke.csscripts/templates/PipelineAsmdef/Editor/Game.Pipeline.Editor.asmdefTextureRuleAudit.csscripts/templates/PipelineAsmdef/Tests/Game.Pipeline.Tests.asmdefTextureRuleTests.cs詳細
Unity パイプライン自動化(ツールおよびビルドエンジニア)
ここでのエキスパートレベルとは、すべてのマシン、すべての実行で同じ結果を得られるパイプラインを指します。インポート時にルールを適用し、シリアル化を通じて編集し、読み込みタイミングに応じてコンテンツをパッキングし、ビルドをゲートするテストを実行し、クリーンなチェックアウトから CI がビルドを実行します。基本方針は、同じ作業を手作業で二度行わないこと、件数、テスト、またはフレームで確認しない限り何も信用しないこと、そして二度目の実行で何も変更されないことです。
ここに記載された関連スキルが利用可能なスキルにない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人で進める場合は、ツールのスキーマに基づいて作業し、不足している点を明示してください。
必須の背景知識: scenario-unity-expert(チャンネル、ジョブプロトコル、レビューループ、6.3 の落とし穴)。
そのツールキットをインポートしてください。このスキルでは scripts/ut_pipeline.py と
scripts/AgentKit/Pipeline/ が追加されます。
ステータス(2026-09-24、ブラインド採点のリファクタリング後): この Mac 上で Unity 6000.3.21f1 を使い、200 個の FBX を含む Blender のドロップに対してすべての手順を実行しました:tests/code/unity-pipeline-automation/(結果は archive/tests/unity-pipeline-automation/live_results.jsonl)。
スタンス(専門家との差分)
- インポートルールはインポート時に実行されるコードであり、決定論的であることを証明します。
OnPreprocess*内の設定、コード変更ごとのGetVersion()の更新、読み取る前に宣言する設定(context.DependsOnSourceAsset)、クロックを使わないこと、辞書の順序に依存しないこと、コールバック内でアセットを書き換えないこと(6.3 Manual;Javier Abud Chavez、S2P9n5U9xVw [00:04:35]、[00:19:29])。証明:共有キャッシュや CI を信頼する前に-consistencyCheckを実行します(Manual)。確認結果:23.5 秒で12,184個のアセットをチェックし、ランダムなピクセルを含むプローブテクスチャにフラグが立ちました。管理対象593ファイルのうち、該当したものは0個でした。バージョンを更新したり、新しいポストプロセッサーを追加したりすると、そのインポータータイプの全アセットが再インポートされ、パッケージも対象になります(テクスチャ1,513個)。 - 変更として認められるのは、正確なオブジェクトに対してシリアライズを経由した場合だけです。 変更前に、変更するコンポーネントに対して Undo を記録します(Freya Holmér、pZ45O2hg_30 [03:01:01])。確認結果:
Undo.RecordObject(go)の後に移動しても元に戻せませんが、RecordObject(go.transform)なら元に戻せます。Prefab インスタンスに直接書き込むと、次の Prefab 更新時に変更が取り消されます。ScriptableObject はSetDirtyを呼ばないと保存されません。 - 各ステージで AssetDatabase のバッチ処理を1回実行し、計測します。
try/finally内でStartAssetEditing/StopAssetEditingを使用します(Abud Chavez [00:30:21])。SaveAndReimport/ImportAssetもその中で実行します。ログではなく AssetDatabase のカウンターで数えます(Abud Chavez [00:26:44])。確認結果:FBX 195個に対する2回のリマップ処理は、1つずつ行うと19.0秒、バッチ処理では5.1秒でした。 - Addressables はフォルダー単位ではなく、読み込み条件ごとに安定した順序でパックします。 まったく同じ条件下で必要となるアセットは同じグループにまとめ、複数のグループで使用される依存関係は明示的に配置します(Olle Axelsson、Valheim、Fzu2Das_1FU [00:23:08])。割り当てられていない共有依存関係は各バンドルにコピーされます [00:18:44]。確認したところ、URP の
Lit.shaderも含まれていました。序数順で割り当てます(6.3 Manual、Addressables determinism):2.9.1 は保存時にグループとエントリーを GUID 順に並べ替えますが、ラベルテーブルは挿入順を維持します。 - リリースしてもアンロードされるわけではなく、参照は読み込みです。 バンドルの参照カウントがゼロになると、メモリが解放されます(Addressables 2.9 manual)。Addressable コンテンツを参照するビルドシーンは、シーンと一緒に読み込まれ、さらにバンドルからも読み込まれます(Code Monkey、C6i_JiRoIfk [00:03:32];Axelsson [00:24:49])。その動作をゲートし、プレイヤー内でアンロードを計測します。
- 起動時にプラットフォームを固定し、すべてのステージで同じ設定を維持して、ビルドしたコンテンツを出荷します。 バッチジョブ内でターゲットを切り替えても何も起こりません(Manual;Thom Hopper、BlVsi2cSJ88 [00:27:18])。ビルドターゲットはインポートの依存関係です(Abud Chavez [00:15:49])。確認結果:Android で実行した1つのステージでは、1,717個のアセットが52秒かけて再インポートされました。元に戻す際にはキャッシュされた成果物が再利用されました(インポート60個)。Addressables のデフォルト設定では、すべてのプレイヤービルド内で全コンテンツが再ビルドされます。
- テストをゲートにします。 コンテンツルールは、アセットごとに1ケースを設けたパラメトリックな Edit Mode テストとして実装し(Warnecke and Fine、wTiF2D0_vKA [00:24:28])、合格をログに記録するプリビルドコールバック内で同期実行します [00:31:43]。ログに記録されたエラーは、
LogAssert.Expectで事前に指定されていない限りテストを失敗させます(Manual)。確認したところ、テスト内の再インポートで記録されたインポートエラーも該当しました。-runTestsと一緒に-quitを指定してはいけません。 - リリースビルドは、デバッグ用の定義を使わず、由来を維持したクリーンなツリーから作成します(docs digest checklist;Hopper、profile defines)。汎用的な実行より、対象を絞った名前付きツールを使います(git-amend、VPjo-M6mPkE [00:03:54];Unity、DgNrgZeJOxQ [00:07:41])。
まず決めておくこと
- 納品物の仕様: DCC とエクスポート設定、カテゴリごとのフォルダー、サフィックス、単位。デフォルト:Blender の
「FBX All」+「Apply Transform」、
_BaseColor/_Normal、追加ラベル用のmanifest.csv。 - 読み込み条件: セット(レベル、バイオーム)として読み込むか、個別に読み込むか。デフォルト:ラベル、
key_by="label"。ストリーミングではkey_by="root"を使用します。 - 対象と予算: プラットフォーム(パイプラインの実行ごとに
-buildTargetを 1 つ指定)、プラットフォームごとのテクスチャ上限、頂点予算、ラベルごとのバンドル予算。デフォルト:デスクトップは 1024 px、モバイルは 512、頂点数は 5,000。 - コンテンツの更新: リリース後にリモートコンテンツを更新するか。リリースごと、プラットフォームごとに
addressables_content_state.binをアーカイブします。 - チャネルと CI: ユーザーのエディターでプロジェクトが開かれているか(
ut_live.channel(P))。Git リポジトリはあるか。Accelerator はあるか。ライセンス:Personal(Hub へのサインインのみ)または有料シート。
ワークフロー
- 事前チェック。
ut_env.preflight(P);ut_pipeline.install(P)。エディターが開いている場合は、同じジョブをut_live.callまたは[CliCommand]ツール経由で実行します。チームのテストから呼び出すパイプラインコードには、専用の Editor asmdef とテスト用 asmdef が必要です(install_asmdef_template)。GATE:Echoが成功し、コンパイルエラーが 0 件であること(1 件でもあると、すべてのバッチジョブが中断します)。 - 納品物をオフラインでスキャン。
up.scan_drop(drop)、同じルール JSON を使用します。GATE:却下されたすべてのファイルに理由があること。同一ファイルが重複している場合は、すべてのコピーを却下します。 - インポート。
up.import_drop(P, drop, target=T):変更されたファイルを<root>/<Category>/<Name>/にインポートし、1 回のバッチで処理して監査します。GATE:受け入れ数 = 検出数 - 却下数。監査エラーの説明があること。ポストプロセッサの変更後にup.consistency_check(P, target=T)を実行し、Assets/配下に何も検出されないこと。 - マテリアルとプレハブ。
up.build_prefabs(P, target=T):プロップごとに URP Lit を使用し、ShaderGUI.ValidateMaterialに従ってキーワードを設定します。バッチ内でSaveAndReimportを使って FBX をリマップし、プレビューシーンで Prefab Variants を作成します。値が変更された場合のみ保存します。GATE:プレハブ数 = 受け入れ数 - サイズエラー数。再実行で書き換えられるファイルが 0 件(git statusがクリーン)であること。 - 見た目を確認。
EditorEditJobs.BuildLineupの後にAgentCapture.CaptureViewsをgraphics=Trueで実行し、ut_review.review_captureを使ってシートを開きます。GATE:マゼンタ、黒、空白のフラグがないこと。プロップが直立し、地面に接し、適切なスケールであること。 - Addressables グループ。
up.assign_addressables(P, "condition", target=T)。GATE:implicit_duplicates == 0であること。up.hard_references(P)が成功すること。 - コンテンツをビルド。
up.build_content(P, T):ビルダーインデックスが>= 0、ClearCachedDataとBuildCache.PurgeCache(false)を実行し、DoNotBuildWithPlayerを使用します。レイアウトを読み戻し、状態をアーカイブします。GATE:重複アセットが 0 件で、ラベルごとのバイト数が予算内であること。 - テスト。
ut_run.run_tests(P, "EditMode", categories="PipelinePreBuild", extra_args=["-buildTarget", up.cli_target(T)])。 GATE:失敗数が 0 件で、合計数が想定アセット数と一致すること。 - プレイヤーをビルド。 コミット済みのテンプレートからプロファイルをコピーします(
templateを指定してPipelineBuild.CreateBuildProfile)。ut_run.build(P, T, profile=...)を実行するか、-activeBuildProfile ... -executeMethod AgentKit.Pipeline.PipelineBuild.BuildFromCommandLineを直接実行します。 リリースでは-agentReleaseを指定し(ゲートでデバッグ用定義を拒否)、ツリーをクリーンに保ち、up.release_ready(repo, app)を実行します。GATE:AGENT_GATEが成功し、hard_referencesが 0 件で、BuildReport がSucceededであること。 - プレイヤーのスモークテスト。
up.player_smoke(app, label)。GATE:読み込まれたアセット数がマニフェストの件数と一致し、リリース後にバンドルがアンロードされること。 - CI。
up.write_ci(repo):ci/pipeline.sh(ステージごとに 1 つのプロセスを使用し、各ステージで同じ-buildTargetを指定。ACCELERATOR=、CONSISTENCY=1、RELEASE=1)と GitHub Actions のファイルを生成します。GATE:Library/のないチェックアウトから実行して成功すること。ライセンスがif: always()で返却されること。Accelerator を使用する場合、ログ内のcache server=の件数が 0 より大きいこと。
数値
| 値 | 対象 | 出典 |
|---|---|---|
| 5.6~6.7 秒 | 593 ファイルを 1 回のバッチでコピーおよびインポート | 実測 |
| 19.0 秒 対 5.1 秒 | 195 個の FBX に対する 2 回のリマップパス(SaveAndReimport)。1 件ずつ処理する場合と 1 回のバッチで処理する場合 | 実測 |
| 11~12 秒 | 197 個のマテリアル、197 個の FBX リマップ、196 個のプレハブバリアント。エディター内の所要時間 | 実測 |
| 1,717 インポート、52 秒/60 インポート | 別のプラットフォームでの初回起動/切り替え後に戻った場合(キャッシュ済みアーティファクト) | 実測 |
| 1,513 個のテクスチャ、17 秒 | 何もしないテクスチャポストプロセッサーの GetVersion() を 1 回更新したことで再インポート | 実測 |
| 12,184 件をチェック、23.5 秒 | このプロジェクトの -consistencyCheck(7,390 件をスキップ。URP シェーダー 2 個にフラグ:ベースラインパッケージ) | 実測 |
| 0 ファイル | 2 回目の全実行(インポート、プレハブ、グループ)で変更されたファイル | 実測 |
| 791 件のテスト、10~16 秒 | 196 個のプレハブ、396 個のテクスチャ、197 個のモデルに対するコンテンツテスト | 実測 |
| 13.5/12.9/4.8 MB | 最大ラベル読み込み量。カテゴリ/分離/条件レイアウト(3 つのバイオーム) | 実測 |
| 5 | カテゴリレイアウト内の重複アセット(テクスチャ 2 個、Lit.shader、フォールバック 2 個) | 実測 |
| 0~63 ミリ秒 | 最後の Release 後もロードされたままのバンドル(7 回のプレイヤー実行) | 実測 |
| 60~158 秒/5~23 秒 | 初回の macOS Mono プレイヤービルド/増分リビルド(共有マシン)。プレイヤーは 127.4 MB | 実測 |
| 0.4~1.2 秒 対 10~17 秒 | 常駐エディターのブリッジ経由で実行した同じジョブと、エディター起動を伴うバッチジョブ | 実測 |
| 4 GB | クロスプラットフォーム互換性のためのバンドルあたりの上限 | Addressables 2.9 マニュアル |
| 30,000 頂点 | FBX の予算に関する警告の例 | Unity チュートリアル、qZ5NmyoxKRk [00:03:55] |
| 38%、約 110 MB | ストリーミングによる Valheim のメモリ削減量、およびロード済みバンドルの削減によるメモリ削減量 | Axelsson [00:03:02]、[00:30:41] |
| 179 秒/486 秒 | Library/ のないチェックアウトから生成した ci/pipeline.sh(v0.2、低負荷のマシン/v0.1、ほかにエディター 6~8 個) | 実測 |
| 0/8/6 | unity test の終了コード:成功/テスト失敗(再試行しない)/判定なし(再試行) | unity-cli スキル |
品質ゲート
- 測定可能: エンベロープの
ok、コンパイルエラーなし、すべてのステージでactive_targetが一致していること、ImportDrop のカウント、Assets/配下の整合性チェックがクリーンであること、プレハブ数、再実行時のコピー数が 0 であること、git statusがクリーンであること、implicit_duplicatesが 0 でduplicated_assetsが 0 であること、ラベルごとの KB、Addressable コンテンツをハード参照するビルドシーンがないこと、NUnit の失敗数が 0 で期待される合計数と一致すること、AGENT_GATEが正常であること、BuildReport がSucceededであること、プレイヤーのスモークテストのカウント、リリース時にツリーがクリーンであること、プロベナンスのsource.dirtyが false であること、禁止された定義がないこと、クリーンなチェックアウトから CI スクリプトを実行した際の終了コードが 0 であること。 - 視覚: 配置シートを開き、マゼンタ色ではないこと、法線マップで陰影が付いていること、プロップが直立していること、ピボットが地面にあること、1.8 m のカプセルと並べたときに妥当なサイズであることを確認します。
よくある間違い
| 間違い | 発生する問題 | 対処法 |
|---|---|---|
OnPostprocessTexture でインポーター設定を変更し、コードを変更しても GetVersion() を更新しない | 古い設定が使われ、マシン間で動作が異なる | OnPreprocess* を使い、バージョンを更新して -consistencyCheck を実行する |
| ルール JSON にインポーター以外のキーを追加する | 管理対象のアセットがすべて再インポートされる | 別ファイル(pipeline_checks.json)に分ける |
移動する前に Undo.RecordObject(gameObject) を呼び出す | 移動を元に戻せない | Transform を記録する |
| Prefab インスタンスまたは ScriptableObject に直接書き込む | 次回の Prefab 更新時に変更が戻る/ファイルが変更されない | RecordPrefabInstancePropertyModifications / SetDirty を使う |
finally を使わずに StartAssetEditing を呼び出す。バッチ外で FBX ごとに SaveAndReimport を呼び出す | データベースがフリーズする。リマップが 4 倍遅くなる | try/finally を使い、バッチ内で再インポートする |
各ステージで異なる -buildTarget を指定する | ステージごとにテクスチャとシェーダーが再インポートされる | テストを含むすべてのステージで同じターゲットを指定する |
| 共有テクスチャのあるフォルダーごとにグループを作成する | 同じテクスチャとシェーダーが各バンドルに含まれる | 条件付きパッキングを使用し、ビルドレイアウトを確認する |
| ファイル内または HashSet の順序でラベルを追加する | マシンごとに設定ファイルの内容が異なる | 序数順に並べる |
| ビルドシーンから Addressable Prefab を参照する | 二重にロードされ、バンドルが迂回される | ゲートで HardReferences を確認する |
| コンテンツをビルドしてから、デフォルトのプレイヤービルドを行う | コンテンツが再ビルドされ、アーカイブ済みの状態が古くなる | DoNotBuildWithPlayer とゲートを使う |
バッチジョブで SetActiveBuildProfile を使う。内部 API のプロファイルを使う | ターゲットまたは定義が古くなり、アップグレード時に壊れる | -activeBuildProfile を使い、コミット済みのテンプレートをコピーする |
| インポーターがエラーをログに出力するアセットをテストで再インポートする | "Unhandled log message" が発生し、テストが失敗する | LogAssert.Expect を使う |
| テスト用 asmdef から Assembly-CSharp-Editor 内のコードを呼び出す | CS0103 が発生し、すべてのバッチジョブが中断される | パイプラインコードを独自の Editor asmdef に配置する |
Accelerator を使い、待機フラグなしで -quit を指定する。サーバーに到達できない | アップロードが失われ、ジョブは何も知らせずに成功する | -cacheServerWaitForUploadCompletion を指定し、cache server= を確認する |
| 作業ツリーに変更がある状態でリリースする | プロベナンスが dirty: true になり、CLI はビルドを続行する | 作業ツリーをクリーンにし、RELEASE=1 を指定して、Addressables の link.xml を gitignore に追加する |
| Blender のデフォルト設定で FBX をエクスポートする | ルートが 90 度回転し、スケールが 100 になる | FBX All + Apply Transform を使う(scenario-blender-export) |
| 名前の重複を順序で解決する | 間違ったアセットが黙って選ばれる | 重複するものをすべて拒否し、問い合わせる |
| ジョブ内で Addressables 設定を作成する | 次回実行時に設定ファイルが一度書き換えられる | GetSettings(true) の後に 2 つのプロバイダータイプを設定する |
-runTests とともに -quit を指定する。相対パスの --output-path を使う | XML が出力されず、プロジェクト外にビルドされる | -quit を省略し、絶対パスを指定する |
引き継ぎ
- 受け取るもの: scenario-blender-export、scenario-maya-expert、scenario-3d、scenario-textures から、エクスポート設定付きの FBX とテクスチャを受け取ります。scenario-unity-architecture からコードのレイアウトと asmdefs を受け取ります。scenario-unity-world-building から、どのプロップを一緒に読み込むかを受け取ります。
- 引き渡すもの: scenario-unity-performance にはビルドレポート、バンドルサイズ、ラベルごとの読み込み情報を渡します。scenario-unity-mobile にはテクスチャ形式(このスキルが設定するのはサイズ上限のみ)と署名済みビルドを渡します。scenario-unity-web には Web ビルドを渡します(WebGL では
WaitForCompletionを使用しません)。scenario-unity-rendering-lighting にはライトマップ UV の要件を渡します。リードには、ルール JSON、プロップのマニフェスト、エンベロープ、NUnit の合計数、レイアウト JSON、BuildReport、プロベナンス、コンタクトシートを渡します。
Unity 6.3 に関する注意事項
- Addressables 2.9.1 はこのエディターのデフォルトです(フォルダーキーと
await handleは 4.0 です)。そのポストプロセッサーは、インポートされたすべてのグループアセットをデフォルト設定に採用します。6.6 では Content Directories が AssetBundle ビルドに置き換わります。 IPreprocessBuildWithContextは AssetBundle ビルドでも実行されます。BuildPipeline.isBuildingPlayerでフィルタリングしてください。- 6.5 より前には、プロファイルを作成する公開 API はありません。AssetDatabase カウンターは
UnityEditor.Experimental.AssetDatabaseExperimental.countersで公開されています。 - Unity CLI はベータ版です。
unity buildは macOS ではプロベナンスマニフェストを.app内に書き込みます。Personal ライセンスのアクティベーションは Hub へのサインインでのみ行えます。
参考資料
references/procedures.md:パイプラインを、実際のテストと結果を添えたコピー可能な呼び出しとしてまとめています。references/expert-notes.md:専門家による原則と判断を、出典とタイムスタンプとともに記載しています。references/critique.md:パイプライン、レイアウト、ビルド、リリースを評価するための基準です。references/gui-paths.md:同じタスクを実行するためのウィンドウとメニューです。references/sources.md:認証情報、URL、タイムスタンプ、改訂履歴を含むすべての出典です。scripts/ut_pipeline.py、scripts/AgentKit/Pipeline/*.cs(ジョブ、ポストプロセッサー、チェック、ゲート、コンテンツテスト)、scripts/AgentKit/PipelineCli/、scripts/Runtime/、scripts/templates/PipelineAsmdef/:コードです。