mcpField
L
llm-to-bedrock

llm-to-bedrock

github.com/aws開発3.3k343 回インストール1 日前に更新
リポジトリ

llm-to-bedrock について

OpenAI、Gemini、Anthropic の呼び出しを Amazon Bedrock に移行するスキルです。コードの評価と移行に加え、モデルアクセスのみを有効化する手順もあります。完全な移行には `gcp-to-aws` または `azure-to-aws` スキルが必要です。

主な機能

  1. 01Amazon Bedrock への移行
  2. 02モデル呼び出しの評価と書き換え
  3. 03モデルアクセスのみの有効化経路
  4. 04移行用の併設スキルが必要

活用シーン

  1. 01既存のモデル呼び出しを Bedrock に移行
  2. 02コードベースを確認して移行を計画
  3. 03必要な Bedrock モデルへのアクセスを有効化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/aws/agent-toolkit-for-aws --skill llm-to-bedrock

インストール後、Claude Code で/llm-to-bedrockを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/helpers/bedrock-known-fixes/
bedrock-known-fixes.md
references/helpers/bedrock-known-fixes/references/
bedrock-iam-inference-profile.md
bedrock-inference-profile-model-id.md
bedrock-response-key-casing.md
bedrock-vision.md
bedrock-vision.py.template
references/helpers/behavior-delta-detection/
behavior-delta-detection.md
references/helpers/behavior-delta-detection/references/
anthropic-to-bedrock.md
gemini-to-bedrock.md
openai-to-bedrock.md
references/helpers/dependency-conflict-resolution/
dependency-conflict-resolution.md
references/helpers/resolve-bedrock-model-id/
resolve-bedrock-model-id.md
references/helpers/run-source-model-baseline/
run-source-model-baseline.md
references/vendored/telemetry/
cli.py
PROTOCOL.md
version.json
references/vendored/telemetry/consent/
accept.py
cli.py
notice.py
opt_out.py
record.py
references/vendored/telemetry/metric_emission/
client.py
migration_attributes.py
migration.py
scripts/
bedrock_pricing.py
iam_policy.py
image_input.py
model_identity.py
preflight_bedrock.py
pyproject.toml

詳細

翻訳後に原文が更新されています。最新の内容は原文をご確認ください。

Bedrock への移行(評価+実行)

単一コマンドで AI を移行できます:OpenAI / Gemini / Anthropic → Amazon Bedrock。

このスキルと一緒に、gcp-to-aws または azure-to-aws スキルをインストールする必要があります。 この スキルには単独で動作する評価の実装はありません。以下のフェーズ A では、同じセッション内で、インストールされている いずれかのスキル独自のフェーズ指示ファイルを直接読み取り、実行することで評価を実施します(agent-advisor が migration-plan フェーズで使用するものと同じインライン実行パターンです。スキル間のツール呼び出しも、ターンの境界もなく、 エージェントがスキル/サブエージェントのディスパッチ機能に対応している必要もありません。ファイルを読む方法はどのエージェントでも使えます)。これらの兄弟スキルのどちらも存在しない場合に、このスキル自身が評価を実施するフォールバック経路はありません。このスキルだけをインストールした場合(たとえば、単一スキルで npx skills add を実行した場合)は、 使用する前に gcp-to-aws または azure-to-aws もインストールしてください。

スキルのベースディレクトリは、ハーネスが読み込み時に出力する「Base directory for this skill: X」の行に示されています。これを <SKILL_BASE> とします。派生パスは次のとおりです。

  • $SCRIPTS = <SKILL_BASE>/scripts
  • $HELPERS = <SKILL_BASE>/references/helpers(以前はヘルパースキルでしたが、現在はリファレンスです)
  • $ASSESS_SKILL / $ASSESS_BASE — ステップ 0b で一度だけ解決します。$ASSESS_SKILL は、このスキルと一緒にインストールされている gcp-to-aws / azure-to-aws のいずれかです(両方ある場合は gcp-to-aws を優先します)。$ASSESS_BASE = <SKILL_BASE>/../$ASSESS_SKILL は、その兄弟スキルの ディレクトリです。フェーズ A ではこのパスから指示ファイルを直接読み取ります。$ASSESS_SKILL ファイル内のすべての相対参照 (references/shared/...、references/phases/... など)は、$ASSESS_BASE の下で解決されます。これは $ASSESS_SKILL を単独で実行した場合と同じです。

利用状況のテレメトリ(任意)

開始または再開する前に、references/vendored/telemetry/PROTOCOL.md を読み込み、 読み取り専用のステータス確認を実行してください。モデルの識別情報ではなく、返されたレポートモードを使用してください。 既存の通知に関するやり取りを完了するのは、そのプロトコルで必要な場合に限ります。テレメトリが利用できない場合や拒否された場合でも、このスキルの実行は妨げられません。

ステップ 0 — 前提条件を確認する

0a. uv が利用可能か確認する
uv --version 2>/dev/null || echo "MISSING"

見つからない場合:「まず uv をインストールしてください。公式インストールガイドを参照してください:https://docs.astral.sh/uv/getting-started/installation/(例:`brew install uvまたはpipx install uv`)」。停止します。

0a-bis. 振り分け:完全な移行か、アクセスのみか

このスキルには 2 つのモードがあります。評価用の兄弟スキルを確認する(0b)前に、ユーザーがどちらを希望しているか判断してください。アクセスのみのモードでは gcp-to-aws / azure-to-aws を一切使用しないため、ここでいずれかを必須にすると、アクセスの有効化だけを希望するユーザーの利用を妨げてしまいます。

次のいずれかに該当する場合は、アクセスのみのモードに振り分けます(下記の「## アクセスのみのモード」セクションに進み、0b とステップ 1 以降はスキップします)。

  • $ARGUMENTS にアクセスの明示的なリクエスト表現(model access、request access、 enable model access、just access、または preflight)が含まれており、ソースコードのパスが指定されていない場合。単独の enable や access だけを理由に振り分けないでください。「enable the Bedrock rewrite」はアクセスのリクエストではなく、完全な移行です。判断に迷う場合は、キーワードではなく、以下の AskUserQuestion を使用してください。または
  • ユーザーの依頼が、コードの書き換えではなく、Bedrock モデルへのアクセスを有効にすることに関する場合(例:「Bedrock で Claude へのアクセスをリクエストするのを手伝って」「Bedrock で GPT モデルを有効にして」「どのモデルを有効にする必要がある?」「アクセスだけ希望しています。移行はエンジニアが行います」)。

曖昧な場合(コードベースとアクセスの両方に言及している場合)は、AskUserQuestion を使用します。

「お手伝いできることは 2 つあります。どちらをご希望ですか? [完全な移行] OpenAI/Gemini/Anthropic の呼び出しを、エンドツーエンドで Bedrock 向けに書き換えます。 [モデルアクセスのみ] コードを変更せずに、特定のモデルで Bedrock アクセスを有効にする方法を確認し、手順をご案内します。」

[モデルアクセスのみ] → アクセスのみのモードに進みます。[完全な移行] → 0b に進みます。

それ以外の場合(コードパスが指定されている、または書き換えの意図が明確な場合)→ 完全な移行のため、0b に進みます。

0b. gcp-to-aws または azure-to-aws の兄弟スキルがインストールされていることを確認する

以下のフェーズ A では、同じセッション内で $ASSESS_SKILL 自身のフェーズ指示ファイルを直接読み取り、実行することで(Discover → Clarify → Design → Estimate、AI のみのパス)、Assess を実行します。このスキルには、代わりに使用できる Assess のロジックはありません。gcp-to-aws と azure-to-aws は別々のスキルであり、このスキルに同梱されているわけではありません。単独のスキルをインストールしても(例:npx skills add ... --skill llm-to-bedrock)、どちらも自動的にはインストールされません。このデプロイでは実行できない Assess フェーズをユーザーに約束する前に、今すぐ確認してください。

if [ -f "<SKILL_BASE>/../gcp-to-aws/SKILL.md" ]; then
  ASSESS_SKILL=gcp-to-aws
elif [ -f "<SKILL_BASE>/../azure-to-aws/SKILL.md" ]; then
  ASSESS_SKILL=azure-to-aws
else
  echo ASSESS_SIBLING_MISSING
fi

$ASSESS_BASE = <SKILL_BASE>/../$ASSESS_SKILL。これにより、<SKILL_BASE>(上記で定義)を基準とした兄弟ディレクトリが確認されます。ネイティブプラグインのインストールでも npx skills add --skill '*' でも、gcp-to-aws/azure-to-aws はこのスキルのディレクトリの兄弟として配置されるため、どのインストールパスでも機能します。${CLAUDE_PLUGIN_ROOT} には依存しません。両方がインストールされている場合は、gcp-to-aws が優先されます。これは、このスキルの元となった、より深くテストされた統合であり、両方のスキルをインストールしている既存ユーザーに対する現在のデフォルト動作を維持できるためです。

  • $ASSESS_SKILL が解決された場合(どちらの値でも)→ ステップ 1 に進みます。

  • ASSESS_SIBLING_MISSING → ここで停止してください。先に進まないでください。 ユーザーに次のように伝えてください。

    "この移行には、このスキルと一緒に gcp-to-aws または azure-to-aws スキルをインストールする必要があります。このスキルはコードスキャン、AI ワークロードの検出、Bedrock モデルの設計を担当します。このスキルがないと、その部分を私自身で実行することはできません。どちらのスキルも、このスキルと同じ aws-startup-advisor プラグインに含まれているため、プラグイン全体をインストールしたのであれば、どちらか一方がすでに私の隣にあるはずです。プラグインのスキルの一部だけがインストールされたようです。次のコマンドで両方を一緒にインストールしてください。 npx skills add aws/agent-toolkit-for-aws/plugins/aws-startup-advisor/skills --skill llm-to-bedrock --skill gcp-to-aws (または、ソースインフラが Azure 上で稼働している場合は azure-to-aws に置き換えてください。このスキルで使用したものと同じ --agent および --global/プロジェクトのスコープを指定してください)。個別のスキル名の代わりに --skill '*' を指定して、同じ npx skills add コマンドを実行すれば、すべてのスキルを一度にインストールできます。その後、エージェントを再起動して、もう一度移行を依頼してください。"

    代替手段として Assess フェーズを自分で実行してはいけません。以下のフェーズ A で明示されているとおり、Assess のロジックは $ASSESS_SKILL にのみ存在します。ここで再実装すると、時間の経過とともに、そのスキルの Discover/Clarify/Design のロジックとのずれが生じます。このスキル単独の Assess はありません。この確認は代替動作を可能にするためではなく、問題を早期に明確に検出するためのものです。

フェーズ A は、スキルとして $ASSESS_SKILL を呼び出すのではなく、そのファイルをディスクから直接読み取ります。そのため、ここではエージェントに別途特別な機能は必要ありません。ファイルの読み取りと Bash の実行ができるエージェントであれば実行できます。(以前のバージョンのこのスキルでは、スキル間の Skill ツール呼び出しによって gcp-to-aws を呼び出していました。この仕組みは Claude Code 専用で、ほかの環境では未検証です。そのため、フェーズ A ではこの仕組みを使用しなくなりました。)


ステップ 1 — ソースコードのパスを収集する

$ARGUMENTS にパスが含まれている場合は、それを $REPO として使用します。それ以外の場合は AskUserQuestion を使用します: 「ソースコードの場所を教えてください。ローカルパスまたは GitHub URL を入力してください。」

GitHub URL の場合は、git clone で一時ディレクトリにクローンし、そのパスを $REPO として使用します。

$REPO の確認:

  1. Git ルートの確認(解決済みパスを比較します。macOS では /tmp が /private/tmp に解決されるため、 文字列をそのまま比較すると誤検出することがあります):

    [ "$(git -C <REPO> rev-parse --show-toplevel 2>/dev/null)" = "$(cd <REPO> && pwd -P)" ] && echo GIT_ROOT_OK || echo GIT_ROOT_MISMATCH
    
    • GIT_ROOT_OK → 続行します。
    • GIT_ROOT_MISMATCH かつコマンドがエラーになった場合(そもそも git リポジトリではない場合)→ 成果物は git ブランチであるため、パスには git リポジトリを指定する必要があることをユーザーに伝え、再度尋ねます。
    • GIT_ROOT_MISMATCH だがリポジトリ内の場合(ユーザーがサブディレクトリを指定した場合)→ AskUserQuestion: 「リポジトリのルートを使用する」(推奨)/「このサブディレクトリで続行する」/「中止」
  2. 未コミット変更の確認:

    git -C <REPO> status --porcelain
    

    未コミットの変更がある場合は、それらを表示して AskUserQuestion:「このまま続行する」または「先にクリーンアップする」

以降のすべてのステップで使用できるよう、$REPO を記録します。


ステップ 1.5 — 既存の利用プロファイルを確認する

Phase A を開始する前に、以前の Discover 実行(gcp-to-aws または azure-to-aws)で、このリポジトリに対する実際の OpenAI/OpenRouter/Anthropic 利用 API の支出がすでに記録されているか確認します。記録されている場合は、後でゴールデンデータセットからの 推定にフォールバックする代わりに、それをコストのベースラインとして再利用します。Phase A に入るたびに、独自の $MIGRATION_DIR の解決と再開ロジックは最初から開始されるため、このステップはそれを ショートサーキットする可能性を確保するため、必ずその前に実行する必要があります。

  1. このスキル自体の出力ディレクトリを除き、$REPO 配下のすべての .migration/<run-dir>/<provider>-usage-profile.json を Glob で検索します:

    for p in anthropic openai openrouter; do
      find "$REPO/.migration" -mindepth 2 -maxdepth 2 -name "${p}-usage-profile.json" \
        -not -path "*/.bedrock-*/*" 2>/dev/null
    done
    

    -mindepth 2 -maxdepth 2 は .migration/<run-dir>/<provider>-usage-profile.json に完全一致します。 -not -path "*/.bedrock-*/*" は llm-to-bedrock 自身の $BEDROCK_RUN_DIR (.migration/.bedrock-<id>/) を除外します — このディレクトリはこのスキル自身の出力であり、 gcp/azure の Discover の出力では決してありません。この glob はプロバイダー名に基づくもので スキル名に基づくものではありません — gcp-to-aws の Discover が書いたか azure-to-aws の Discover が書いたかに関係なくプロファイルを見つけます。どちらも同じ $REPO/.migration/ ツリー配下の同じファイル名規則に書き込むためです。

  2. 3 つすべてで一致がゼロ → 現在の動作に変更はありません。今日とまったく同じように フェーズ A に進みます。

  3. どの実行の成果物を使うかを決定する (決定的なタイブレーク、ソース実行のステータスを提示): 少なくとも 1 つ一致する各実行ディレクトリについて、そのディレクトリの .phase-status.json → last_updated (完全な ISO-8601 タイムスタンプであり、年を含みます) を読み取り、それを主ソートキーとして使用します — 最も大きい last_updated が優先されます。 ディレクトリ自身の <MMDD-HHMM> 名をそれ単体で時系列として扱わないでください: <MMDD-HHMM> の単純な辞書順比較が時系列になるのは単一の暦年内に限られます — 1231-1200 (12 月 31 日) は、客観的により後の年である FOLLOWING 年の 0102-1200 (1 月 2 日) よりも辞書順で後にソートされるため、名前だけを使うと古い実行を選んでしまう可能性があります。 候補の last_updated が欠落しているか解析不能な場合にのみ <MMDD-HHMM> ディレクトリ名に フォールバックし、そうする場合は明示的にその旨を伝えてください — このフォールバックは 同年内という前提に基づくものであり、一般的な時系列の保証ではなく、実際のタイムスタンプ比較と 同等であるかのようにユーザーに提示しては決してなりません。.phase-status.json → current_phase を、ユーザーに提示する (タイブレークには使用しない) 補足情報として使用します — たとえば、current_phase が Discover が Clarify を超えて進まなかったことを示す実行は、 その usage-profile ファイルが依然として最新であっても、放棄または辞退されたセッションであった 可能性が高いことをユーザーに伝えます。数値を採用する前に、両方の情報をユーザーに明示的に 伝えてください: 「既存の [provider] 使用プロファイルを <MMDD-HHMM> の実行 (ステータス: <current_phase>) から見つけました — それを使用します。」 実行ディレクトリの .phase-status.json が完全に欠落しているか解析不能な場合でも、<MMDD-HHMM> フォールバック経由で 候補として許可しますが、フェーズ名の代わりに status: unknown を提示してください。 真のタイまたは曖昧さ (2 つ以上の候補すべてに使用可能な last_updated がなく、それらには 同年内に限定された <MMDD-HHMM> フォールバックしか利用できない、またはそれらの last_updated 値がそれ以外の理由で曖昧である場合): 黙って推測しないでください — すべての曖昧な候補 (ディレクトリ名 + それぞれについて判明しているステータス) をユーザーに提示し、 どれを実際に使用すべきかを尋ねてください。自動的に 1 つを選ぶのではなく、上記の 「両方の情報をユーザーに明示的に伝える」パターンを再利用します。

  4. 勝者となった実行ディレクトリについて、そこに存在するすべての usage-profile ファイルを 読み取ります (1 回の実行が複数プロバイダーのプロファイルを同時に持つことができます — gcp が生成したプロファイルと azure が生成したプロファイルの混合を含みます — プロファイルの スキーマ自体は生成元に関係なく同一であるため、B1 はどのスキルがどのファイルを書いたかを 区別する必要はありません)。

  5. 各プロファイルについて: 最初に metadata.capture_warnings を確認します — 空でない場合は 一部のエンドポイントが失敗し、そのカテゴリのボリュームはゼロではなく UNKNOWN であることを 意味します。その注意事項をそのまま引き継いでください。

  6. 勝者となった実行内のすべてのプロファイルにわたって合計した summary.monthly_cost_usd を 計算します (max/1 つ選択ではなく、両方のスキル — gcp と azure の estimate-ai.md は同一の ルールを適用します — の estimate-ai.md に文書化された SUM の規律を再利用)、 usage_by_model[] を同じ正規化ルールで結合します (OpenRouter の prompt_tokens/completion_tokens → input_tokens/output_tokens; Anthropic の cache_read_tokens/cache_creation_tokens はボリューム合計に含めます — これらは Admin API が input_tokens とは別に報告する追加のトークンプールであり、その一部としての計上ではありません。 完全な uncached_input_tokens + cache_read_input_tokens + cache_creation_input_tokens の 契約については、いずれかの兄弟スキルの estimate-ai.md の「Prerequisites」セクションを 参照してください)。metadata.partial_window の例外を適用します: 部分ウィンドウのプロファイルの 数値は active_days でラベル付けされた参考値であり、月次のベースラインに混ぜ込まれることは 決してありません (スキーマ上の帰結は以下で規定)。第 2 の並行する例外 — metadata.cost_status (Anthropic プロファイルのみ。現在のところこのフィールドを書き込む唯一の プロファイル): cost_status が "cost_unavailable" のプロファイルは summary.monthly_cost_usd が null です — このドル SUM から完全に EXCLUDE します (null を加算せず、0 で置き換えもしない) が、その usage_by_model[] のトークン合計は 引き続き以下の usage_by_model[] に含めます — そのプロファイルでは使用状況は成功しており、 失敗したのはコスト側のみだからです。これは partial_window 例外と同じ形 (一方はドルのみを 除外し、他方もドルのみを除外する) を踏襲しますが、別個の独立した条件です — プロファイルは partial_window: false であっても cost_status: "cost_unavailable" になり得ます。 第 3 の例外 — OpenRouter の BYOK/重複の重複排除: 勝者となった実行ディレクトリに openrouter-usage-profile.json と直接プロバイダーのプロファイル (anthropic-usage-profile.json または openai-usage-profile.json) の両方が存在し、 かつ OpenRouter プロファイルの metadata.cost_provenance が "byok_passthrough" または "mixed" である場合、重複するモデルについて両方のプロファイルのドル数値を合計しないでください — そうしないと同じ基盤となるプロバイダー支出が二重に計上されます (1 回は直接プロバイダー自身の 使用状況 API 経由、もう 1 回は同じトラフィックをルーティングする OpenRouter 経由)。 重複するモデルについては直接プロバイダー自身の数値をグラウンドトゥルースとして優先し、 OpenRouter プロファイルの対応する usage_by_model[] のドルエントリはその重複分については ルーターフィーのみとして扱います (この SUM から除外します)。cost_provenance が "unknown" の場合 (このフローが現在書き込む唯一の値 — discover-openrouter-api.md 自身に 文書化された検出の制限を参照)、重複を自動的に解決するための信頼できるシグナルはありません: 2 つのプロファイル間でモデルを照合します — OpenRouter の usage_by_model[].model は provider/model-name 形式 (例: "openai/gpt-4.1") を使用します。直接プロファイルのベアな モデル名 (例: "claude-sonnet-5") が OpenRouter のモデル名の最後の / より後の部分文字列と 等しい場合、そのモデルは「同じ」です。OpenRouter の usage_by_model[] の行のうち、そのモデルが 直接プロファイルに存在するモデルと一致するものすべてについて、その行のドルとトークンの数値を この SUM から完全に EXCLUDE します (ドルだけではありません — 直接プロファイルがすでにその トラフィックのトークンを計上しているため、OpenRouter の数値も含めると両方が二重計上されます)。 OpenRouter のみのモデル (直接プロファイルに一致がないもの) はすべて従来どおり合計に含めます。 除外をユーザーに提示するサマリーで「OpenRouter と <provider> の使用プロファイルが両方存在します。 BYOK トラフィックの二重計上を避けるため、重複する N 個のモデルを OpenRouter の合計から除外しました — provenance が unknown であるため、この除外はそれらのモデルについて完全な重複を前提としており、 OpenRouter がそれらを部分的にしか BYOK ルーティングしていない場合は過小計上になる可能性があります。」 としてフラグを立ててください。

  7. これらの計算済みの数値を保持してください — まだ書き込まないでください。 $BEDROCK_RUN_DIR は このドキュメントのこの時点では存在しません (これはフェーズ A の実行後、以下の 「### A3 — Assess 出力を特定し、次にこのスキル自身の実行状態を確立する」でのみ確立されます)。 ここで書き込むと、まだ割り当てられていないディレクトリ変数に書き込むことになります。 計算済みの source_run_dir、source_profiles、captured_at、capture_warnings、windows、 summary、usage_by_model[] の値をそのまま引き継ぎ (形は以下の「新しい成果物」で規定)、 ここで短いサマリーを提示します: 「既存の使用状況データが見つかりました: N 個のモデルにわたって 月額 $X (ソース: [プロバイダーのリスト]、取得日 <date>)。サンプリングされたゴールデン データセットのトラフィックから推定する代わりに、これを現在のコストのベースラインとして 使用します。」 実際のファイル書き込みは A3 で、$BEDROCK_RUN_DIR が設定された直後に行われます — そこの相互参照を参照してください。

  8. このステップは同意を求めるプロンプトを決して出しません — 以前にすでに同意された実行が すでに書き込んだファイルを読み取るだけです。新たな攻撃面はなく、新たな同意ゲートも不要です。

  9. 冪等性: このステップは、再開されたセッション (A2 の再開パス) を含め、フェーズ B の開始ごとに 再実行しても安全です。読み取り専用のファイル操作のみを行います — usage-baseline.json の実際の 書き込みは後で A3 で行われ (上記ステップ 7 参照)、その書き込み自体も冪等です — 同じ入力で再実行 すると usage-baseline.json を上書きして同じ出力が生成され、異なる入力 (例: 前回の実行以降に 新しいプロファイルが出現した) での再実行は正しく再解決して上書きします。したがって、すでに実行 された再開でこのステップを再実行しても無害です。何らかの「実行済み」チェックの背後にゲートされて いません。

新しいアーティファクト: $BEDROCK_RUN_DIR/usage-baseline.json

以下に示す「### A3 — Locate Assess の出力を確認し、続いてこのスキルの独自の実行状態を確立する」において、$BEDROCK_RUN_DIR($REPO/.migration/.bedrock-<id>/)に書き込まれます。これは $BEDROCK_RUN_DIR が設定された直後であり、ステップ 1.5 自体ではありません。というのも、ステップ 1.5 の実行時点では $BEDROCK_RUN_DIR がまだ存在しないためです(ステップ 1.5 の上記ステップ 1〜6 は、フェーズ A より前に依然としてここで実行されるため、フェーズ A1 自身の新規 Discover フォールバック判定が正しくショートサーキットできます。先送りされるのはファイルの WRITE のみです)。これにより、フェーズ C のレポートジェネレーターは、.migration/*/ 自体を再グロブすることなく(そのグロブはこのステップにのみ属します)、安定した、すでに解決済みの読み取り先を得られます。

スキーマ(プロバイダーごとのウィンドウステータスマップ。これにより、partial/full の混在した組み合わせを表現できます):

{
  "source_run_dir": ".migration/0315-1030",
  "source_profiles": ["anthropic-usage-profile.json", "openai-usage-profile.json"],
  "captured_at": "<ISO 8601, max across source profiles>",
  "capture_warnings": [],
  "windows": {
    "anthropic": { "window_days": 30, "active_days": 12, "partial_window": true, "cost_status": "partial_window" },
    "openai": { "window_days": 30, "active_days": 30, "partial_window": false, "cost_status": "complete" }
  },
  "summary": {
    "monthly_cost_usd": 0.0,
    "monthly_cost_usd_is_blended_estimate": true,
    "currency": "USD",
    "models_seen": 0
  },
  "usage_by_model": [
    {
      "model": "string",
      "provider": "openai|anthropic|openrouter",
      "partial_window": true,
      "input_tokens": 0,
      "output_tokens": 0,
      "num_model_requests": 0
    }
  ]
}

検証ルール:

  • source_profiles は空ではありません(このステップで少なくとも 1 つのプロファイルが見つかった場合にのみファイルが書き込まれます。空の配列ではなく、ファイルの不在が「既存のプロファイルが見つからなかった」ことを示します)。
  • windows は、usage_by_model[] に寄与するすべてのプロバイダーをキーとします。windows に存在しないプロバイダーは、usage_by_model[] にも現れてはなりません。
  • usage_by_model[].provider はソースを明確化します。usage_by_model[].partial_window は、その行のプロバイダーの windows.<provider>.partial_window の直接コピーです。これは(プロバイダーごとのみではなく)行ごとに保持されるため、windows を相互参照せずに usage_by_model[] のみを読むコンシューマーでも、どの行が参照専用であるかを判別できます。
  • summary.monthly_cost_usd_is_blended_estimate: windows に partial_window: true のプロバイダーが 1 つでも含まれる場合は常に true になります。true の場合、コンシューマー(llm2bedrock-report-generator.md §6)は monthly_cost_usd を、ラベル付けされた参考値として(partial プロバイダーの active_days を表示した上で)提示しなければならず、無条件の月次ベースラインとして提示してはなりません。寄与するすべてのプロバイダーが full-window の場合、このフラグは false となり、monthly_cost_usd は通常のブレンドされた月次ベースラインとなります。これは、summary を 2 つの別個のトップレベル数値に分割することなく、上記ステップ 6 の規律を満たします。単一の monthly_cost_usd 数値はステップ 6 が計算する SUM のままであり、このブール値がコンシューマーにその提示方法を伝えます。
  • windows.<provider>.cost_status: "complete" | "partial_window" | "cost_unavailable" で、そのプロバイダーのソース使用プロファイルの metadata.cost_status からそのままコピーされます(現在このフィールドを書き込むのは Anthropic 使用プロファイルのみです。どちらの兄弟スキルでも discover-anthropic-api.md のステップ 3 を参照してください。まだこれを書き込まない OpenAI/OpenRouter プロファイルでは、partial_window が false の場合は "complete" に、true の場合は "partial_window" にデフォルト設定されます。これらのプロバイダーでは、ウィンドウの完全性とコストの完全性がまだ分離されていないためです)。いずれかの windows.<provider>.cost_status が "cost_unavailable" の場合、そのプロバイダーのドル額は上記ステップ 6 で summary.monthly_cost_usd からすでに除外されています。トークン量から示唆されるよりも低いドル合計を説明するために windows を読むコンシューマーは、ソースプロファイルファイルを再度開くことなく、プロバイダーごとにここでその理由を見つけられます。
  • source_run_dir のパス解決について、明示的に記述: source_run_dir は POSIX であり、$REPO からの相対パスです(すべてのサブエージェントのコンテキストブロックに Repository: 行として渡される同じ $REPO)。絶対パスにはならず、また $BEDROCK_RUN_DIR からの相対パスにもなりません。これにより、アーティファクトはクローン/移動されたリポジトリ間でポータブルに保たれます。書き込み側(上記ステップ 7。採用された実行ディレクトリの find が生成した絶対パスから $REPO/ プレフィックスをここに書き込む前に取り除かなければなりません)と読み取り側(llm2bedrock-report-generator.md §6)はいずれも同じように解決します。つまり、usage-baseline.json 自身のすでに合計された数値を信用するのではなく、ソースプロファイルファイルを直接再度開く必要がある場合、$REPO + source_run_dir を結合して絶対パスを取得します。
既存のプロファイルがない場合の単独実行

このステップで一致するものが見つからなかった場合は、Phase A で実行する $ASSESS_BASE 自身の discover.md のインライン実行に全面的に依存してください(この実行で Step 0b が $ASSESS_SKILL として解決した gcp-to-aws または azure-to-aws のいずれか)。このファイルでは、独自の同意/トリガーロジックを通じて、OpenAI/OpenRouter/Anthropic の利用状況をすでに調査できます。gcp-to-aws では現在、Step 1e~1g でこれを実施しており、azure-to-aws にも同じ機能があります。ここで「ライブ調査を提案する」新たなエントリーポイントは設計しません。このステップで再実装すると、約400行に及ぶセキュリティ契約の取得ロジックと提案/同意のフローを3回目、4回目、5回目と重複して実装することになり(クラウドごとに1回)、呼び出し元の間で内容にずれが生じるおそれがあります。代わりに、Phase A の説明ではすでに $ASSESS_BASE/references/phases/discover/discover.md をパスで指定し、全体を実行するよう読者に指示しています。これはすでに実装済みの「パスで参照し、再実装しない」という仕組みで、両方のクラウドに対応しています。

調整点が1つあります。Phase A のインライン Discover で、新しい $MIGRATION_DIR に新しいプロファイルを取得した場合は、Phase A の Discover サブステップの最後に、その実行固有のディレクトリに対して上記のステップ4~7を再実行し、得られた数値を同様に保持してください(ここでもステップ7の書き込み延期の規律が適用されます。A3 はまだ実行されていないため、この時点では $BEDROCK_RUN_DIR は存在しません)。これにより、プロファイルがこのステップでの再利用によるものか、Phase A での新規取得によるものか、またどちらのクラウドの Assess スキルが生成したものかにかかわらず、Phase C は常に一貫した場所から読み取れます。

追加機能、任意 — 既存のフローへの影響なし: usage-baseline.json が存在しない場合、動作に変更はありません。既存の動作差分比較と、golden-dataset-sample から外挿したコスト表(llm2bedrock-report-generator.md §6.3)は、これまでどおり実行されます。


Phase A — Assess(インラインで $ASSESS_SKILL 独自の AI パスファイルを実行)

ソースコードを読んだり、AI SDK を検出したり、最初から自分で Clarify の質問をしたりしないでください。 このフェーズでは、ディスク上にある $ASSESS_SKILL 独自のフェーズ指示ファイルを読み、$ASSESS_SKILL を単独で実行する場合とまったく同じように、その指示に正確に従います。同じ内容、同じ状態ファイル、同じ成果物を使用します。$ASSESS_SKILL を別個のスキルとして呼び出す場合との違いは、ツール呼び出しもターン境界もないことだけです。以下のすべてを、このセッション内でインライン実行します。上記の Step 1.5 では、既存の利用状況 API プロファイル(gcp-to-aws または azure-to-aws の Discover で取得したもの)がないか確認し、見つかった場合は Bedrock のコストベースラインとなる数値を計算済みです。これらの数値は、後述の「### A3 — Assess の出力を特定し、このスキル独自の実行状態を確立する」で $BEDROCK_RUN_DIR が作成された後、$BEDROCK_RUN_DIR/usage-baseline.json に書き込むまでメモリ内に保持されます。以下の Phase A は、いずれの場合も最後まで実行します。既存のプロファイルが見つからなかった場合に限り、Discover 独自の新しい利用状況 API の取得、または golden-dataset 外挿にフォールバックします。

パスの解決。 $ASSESS_SKILL の指示ファイルでは、相対参照(references/phases/...、references/shared/...、references/vendored/...、references/design-refs/...、shared/...、design-refs/...、phases/...、data/...。短縮形を含む)が使用されています。すべての参照を、記述されている接頭辞をそのまま使って $ASSESS_BASE(上記で定義)配下に解決します。たとえば、shared/pricing-cache.md は $ASSESS_BASE/references/shared/pricing-cache.md に解決します。$MIGRATION_DIR だけは $ASSESS_BASE 配下に解決しないパスであり、A1 に記載の $ASSESS_SKILL 独自の規則に従い、$REPO 配下に置きます。ここで $ASSESS_SKILL のファイルは読み取り専用です。このフェーズでファイルを編集することはありません。

A1 — Discover、Clarify、Design、Estimate を実行する

開始前に、ユーザーに次のように伝えます。

「これから Discover → Clarify → Design → Estimate の評価($ASSESS_SKILL を単独で実行する場合と同じロジック)を実行して、AI ワークロードを検出し、Bedrock への移行を設計します。いくつか質問しますので、ご回答ください。」

その後、順番に次を実行します。

  1. $MIGRATION_DIR を解決します。 $ASSESS_BASE/references/phases/discover/discover.md のステップ 0 の説明どおり、$REPO に既存の .migration/ ディレクトリがあるか確認します(既存の実行があれば一覧表示し、「再開/新規/キャンセル」を提示します。なければ、現在のタイムスタンプを使って $REPO/.migration/<MMDD-HHMM>/ を作成し、$MIGRATION_DIR に設定します)。 .phase-status.json がまだないディレクトリは、存在していても既存の実行ではありません。新規として扱い、discover.md の「再開/新規/キャンセル」のプロンプトはスキップしてください(これは、独自のインライン gcp-to-aws 委譲について agent-advisor の migration-plan.md フェーズ A に記載されているのと同じ例外です)。llm-to-bedrock はこのステップの前に $MIGRATION_DIR を作成しないため、ここで注意が必要です。ただし、このステップでディレクトリを作成した後、discover.md のステップ 0 が .phase-status.json を書き込む前に実行が中断されると、後で再開するときにディレクトリだけが残ります。その場合、discover.md の「再開」分岐では存在しない .phase-status.json を読み込もうとしてしまいます。

  2. $ASSESS_BASE/references/phases/discover/discover.md を最初から最後まで読み、記載どおりに実行します。独自のステップ 0 の状態ファイル初期化(再開時はスキップします。$MIGRATION_DIR にはすでに .phase-status.json があります)と、ステップ 1 のサブディスカバリーのゲート(1a~1e)も含みます。これらのゲートは $REPO に実際に存在するものを基準にしており、Terraform ファイルがある場合にのみ IaC ディスカバリーを実行し、請求書データのエクスポートがある場合にのみ請求ディスカバリーを実行する、といった動作をすでに行います。そのため、誘導する必要はありません。discover.md 独自の使用量 API の同意/取得アクションでは、該当する場合に対応する Admin API の使用量ディスカバリーが提示されます(OpenAI、OpenRouter、および azure-to-aws の場合は Anthropic)。いずれかを承諾すると、手動でエクスポートしなくても、Estimate で実際の支出額とトークン量を確認できます。(Anthropic の Admin キーには選択可能なスコープがなく、すべて許可するか、何も許可しないかのどちらかです。以前の文にあった「Usage を Read に設定」という表現は、OpenAI 独自のキーについても、より限定的な意味で誤っていました。この一般化された文に引き継がないでください。これは、元の箇所で修正された、隣接する既存の不正確な記述として記録してください。)

    Discover のステップ 0 で実行の .phase-status.json を書き込む際、owning_skill の隣に "initiated_by": "LLM_TO_BEDROCK" を記録する必要があります。owning_skill には、実際に実行された GCP_TO_AWS/AZURE_TO_AWS(つまり、$ASSESS_SKILL 独自の識別子)を設定します。これは、別のスキルによって開始された実行に関する discover.md 独自の指示に従ったものです。この実行は llm-to-bedrock によって開始されており、テレメトリーはこの値を使ってその開始元を特定します。 HANDOFF_OK の場合: ai-workload-profile.json、gcp-resource-inventory.json / azure-resource-inventory.json、または billing-profile.json の少なくとも 1 つが $MIGRATION_DIR に存在します。

  3. 読み込んで実行 $ASSESS_BASE/references/phases/clarify/clarify.md を完全に実行します。これは 自身でルーティングします — ai-workload-profile.json が唯一のディスカバリー成果物である場合、clarify-ai-only.md を読み込み、そのスタンドアロンのフローを実行します。インフラ成果物も存在する場合は、代わりにフラグメント/アセンブラ分割を実行します。いずれの場合も、読み込まれた内容に正確に従ってください。 HANDOFF_OK の場合: preferences.json が $MIGRATION_DIR に存在します。

  4. 読み込んで実行 $ASSESS_BASE/references/phases/design/design.md を完全に実行します。これは ai-workload-profile.json が存在する場合に design-ai.md へルーティングします — これがこのスキルの 実行フェーズが依存するファイルです。HANDOFF_OK の場合: aws-design-ai.json が $MIGRATION_DIR に存在します (さらに、インフラまたは 請求のルートも実行された場合は aws-design.json/aws-design-billing.json も存在します)。

  5. 読み込んで実行 $ASSESS_BASE/references/phases/estimate/estimate.md を完全に実行します。Estimate を 超えて続行する必要はありません — このスキルは Assess 成果物 (aws-design-ai.json、ai-workload-profile.json、preferences.json) のみを必要とするため、 estimate.md が Estimate 後の意思決定ゲートに到達したら、インフラを生成しないことを選択する (または単に意思決定パックで停止する) だけで十分です。generate.md が生成するもの (Terraform、MIGRATION_GUIDE.md、migration-report.html) は一切読み込みません。

上記の各ファイルは、それぞれ独自のプロトコルに従って $MIGRATION_DIR/.phase-status.json を 自身で管理します — 上記のステップ 2 で示した initiated_by フィールドを除き、そのファイルに 自分で書き込まないでください。いずれかのファイルの独自の _postconditions/ハンドオフチェックが 失敗した場合 (GATE_FAIL)、停止して、そのファイルが報告した内容を正確にユーザーに示してください。 ゲートを通過させるために成果物にパッチを当てないでください。

A2 — Assess が完了していることを確認する

上記のフェーズ A は Estimate までのすべてのステップをインラインで実行したため (別々の 呼び出しにまたがるのではなく)、A1 のステップ 5 が GATE_FAIL なしで終了すれば Assess は完了です。この チェックは、セッションが A1 の途中で中断された場合 (例: ユーザーが Clarify の途中で停止し、後で再開する場合) のバックストップとして存在します — $MIGRATION_DIR/.phase-status.json を 再読み込みし、phases 内でまだ "completed" になっていないステップで A1 を再開してください。 Discover から再開するのではなく。

その再読み込みを信頼する前に、$ASSESS_BASE/SKILL.md § State Validation を適用してください (これは A1 自身のフェーズファイルがこの状態を読むときに依存するのと同じ契約であり、このラッパーレベルの バックストップ再読み込みもより緩い基準で扱われるべきではありません)。特に: .phase-status.json がパースに失敗した場合 (中断された書き込みにより無効になった — 例: セッションが フェーズの途中ではなく書き込みの途中で中断された)、§ State Validation チェック 2 の再構築 手順が、これを復旧する唯一の認められた方法です — $MIGRATION_DIR に実際に存在する 成果物から完了したフェーズを推測し、推測されたステータスを確認のためにユーザーに提示し、 その確認があった場合にのみ .phase-status.json を書き換えます。これは A1 の「そのファイルに 自分で書き込まないでください」というルールに対する、狭く明示的な例外です: この契約に基づく .phase-status.json の復旧は、フェーズファイル自身の状態管理と同じ行為ではなく、 これを行わずに進めると、このラッパーが委任するすべてのフェーズファイルとは異なり、検証していない状態で再開することになります。

ワークショップガード: phases.workshop == "in_progress" の場合、design.md の内部ワークショップパス が活発に再価格設定しています (workshop-refresh.md が古いマッピングと新しいマッピングの間で aws-design-ai.json を書き換えています) — Design を完了として扱う前に、そのループを 終了してください (終了または辞退時に phases.workshop を "completed" に戻します)。

A3 — Assess の出力を特定し、このスキル自身の実行状態を確立する

すでに解決して確認済みの同じ $MIGRATION_DIR を A1/A2 で使用してください。ここでディレクトリを再選択しないでください。 $MIGRATION_DIR は A1 のステップ 1 ですでに設定されており(セッション再開時には A2 の再読み込みで再確認され、置き換えられていません)、この時点で「最新のディレクトリ」を検索し直すと(ls -td "$REPO/.migration"/*/ | head -1)、A2 が完了を確認した実行より新しい、別の実行が選択される可能性があります。たとえば、Design がまだ進行中の兄弟実行が該当します。その場合、B1 はこのフェーズで実際に評価した実行ではなく、その兄弟実行の未完了のモデルマップを読み込んでしまいますが、エラーは発生しません(新しいディレクトリには、別の未完了の評価から作成された、以下の 3 ファイルがすべて含まれている場合もあります)。ここで $MIGRATION_DIR が何らかの理由で未設定の場合(上記の A1/A2 を考えると、未設定であってはなりません)、これはこのフェーズ自体の状態追跡のバグです。ls -td からディレクトリを推測せず、停止して報告してください。

$MIGRATION_DIR に次の 3 ファイルがすべて存在することを確認してください(Phase B ではすべてのファイルを読み込みます)。

  • aws-design-ai.json(モデルマッピングとアーキテクチャ)
  • ai-workload-profile.json(検出されたワークロード)
  • preferences.json(Clarify で取得したユーザー設定)

3 ファイルのうち 1 つでも欠けている場合、Assess で AI パスが正しく完了していません。欠けているファイル名とエラーを示して停止してください。GATE_FAIL なしで A1 が完了していれば、これらのファイルが存在するはずです。このステップは、Execute が読み込む前に確認するための最終チェックです。

このスキル独自の実行状態を確立します(読み取り・マージ・書き込み)。このスキルは委任された実行の状態とは別に、独自の軽量な実行状態ファイルを保持します。これにより、AI 移行が使用状況ファネルに独自の名前で表示されます。このスキルは独自の状態スキーマ(フェーズは assess、execute)を宣言します。共有 DSL の読み取り・マージ・書き込みルールが適用されます。ここでは委任された実行の .phase-status.json に手を加えないでください。この呼び出しで作成された実行にはすでに initiated_by(A1)が含まれており、以前の実行のファイルを書き換えると、テレメトリーフックに新しい作業のような履歴が表示されてしまいます。

  1. $BEDROCK_RUN_DIR を $REPO/.migration/.bedrock-<id>/ に設定します。<id> は $MIGRATION_DIR のベース名です(例:.migration/.bedrock-0910-1100/)。先頭にドットがあるため、上記の ls -td "$REPO/.migration"/*/ の検索対象にならず、Assess の実行ディレクトリと誤認されることはありません。委任された実行をキーにすることで、移行を再開した際に同じディレクトリが再利用されます。ステップ 1.5(または Phase A 自身による新規 Discover の取得)で既存の usage-API プロファイルが見つかった場合、$BEDROCK_RUN_DIR には usage-baseline.json も格納されます。このファイルは、このディレクトリが存在するようになった後、以下のステップ 2 で書き込まれます(スキーマについては上記のステップ 1.5 の「New artifact」セクションを参照してください)。

    • $BEDROCK_RUN_DIR/.phase-status.json がすでに存在する場合、この移行は再開中です。run_id を含めてファイルをそのまま保持し、続行してください。

    • それ以外の場合は、ディレクトリを作成し、.phase-status.json を書き込みます。

      {
        "migration_id": ".bedrock-<id>",
        "last_updated": "<ISO 8601 now>",
        "current_phase": "execute",
        "run_id": "<fresh UUID from uuidgen>",
        "owning_skill": "LLM_TO_BEDROCK",
        "phases": { "assess": "completed", "execute": "in_progress" }
      }
      

    assess/execute フェーズ名は、まだテレメトリー API モデルに含まれていないため、この実行についてマシンの外部に送信されるのは実行レベルのイベント(RUN_STARTED、RUN_COMPLETED)のみです。AI ジャーニーのエントリーポイントは、initiatingSkill を含む委任された実行のイベントですでに確認できます。

  2. $BEDROCK_RUN_DIR が存在するようになったので、usage-baseline.json を書き込みます。 Step 1.5 のステップ 7 で計算済みの数値を保持していた場合(または、Step 1.5 の「単独実行」注記に従って Phase A 独自の Discover キャプチャを行い、その数値を保持していた場合)、Step 1.5 の上記「新しいアーティファクト」セクションにあるスキーマを使って、今すぐ $BEDROCK_RUN_DIR/usage-baseline.json に書き込みます。数値を保持していなかった場合(Step 1.5 で一致が 0 件で、Phase A の Discover でも新しいプロファイルがなかった場合)は、この書き込みを完全にスキップします。usage-baseline.json が存在しないこと自体が、llm2bedrock-report-generator.md §6.3 が確認する「ベースラインなし」のシグナルです。

  3. Bedrock の実行を作成または検証した後、references/vendored/telemetry/PROTOCOL.md に従い、cli 報告モードで照合します。 hook モードでは、報告をホストフックに任せます。


Phase B — 準備の実行

B1 — Assess の出力を読み込む

$MIGRATION_DIR/aws-design-ai.json を読み込み、以下を抽出します。

  • ai_architecture.bedrock_models[] → {source_model, aws_model_id, use_case} の配列
  • すべての aws_model_id の値を $TARGET_MODELS(配列)に収集します。それぞれの use_case も保持してください。 プリフライトスクリプトは各モデルを適切な API で自動的にプローブします(チャットには Converse、埋め込みには InvokeModel)。ただし、評価器による品質スコアリングはチャットモデルにのみ適用されます。埋め込みのターゲットには、形式と次元の検証のみが行われます。

$MIGRATION_DIR/ai-workload-profile.json を読み込み、以下を抽出します。

  • summary.ai_source → ソースプロバイダー

$MIGRATION_DIR/preferences.json を読み込み、以下を抽出します。

  • design_constraints.target_region → $REGION(指定がない場合はデフォルトの us-east-1)

検証: aws-design-ai.json に ai_architecture.bedrock_models[] 配列がない場合、または配列が空の場合は、停止します。「Assess の出力が不完全です — モデルのマッピングがありません。」

B2 — AWS アイデンティティの確認
aws sts get-caller-identity 2>&1

コマンドが失敗した場合(認証情報がない、SSO トークンの有効期限切れなど)は、エラーを表示し、aws configure または aws sso login の実行をユーザーに案内します(このセッションで実行するには ! aws sso login と入力するよう提案します)。その後、B2 を再実行します。アイデンティティを確認できるまでは先に進まないでください。

成功した場合は、AskUserQuestion を使って Account、Arn、UserId を表示します。 「この AWS アイデンティティを Bedrock の呼び出しに使用します。よろしいですか?」

選択肢:

  • はい、このアイデンティティを使用する → 続行
  • 別の AWS プロファイルを使用する → 使用するプロファイルを尋ね、$AWS_PROFILE_CHOICE として記録し、aws sts get-caller-identity --profile $AWS_PROFILE_CHOICE で B2 を再実行して、再度確認します。 AWS_PROFILE のエクスポートには依存しないでください — 環境変数は Bash ツール呼び出し間やワークフローのサブエージェントには引き継がれません(B3 を参照)。代わりに、選択したプロファイルをすべての箇所で明示的に渡してください。すべての AWS CLI 呼び出しで --profile を指定し、B4 のプリフライトコマンドでは先頭に AWS_PROFILE=$AWS_PROFILE_CHOICE をインラインで付け、ワークフローの引数では awsProfile フィールド内に指定して、サブエージェントも同様に実行できるようにします。

リージョンも確認します。「Bedrock のリージョンは $REGION です。よろしいですか?変更しますか?」

B3 — ソース API キー(任意)

まず、アーティファクトディレクトリを作成し、直ちにそのディレクトリを Git の追跡対象から除外してください。キーが存在する前に実行することで、リライターが実行される前にユーザーが中断した場合でも、秘密情報が追跡対象の作業ツリーに置かれることはありません。

mkdir -p "$REPO/.saws-migrate" && printf '*\n' > "$REPO/.saws-migrate/.gitignore"

B1 のソースプロバイダーに基づいて $KEY_ENV_VAR を決定します(ベースラインスキルのパーサーが想定する環境変数名です。NAME= のプレフィックスがないキーだけでは解析されません)。

  • openai → OPENAI_API_KEY
  • anthropic → ANTHROPIC_API_KEY
  • google / gemini → GEMINI_API_KEY

キーをこの会話に入力してはいけません(絶対厳守)。 チャットにキーを貼り付けるようユーザーに求めないでください。また、その値をコマンド、質問、出力に表示、cat、展開してはいけません。エージェントが扱うのはファイルパスだけです。ユーザーが求められていないのにチャットへキーを貼り付けた場合は、使用せず、そのキーが会話の記録に残ったことを伝え、キーのローテーションを勧めてから、以下のいずれかの方法で続行してください。

まず、キーがすでにシェル環境に存在するかを確認します(Bash を呼び出すたびにユーザーのプロファイルが読み込まれるため、プロファイルでエクスポートされたキーはすべての呼び出しから参照できます)。 POSIX 互換です。printenv は bash と zsh のどちらでも動作します(${!VAR} による間接参照は bash 専用で、zsh ではエラーになります)。次のコマンドはキーの有無だけを出力し、値は出力しません。

[ -n "$(printenv "$KEY_ENV_VAR")" ] && echo ENV_KEY_PRESENT || echo ENV_KEY_ABSENT

AskUserQuestion: 「ソースモデル用の API キー(例:GPT-4o 用の OpenAI キー)をお持ちですか? キーを提供すると、品質を横並びで比較できます。提供しない場合、評価は絶対評価のみになります。」

選択肢(ENV_KEY_PRESENT の場合に限り、最初の選択肢を提示します):

  • 環境にすでに設定されている $KEY_ENV_VAR を使う → 1 つのコマンドで環境変数をファイルに書き出します。値が会話の記録に残ることはありません。

    printf '%s=%s\n' "$KEY_ENV_VAR" "$(printenv "$KEY_ENV_VAR")" > "$REPO/.saws-migrate/.source-provider-env" && chmod 600 "$REPO/.saws-migrate/.source-provider-env"
    

    次に、以下の形式チェックを実行し、sourceBaselineAvailable = true、sourceKeyRef = "$REPO/.saws-migrate/.source-provider-env" を設定します。

  • 自分でファイルに書き込む → ユーザー自身のターミナルで実行するコマンドを提示します(エージェント経由では実行しません。Claude Code では ! プレフィックスを付けるとセッション内で実行されます)。read -rs はキーをエコーせずに読み取ります。

    read -rs k && printf '%s=%s\n' "<KEY_ENV_VAR>" "$k" > "<REPO>/.saws-migrate/.source-provider-env" && chmod 600 "<REPO>/.saws-migrate/.source-provider-env" && unset k
    

    提示する際は、環境変数名とリポジトリパスを実際の値に置き換えてください(これらは秘密情報ではありません)。次に、以下の形式チェックを実行し、上記と同じフラグを設定します。

  • スキップ → sourceBaselineAvailable = false、sourceKeyRef = ""。

どの方法でファイルに書き込んだ場合も、形式を検証してください(キーは出力されません。NAME= のプレフィックスなしで値が書き込まれた場合に検出できます。この場合、ベースラインパーサーはそのキーを黙って見落とします)。

grep -qE '^(OPENAI|ANTHROPIC|GEMINI)_API_KEY=.+' "$REPO/.saws-migrate/.source-provider-env" && echo KEY_FORMAT_OK || echo KEY_FORMAT_BAD

KEY_FORMAT_BAD の場合は、ファイルを書き込んだ方法と同じ方法で、内容を表示せずにファイルを書き直してもらいます。

(.saws-migrate/ は上記の最初のコマンドですでに Git の追跡対象から除外されています。リライターも、二重の対策としてコミット前にこの設定を再確認します。)

重要: ファイルがキーの受け渡し手段です。後続の手順にキーを渡すために export に頼らないでください。ある Bash 呼び出しで設定したシェルの状態は、別の呼び出しやワークフローのサブエージェントには引き継がれません。確実に参照できるのはプロファイルでエクスポートされた変数(上記の ENV_KEY_PRESENT の方法)のみですが、その場合もベースラインランナー用にファイルへ書き出す必要があります。

B4 — Bedrock プリフライト
uv run --project $SCRIPTS python $SCRIPTS/preflight_bedrock.py --region $REGION --models <comma-separated $TARGET_MODELS> --dataset-size 200

(--dataset-size 200 はゴールデンデータセットの上限と一致するため、クォータ警告は最悪ケースを反映します。B2 でデフォルト以外のプロファイルを選択した場合は、先頭に AWS_PROFILE=$AWS_PROFILE_CHOICE を付けてください。)

JSON 出力を解析します。失敗時は、TOP LEVEL に reason/detail(最初に失敗したモデルから取り出されたもの)と failing_models(失敗したすべての ID)が含まれます。モデルごとの判定は models[] にあります。

  • ok == false + reason: credentials → detail を表示し(認証情報の設定/更新)、停止します。ユーザーは修正後に再実行します。
  • ok == false + reason: model_access → Bedrock コンソールでモデルアクセスが有効になっていません(IAM の問題ではありません)。失敗したモデルについて、ユーザーにコンソールの Model access ページを案内し、停止します。有効化後に B4 を再実行します。
  • ok == false + reason: authz → IAM が推論を拒否しています。Converse/InvokeModel ターゲットの場合は付与すべきアクションは bedrock:InvokeModel です。mantle 専用の openai.gpt-5* ターゲットの場合は bedrock-mantle:* のセットです(B4a を参照)。detail にどちらかが示されます。付与すべきアクションをユーザーに伝え、停止します。
  • ok == false + reason: mantle_deps_missing → 固定されたスクリプト環境に openai / aws-bedrock-token-generator がないため、mantle 専用ターゲットをまったくプローブできませんでした。これは環境の障害であり、Bedrock の判定ではありません。ユーザーに再同期(uv sync --project $SCRIPTS)を伝え、停止します。続行しないでください — アクセスは検証されていません。
  • ok == false + reason: model_unavailable → $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md にある resolve-bedrock-model-id リファレンスを読み、failing_models の各 ID + リージョンでその手順に従います。候補を提示して AskUserQuestion を実行します:「<candidate> を使用する(クロスリージョン推論プロファイル)」/「別のモデル ID を貼り付ける」/「中止する」。選択されたら、$TARGET_MODELS の ID を置き換えて B4 を再実行します。
  • ok == false + その他の reason → detail を表示して停止します。
  • ok == true → 続行します。quota_warning があれば提示し、また reason が embedding_unprobed であるモデル(プリフライトでプローブできない埋め込みファミリー — ユーザーにコンソールでモデルアクセスを確認するよう促してください)があれば提示します。

フェーズ C — 実行

フェーズ C は、Agent ツール(サブエージェントタイプ aws-startup-advisor:llm2bedrock-code-analyzer、aws-startup-advisor:llm2bedrock-log-ingestor、aws-startup-advisor:llm2bedrock-prompt-evaluator、aws-startup-advisor:llm2bedrock-code-rewriter、aws-startup-advisor:llm2bedrock-report-generator)を介して、5 つのプラグインエージェントを順番にディスパッチします。各エージェントは結果を $PHASE_DIR = $REPO/.saws-migrate/phase-results/ 配下のファイルに書き込みます。次に進む前に、同梱のバリデーターで各ファイルを検証します。ワークフローランタイムはありません — ファイルがそのまま状態です。

バリデーター(各ステップで使用)
uv run --project $SCRIPTS python $SCRIPTS/validate_result.py --schema <analysis|ingestion|eval|rewrite|delta-decisions> <file>
  • 終了コード 0 + RESULT=valid CONTROL=ok → フェーズ完了。続行します。
  • 終了コード 0 + CONTROL=blocked REASON=<r> → ブロックフロー(下記)。
  • 終了コード 0 + CONTROL=partial COMPLETED=<n> TOTAL=<m> → 部分フロー(eval のみ)。
  • 終了コード 1(RESULT=invalid + エラー行)または終了コード 2(ファイル欠落)→ ステートレス修正リトライ: 同じタイプの新しいエージェントをディスパッチします。そのプロンプトは、元のコンテキストブロック + ファイルパス + バリデーターのエラー出力そのまま + 指示「<path> にある出力ファイルのみを、検証に通るよう修正してください。必須フィールドが本当に欠けている場合を除き、フェーズの作業をやり直さないでください」です。フェーズごとに最大 2 回のリトライとし、その後は停止してエラーを表示します。
コンテキストブロック(各ディスパッチ時にインスタンス化)

エージェントがラベルを解析するため、以下の行形式を正確に使用します。空の場合は、任意の行を省略します。

Repository: <$REPO>
AWS region: <$REGION>
AWS profile (pass as --profile / AWS_PROFILE= inline on every aws/boto3 invocation): <$AWS_PROFILE_CHOICE — omit line if default>
Target Bedrock model(s): <comma-joined $TARGET_MODELS, with any resolved overrides already applied>
Migration plan dir: <$MIGRATION_DIR>
Resolved target model id: <override for the primary chat model — omit if none>
Scripts directory (pinned uv toolchain): <$SCRIPTS>
Report date suffix: <saved suffix from run-context — C5/C6 dispatches only>
Usage baseline path: <$BEDROCK_RUN_DIR/usage-baseline.json — C5/C6 dispatches only, omit line if the file is absent>
Source baseline available: <true|false>
Source provider env file: <path — omit if none>
User-supplied log files: <comma-joined — omit if none>
Golden dataset cap (max cases the ingestor may emit): 200
Phase results directory: <$PHASE_DIR>
Prior phase results (Read these files): <paths of already-validated phase JSONs>
Confirmed behavior-delta decisions file (Read it): <$PHASE_DIR/delta-decisions.json — C5 only>
<helper-reference lines — inject ONLY the ones this agent needs, per the table below>

前フェーズの結果はファイルパスとして渡します。JSON をプロンプトに直接含めないでください。

ヘルパー参照(以前のヘルパースキル。現在は $HELPERS 配下にあります)。 エージェントは名前でスキルを読み込まなくなりました。代わりに、挿入した絶対パスにあるヘルパー参照をエージェントが読み込みます。各ディスパッチでは、そのエージェントが使用するヘルパー行(# 4 セクションに記載)のみを追加します。

エージェント(ディスパッチ)追加するヘルパー参照行
C1 llm2bedrock-code-analyzerbehavior-delta-detection reference: $HELPERS/behavior-delta-detection/behavior-delta-detection.md; resolve-bedrock-model-id reference: $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md
C5 llm2bedrock-code-rewriterbedrock-known-fixes reference: $HELPERS/bedrock-known-fixes/bedrock-known-fixes.md; behavior-delta-detection reference: $HELPERS/behavior-delta-detection/behavior-delta-detection.md; dependency-conflict-resolution reference: $HELPERS/dependency-conflict-resolution/dependency-conflict-resolution.md
C3 llm2bedrock-prompt-evaluatorbedrock-known-fixes reference: $HELPERS/bedrock-known-fixes/bedrock-known-fixes.md; resolve-bedrock-model-id reference: $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md; run-source-model-baseline reference: $HELPERS/run-source-model-baseline/run-source-model-baseline.md
C2 llm2bedrock-log-ingestor、C6 llm2bedrock-report-generator(なし — これらのエージェントはヘルパーを読み込みません)

$HELPERS を絶対パス(<SKILL_BASE> があります)に展開し、${CLAUDE_PLUGIN_ROOT} が空のサブエージェントでも解決できる絶対パスを受け取れるようにします。

C0 — 実行コンテキストゲート(再開時の安全性)

Eval フェーズでは、ゴールデンケースごとに Bedrock の有料呼び出しが 1 回発生します(ソースキーがある場合は、ケースごとにソースプロバイダーへの有料呼び出しも 1 回発生します)。ディスパッチの前に、評価でユーザー負担の Bedrock 呼び出しが発生し、上限は 200 ケースであることをユーザーに伝えてください。

  1. mkdir -p $PHASE_DIR を実行します。次のフィールドのみを含む $PHASE_DIR/current-context.json を作成します(ハッシュには shasum -a 256 を使用します。キーのハッシュはフィンガープリントであり、キーの値は決して保存しません)。
{
  "repo_root": "<cd $REPO && pwd -P>",
  "migration_dir": "<$MIGRATION_DIR>",
  "region": "<$REGION>",
  "aws_profile": "<$AWS_PROFILE_CHOICE or \"\">",
  "aws_account": "<Account from B2>",
  "repo_head_sha": "<git -C $REPO rev-parse HEAD>",
  "repo_branch": "<git -C $REPO rev-parse --abbrev-ref HEAD>",
  "repo_dirty_sha256": "<sha256 of: git status --porcelain + git diff + git diff --cached, EACH with pathspecs -- . ':(exclude).saws-migrate' ':(exclude).migration' ':(exclude)MIGRATION_REPORT_*.md'; \"\" when all three are empty>",
  "target_models": [{"source_model": "...", "aws_model_id": "...", "use_case": "..."}],
  "resolved_model_overrides": {},
  "source_provider": "<from B1>",
  "source_baseline_available": <true|false from B3>,
  "source_key_sha256": "<sha256 of .source-provider-env contents, \"\" when absent>",
  "usage_baseline_sha256": "<sha256 of $BEDROCK_RUN_DIR/usage-baseline.json contents, \"\" when absent>",
  "log_files": [{"path": "...", "sha256": "..."}],
  "max_golden_cases": 200,
  "assess_design_sha256": "<sha256 of $MIGRATION_DIR/aws-design-ai.json>",
  "report_date_suffix": "<date +%Y-%m-%d>",
  "schema_version": 1,
  "plugin_version": "<version from <plugin>/.claude-plugin/plugin.json>"
}
  1. ステージ 0(C5 後の正規化)。 $PHASE_DIR/rewrite.json が存在し、ペイロードとして検証される場合(CONTROL=ok)、ライブの repo_* 値は使用しないでください。次の 3 つの整合性チェックを実行します:(1)rewrite.baseline_parent_sha が保存済みの repo_head_sha と一致すること。(2)git rev-parse <rewrite.branch_name> が rewrite.branch_tip_sha と一致すること。(3)git status --porcelain(アーティファクトの除外を適用)が空であること。すべて合格した場合 → 保存済みの repo_* 値をそのまま現在のコンテキストにコピーし、ステップ 3 に進みます。チェック 2 が失敗した場合(tip が移動)→ 停止して AskUserQuestion:「コミットを維持する(混在した作成者に関する注記を付けてレポートのみを再生成)」/「ブランチをリライターの tip にリセットし、C6 から再生成する」/「中止」。チェック 3 が失敗した場合(作業ツリーが dirty)→ 停止して、コミット/stash(その後、再チェック)するか、編集内容を破棄するよう求めます。チェック 1 が失敗した場合 → ステップ 3 で repo_* 全体の不一致として扱います。

  2. $PHASE_DIR/run-context.json が存在する場合、次を比較します:

uv run --project $SCRIPTS python $SCRIPTS/validate_result.py --check-run-context $PHASE_DIR/run-context.json --current $PHASE_DIR/current-context.json
  • RUN_CONTEXT=match → 再開:C1→C2→C3→(C4:delta-decisions.json)→C5→(C6:レポートファイル)の順に進みます。フェーズが完了とみなされるのは、そのファイルが CONTROL=ok で検証された場合に限ります(C6 は、rewrite.json がペイロードとして有効で、MIGRATION_REPORT_<saved suffix>.md が存在する場合に限ります)。最初に見つかった欠落/無効/制御状態のファイルで進行を停止します。ブロック状態/部分的なファイルは、以下のフローに従い、完了とは決してみなしません。ユーザーに「完了済みのフェーズ X..Y をスキップして、Z から再開」するか確認します。説明のつかない空白より後のファイルは、その空白とともにアーカイブします。
  • RUN_CONTEXT=mismatch → 範囲を限定して無効化します。各 MISMATCH 行をこの表に照らし、該当する単位を $REPO/.saws-migrate/phase-results-archive/<saved suffix>-$(date +%H%M%S)/(phase-results/ の兄弟ディレクトリ。内側にネストしない)にアーカイブし、その直後に run-context.json を current-context.json で上書きします(REPORT 自体を無効化する場合を除き、保存済みの report_date_suffix を引き継ぎます)。その後、無効化されたフェーズを順に再実行します。どのフィールドが異なり、何が再実行されるかをユーザーに伝えます。
不一致のフィールドアーカイブ(単位)維持
repo_root, migration_dir, region, aws_profile, aws_account, source_provider, assess_design_sha256, schema_version, plugin_versioneverything—
repo_head_sha / repo_branch / repo_dirty_sha256everything—
target_models / resolved_model_overridesANALYSIS, EVAL, REWRITE, REPORTINGESTION
log_files / max_golden_caseseverything—
source_key_sha256 / source_baseline_availableANALYSIS, EVAL, REWRITE, REPORTINGESTION
usage_baseline_sha256EVAL, REWRITE, REPORTANALYSIS, INGESTION

単位:ANALYSIS = analysis.json · INGESTION = ingestion.json + .saws-migrate/golden-dataset/ · EVAL = eval.json + .saws-migrate/eval-results/(cost_compare.py を除く)· REWRITE = rewrite.json + delta-decisions.json · REPORT = MIGRATION_REPORT_<saved suffix>.md。 C5後にC1~C3を再実行するには、移行前のツリーが必要です。 rewrite.json がペイロードとして有効で、テーブルによって ANALYSIS/INGESTION/EVAL が無効化された場合は、古い移行ブランチを破棄することをユーザーに確認します(tipが移動している場合は、まず保持またはリセットのフローを実行します)。その後、git checkout <saved repo_branch> を実行し、古いブランチと saws-migrate-baseline タグを削除して、C1から再実行します。ユーザーが同意しない場合は停止します。書き換えを含むツリーを再分析すると、結果が無意味になります。

  1. 保存済みのrun-contextがない場合 → 新規実行:current-context.jsonをrun-context.jsonとして書き込み、C1をディスパッチします。
C1 — アナライザー · C2 — インジェスター · C3 — 評価者

各フェーズを順番に実行し、コンテキストブロック(すべての前フェーズのファイルパスを列挙)とともにエージェントをディスパッチしてから、その出力ファイルを検証します。

ステップagentType出力ファイルスキーマ
C1aws-startup-advisor:llm2bedrock-code-analyzer$PHASE_DIR/analysis.jsonanalysis
C2aws-startup-advisor:llm2bedrock-log-ingestor$PHASE_DIR/ingestion.jsoningestion
C3aws-startup-advisor:llm2bedrock-prompt-evaluator$PHASE_DIR/eval.jsoneval

ブロック時のフロー(CONTROL=blocked):REASONに応じてユーザーと解決します —

  • model_access → ユーザーがBedrockコンソールでモデルを有効にします(フィンガープリント対象の変更はありません。ブロックされたフェーズのみを再ディスパッチします)
  • model_unresolvable → ユーザーがIDを選択または貼り付けます → resolved_model_overrides に記録し、Target行に反映します
  • source_key_auth → ユーザーが新しいキーを提供する(B3を再実行)か、ベースラインを利用不可に設定します
  • authz → IAMによって推論が拒否されています。detailには付与するアクションセットが示されます。Converseターゲットの場合は bedrock:InvokeModel*、mantleのみの openai.gpt-5* ターゲットの場合は bedrock-mantle:* アクション(CreateInference、CallWithBearerToken)です。ユーザーがIAMを修正します。フィンガープリント対象の変更はないため、ブロックされたフェーズのみを再ディスパッチします。これを model_access に振り分けてはいけません。IAM拒否に対してコンソールのModel accessページで修正するのは誤りであり、その逆も同様です。
  • mantle_deps_missing → 固定されたスクリプト環境に openai / aws-bedrock-token-generator がないため、mantleターゲットをまったくプローブできませんでした。ユーザーが再同期します(uv sync --project $SCRIPTS)。ブロックされたフェーズのみを再ディスパッチします。アクセスは一度も検証されていないため、以前のパスを引き続き有効として扱ってはいけません。
  • assess_output_missing → フェーズAを再実行し、その後C0からフェーズCを再開します

どの解決後も、C0の手順を再実行します(current-contextを再構築し、無効化テーブルを適用して、run-contextを上書きします)。そして、最も早く無効化されたフェーズから再ディスパッチします。実行を再開する場所を決めるのはブロック箇所ではなく、テーブルです。

部分実行時のフロー(evalのみ、CONTROL=partial):AskUserQuestion —

  • 残りのケースを続行 → 次の追加コンテキスト行を付けて評価者を再ディスパッチします: Resume: raw_results.jsonl already contains completed cases — evaluate only prompts whose ids are not present in it, then re-score and overwrite eval.json
  • 部分的な合格率で続行 → 次の指示を付けて評価者を再ディスパッチします:Finalize partial: do NOT call Bedrock again — score the cases already in raw_results.jsonl and emit the FULL eval payload over only those cases, with total_cases = the number scored and a notes prefix line 'partial_coverage: <completed>/<total> cases (throttled)'。その後、通常どおりC4を実行します。
  • 中止 → 停止します。ファイルは後でC0から再開できるよう、ディスク上に残します。
C4 — サイドバー(2 つのゲート)+決定の永続化

ゲート(a)— 品質の続行/中止。 $PHASE_DIR/eval.json を読み込みます。しきい値は pass rate >= 0.9 AND source_baseline_quality != 'poor' です(notes に no_golden_cases: true がある場合、品質シグナルはありません。必ず確認してください)。しきい値以上の場合は、何も表示せずに続行します。 しきい値未満の場合は、AskUserQuestion を表示します。

  • そのまま続行 → ゲート(b)
  • ターゲットモデルを変更 → resolved_model_overrides に記録し、C0 を再実行します(このテーブルによって ANALYSIS/EVAL が無効になり、C1 から実行が再開されます)。再試行の上限:2 回。
  • 中止 → 停止し、コードには触れません。

ゲート(a.5)— 書き換え戦略(移行計画に基づく)。 $MIGRATION_DIR/aws-design-ai.json → ai_architecture.code_migration.migration_path から migration_path を読み込みます。 値が "mantle"("mantle"、"mantle_openai_responses")で始まる場合は、 rewrite_strategy = "mantle" に設定します。それ以外(値が "converse"、"gpt-oss"、またはフィールドがない場合)は、rewrite_strategy = "converse" に設定します。 ユーザーへの確認は不要です。この決定は Assess/Design フェーズですでに行われています。

完全一致ではなく、プレフィックスで判定してください。Design は同一モデルの OpenAI 移行の場合、より具体的な "mantle_openai_responses" を書き込みます。"mantle" との完全一致で判定すると、これらの実行は 気付かれないまま Converse の経路に進み、動作している同一モデルのコードが、Converse のインターフェイスを持たないモデルに対する boto3 Converse クライアントへと書き換えられてしまいます。

ゲート(b)— 動作差分の解決。 analysis.behavior_deltas[] のうち user_visible == true のものごとに、behavior-delta-detection リファレンス($HELPERS/behavior-delta-detection/behavior-delta-detection.md と、その references/ ディレクトリ内の source_provider サブリファレンスを読み込みます)にある選択肢を使って AskUserQuestion を表示します。

永続化: 決定の配列(各エントリは {delta_type, location, resolution_chosen, source}。ユーザーに見える差分がない場合は [])を $PHASE_DIR/delta-decisions.json に書き込み、検証します(--schema delta-decisions)。C5 より前にこのファイルが存在している必要があります。これにより、C5 の再試行やクラッシュ後の再開を単独で行えます。

C5 — リライター · C6 — レポート
ステップagentType出力スキーマ
C5aws-startup-advisor:llm2bedrock-code-rewriter$PHASE_DIR/rewrite.jsonrewrite
C6aws-startup-advisor:llm2bedrock-report-generatorリポジトリのルートにある MIGRATION_REPORT_<saved suffix>.md(なし — ファイルの存在を完了チェックに使用)

C5 のコンテキストブロックには、Confirmed behavior-delta decisions file の行と Report date suffix の行が含まれます(再開時は run-context から取得し、今日の日付は使用しません)。C6 のコンテキストブロックには、4 つすべてのフェーズ結果ファイルのパスが記載されます。

rewrite_strategy == "mantle" の場合、C5 のコンテキストブロックには次の項目も含まれます。

  • Rewrite strategy: mantle(Converse の場合はこの行全体を省略します。この行がないことが、デフォルトの Converse パスを示します)
  • Mantle model map: <source-model> -> <bedrock-model-id> — プランの ai_architecture.bedrock_models[] エントリを参照します(各 source_model → aws_model_id のペア)。
  • マッピングされた aws_model_id のいずれかが独自 GPT モデル(openai.gpt-5*)の場合は、Mantle surface: responses と Mantle base path: /openai/v1。これらのモデルは Responses API を通じて /openai/v1 パスでのみ提供されます。これは、他の mantle モデルが使用する v1 パスとは異なるため、リライターは /v1 のベース URL や Chat Completions 呼び出しを生成してはなりません。$ASSESS_BASE/references/shared/openai-on-bedrock.md を参照してください。
  • bedrock_models[].model_change が false の場合は Same model: true。リライターにモデルパラメーターを変更せず、エンドポイント、認証情報、モデル ID の変更と(ソースで Chat Completions を使用していた場合は)インターフェースの再構成に変更を限定するよう指示します。
C7 — 概要を表示
uv run --project $SCRIPTS python $SCRIPTS/render_report.py --phase-results $PHASE_DIR --repo $REPO --date-suffix <saved suffix>

概要を表示します。ユーザーに rewrite.branch_name(通常は bedrock-migration ですが、すでにそのブランチがある場合は bedrock-migration-2 のように衝突回避の接尾辞が付きます)とレポートファイルを案内します。元に戻す方法も伝えます。必ず rewrite.branch_name にある実際のブランチ名に置き換えてください。衝突が発生した実行では、bedrock-migration はユーザーが以前から使用しているブランチであり、削除すると作業内容が失われます。

破棄するには、git checkout <your original branch>、git branch -D <rewrite.branch_name>、 git tag -d saws-migrate-baseline、および rm -rf .saws-migrate .migration を実行すると、すべての 移行成果物(API キーファイルを含む)が削除されます。

このスキルの実行状態を閉じます($BEDROCK_RUN_DIR/.phase-status.json の読み取り・マージ・書き込み)。 phases.execute を "completed" に、current_phase を "complete" に設定し、last_updated を更新します。これにより、AI 移行が使用状況のファネル上で完了として記録されます。 この状態を書き込んだ後、references/vendored/telemetry/PROTOCOL.md に従い、cli 報告モードで照合します。hook モードでは CLI をスキップします。


アクセス専用モード

ユーザーがコード移行ではなく、指定したモデルセットの Bedrock モデルアクセスの確認または有効化を希望する場合に、ステップ 0a-bis から開始します。ID の確認(B2)と事前チェック(B4)は再利用しますが、モデルリストはユーザーから取得します。また、gcp-to-aws、Assess、ソースキー(B3)、フェーズ C には一切触れません。「どのモデルを有効にする必要があり、その方法は何か」に答えたら終了します。Git ブランチもリライトも作成しません。

AC1 — 期待値を設定する(正確性 — これを最初に伝える)

モデルを収集する前に、ユーザーに次のように伝えてください:

「Bedrock の『モデルアクセス』について、いくつかポイントがあります:

  • Claude、Llama、Nova、Mistral などは bedrock-runtime エンドポイント上の Bedrock 基盤モデルであり、推論には bedrock:InvokeModel / Converse を使用します。商用リージョンでは、呼び出し元が AWS Marketplace の権限(aws-marketplace:Subscribe / Unsubscribe / ViewSubscriptions)を持っていれば、アクセスはデフォルトで有効です — モデルは初回呼び出し時に自動サブスクライブされます。コンソールの Model access ページは明示的な有効化/カタログのステップです(GovCloud では必須のフローです)。Anthropic のモデルはさらに、呼び出しの前にアカウントごとに一度だけ First-Time-Use フォーム(PutUseCaseForModelAccess)が必要です — ただし bedrock-mantle 経由でアクセスする場合を除きます。
  • Bedrock 上の OpenAI にはいくつかの形態があり、いずれも実在します — そしてどのエンドポイントを使うかは ID ごとに決まり、一律のルールではありません:
    • オープンウェイトの gpt-oss(openai.gpt-oss-20b-1:0、openai.gpt-oss-120b-1:0)→ bedrock:InvokeModel / Converse 経由の bedrock-runtime(その Responses API は bedrock-mantle でも提供されています)。
    • ベアのプロプライエタリ GPT ID(openai.gpt-5*、gpt-oss ではない)→ bedrock-mantle エンドポイント(Responses API)でプローブされます。
    • us. / in. / global. が先頭に付いた GPT-5.6 CRIS プロファイル ID(例:global.openai.gpt-5.6-sol)→ Converse がサポートされる bedrock-runtime ターゲットです。
    • bedrock-mantle パスは別のアクションセットを使用します — bedrock-mantle:*(例:AmazonBedrockMantleInferenceAccess マネージドポリシー:bedrock-mantle:CreateInference + CallWithBearerToken)— これは bedrock:InvokeModel とは異なります。プリフライトはモデルごとに判断します。決めつけないでください。
  • Bedrock 上にないものは、api.openai.com にある OpenAI 自身のホスト型 API の呼び出しです — それは OpenAI に帰属します。『Bedrock 上の GPT』とは、AWS のエンドポイントと IAM を通じてアクセスする上記の AWS 提供モデルを意味します。

プリフライトは各モデルを適切な API で自動的にプローブし、モデルごとに有効化すべきアクセスを正確に報告します。それを伝えます。」

AC2 — 要求されたモデルとリージョンを収集する(フレンドリ名はまだ解決しないこと)
  • モデル(生の要求のみ): $ARGUMENTS がモデル ID を指定している場合は、それらを直接使用します — 解決はスキップします。すでに ID だからです。そうでない場合は AskUserQuestion:「どのモデルへのアクセスが必要ですか? Bedrock のモデル ID(例:anthropic.claude-sonnet-4-5-v1:0、openai.gpt-oss-120b-1:0)またはプロバイダー + 名前を指定してください。ID を解決します。」ユーザーが指定したもの(ID および/またはフレンドリ名)を $REQUESTED_MODELS に収集します — ここでフレンドリ名リゾルバーを呼び出さないでください。 リゾルバー自身のコマンド(aws bedrock list-foundation-models / list-inference-profiles)は --region を必要とし、呼び出し時にアクティブな AWS アイデンティティで実行されます — $REGION / AC3 が設定される前に解決すると、誤ったリージョンやデフォルトの(まだ確認されていない)プロファイルに対して実行され、モデル名とは無関係な理由で失敗する可能性があります。
  • リージョン: AskUserQuestion:「どの AWS リージョンですか?(デフォルト us-east-1)」→ $REGION。
AC3 — AWS アイデンティティの確認

B2 のアイデンティティ確認ステップを記載どおりに正確に実行します(プロファイル選択の処理と $AWS_PROFILE_CHOICE を含みます)。確認されたアイデンティティなしでは続行しないでください。

AC3.5 — リージョンと ID が確認できたので、わかりやすい名前を解決します

$REQUESTED_MODELS 内で、まだ Bedrock のモデル ID ではないエントリについては、ここで解決します ($HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md を読み、その手順に従ってください)。AC2 の $REGION を使用し、AC3 でデフォルト以外のプロファイルが選ばれた場合は、リゾルバー自身の AWS CLI 呼び出しに AWS_PROFILE=$AWS_PROFILE_CHOICE をプレフィックスとして付けてください(環境変数は Bash 呼び出し間で保持されないため、プレフィックスを付けないと、直前に確認した ID ではなく DEFAULT の ID に対して照会されます)。解決された ID をユーザーに確認します。最終的な ID(すでに ID であるエントリと、新たに解決されたエントリ)を $TARGET_MODELS にまとめます。

その後、ユーザーが $REGION または AWS プロファイルを変更した場合(たとえば、AC4 の authz/credentials エラーを受けて再確認を求められた場合)は、AC4 を再実行する前に、名前ベースのエントリについてこの解決手順を再実行してください。古いリージョン/プロファイルに対して解決したモデル ID は、新しい設定では適切でない(または存在しない)可能性があります。

AC4 — 指定されたモデルの事前チェックを行います

$TARGET_MODELS に対して B4 の事前チェックを実行し、B4 と同じ方法で判定結果を解釈します。ただし、モード固有の違いは次のとおりです。

uv run --project $SCRIPTS python $SCRIPTS/preflight_bedrock.py --region $REGION --models <comma-separated $TARGET_MODELS> --dataset-size 0

(--dataset-size 0 — このモードにはゴールデンデータセットがないため、クォータとデータセットの比較に関する警告には意味がありません。クォータに関する通常の注記があれば、引き続き表示します。AC3/B2 でデフォルト以外のプロファイルが選ばれた場合は、インラインで AWS_PROFILE=$AWS_PROFILE_CHOICE を先頭に付けてください。環境変数は Bash 呼び出し間で保持されないため、プレフィックスを付けないと、ユーザーが直前に確認した ID ではなく DEFAULT の ID を検証し、credentials/authz エラーが発生した場合、別のアカウントに対するエラーになります。)

次に、B4 の分岐表に従います。

  • reason: model_access → モデルは存在しますが、このアカウントではアクセスが有効になっていません。失敗したモデルに必要な前提条件を案内してください。
    • 商用リージョン: 呼び出し元に AWS Marketplace の権限(aws-marketplace:Subscribe / Unsubscribe / ViewSubscriptions)があれば、アクセスはデフォルトで有効です。モデルは初回の呼び出し時に自動でサブスクライブされます。これらの権限がない場合は、権限の付与が解決策です。
    • GovCloud、サードパーティモデル(大半のモデル — まず確認): GovCloud アカウントは商用アカウントと 1 対 1 でリンクされており、AWS の公式ドキュメントによると、サードパーティモデルへのアクセスは両方のアカウントで有効にする必要があります。GovCloud でのみ有効にしても、アカウントはブロックされたままです。次の 2 つの手順を順番に実行します。
      1. リンクされた商用アカウントで、us-east-1 または us-west-2 にてモデルを 1 回呼び出します(または、上記の商用リージョンの箇条書きにあるように、SDK / CLI で有効にします。最初に AWS の ID /プロファイルをそのアカウントに切り替えてください)。これは、GovCloud ではなく商用アカウントに対して同じ自動有効化の仕組みを実行するものです。注:この手順の後、権利情報がリンク先の GovCloud アカウントに反映されるまで数分かかる場合があります。
      2. GovCloud の ID に切り替えてから、コンソールの Model access ページを使用します。必ず us-gov-west-1 で操作してください(推論リージョンではありません。GovCloud の Model access コンソールページは、ユーザーがモデルを呼び出そうとしている $REGION にかかわらず、このリージョンにしかありません)。 各手順の前に、現在有効な ID /プロファイルを確認してください。ここが一致していないと(別のアカウントで操作していると)、有効化が「機能しなかった」ように見えます。
    • GovCloud、Amazon 提供モデル: 上記の GovCloud アカウントでの手順だけが必要です。Amazon のモデルはサードパーティの AWS Marketplace の掲載製品ではないため、リンクされた商用アカウントでの手順は不要です。
    • Anthropic モデルでは、bedrock-mantle 経由の場合を除き、呼び出し前にアカウントごとに初回のみの First-Time-Use フォーム(PutUseCaseForModelAccess)への入力も必要です。 失敗したモデルと該当する前提条件をユーザーに伝え、有効化後に AC4 を再実行することを提案してください。これは、「アクセスを得る」ためにここに来たユーザーによくある、想定どおりの結果です。
  • reason: authz → アクセスは有効ですが、IAM によって推論が拒否されています。付与すべきアクションを案内してください。標準モデルの場合は bedrock:InvokeModel、mantle のみを対象とする openai.gpt-5*(gpt-oss ではなく、プロプライエタリな GPT のモデル ID)の場合は bedrock-mantle:* の権限一式です(B4a を参照)。どのアクションかは detail に記載されているため、ID から推測せず、その内容に従ってください。gpt-oss では mantle ではなく bedrock:InvokeModel で失敗します。
  • reason: model_unavailable → その ID は $REGION で提供されていません。resolve-bedrock-model-id の手順を使って、クロスリージョン推論プロファイルの ID または正しい ID を提案し、再確認してから AC4 を再実行してください。
  • reason: credentials / mantle_deps_missing /その他 → detail を提示し、B4 のルールに従ってください(修正して再実行し、確認できていないアクセスを確認済みだと主張しないでください)。
  • ok == true + reason: embedding_unprobed → モデルが未認識の埋め込みモデルファミリーに属しているため、プリフライトでは実際に呼び出すことができませんでした(preflight_bedrock.py の probe_model() を参照)。これは JSON レベルでは ok: true ですが、リクエストは 1 件も送信されていないため、実際のアクセスについては何も確認できていません。確認済みかどうかにかかわらず、これを「有効」と伝えてはいけません。「有効」は、このプローブで確認していない事実を断定する表現です。ユーザーには、このモデルのアクセスは未確認であることを伝えてください(「有効 — 未確認」ではありません)。そのモデルに依存する前に、Bedrock コンソールで確認するか、手動でテスト呼び出しを行うよう依頼してください。
  • ok == true + reason: throttled_ok → プローブはサービスに到達しましたが、スロットリングされました(ThrottlingException / ServiceQuotaExceededException / mantle での 429)。これはリクエストが認可されたことを証明しますが、「呼び出しが成功した」という主張とは異なります。応答は返されていないため、モデルの実際の動作については何も確認できていません。ユーザーには、アクセスは認可済みと確認できましたが、プローブ自体はスロットリングされましたと伝えてください。これは割り当て量に関する注意事項であり、アクセス判定を疑う理由ではありません。
  • ok == true(その他の reason、つまり実際の呼び出しまたは InvokeModel 呼び出しで実際の応答が返された場合)→ その ID のアクセスは $REGION で正常に機能していることをユーザーに伝えてください。
AC5 — 要約して停止

ユーザーにモデルごとの要約を提示します:<model_id> → enabled & working(実際の invoke が成功) / access unverified — no request made(embedding_unprobed。手動でのコンソール/テスト確認を推奨) / authorized (probe throttled)(throttled_ok。アクセスは確認済みですが、応答は観測されていない) / enable access(model_access ブランチから該当する前提条件を明示 — 商用リージョンでは Marketplace の権限、GovCloud ではリンクされた商用アカウントのステップ(サードパーティモデル)に加えて us-gov-west-1 コンソールの Model access ページ、さらに該当する場合は Anthropic の FTU フォーム) / grant <action> / not available in <region>, use <candidate>。embedding_unprobed や throttled_ok を enabled & working にまとめてはいけません — それぞれユーザーにとって異なる意味を持ちます(リクエスト未実施 / 承認済みだが応答なし / 実際に動作確認済み)。また、初回のサードパーティモデルで実際に invoke が成功した場合でも、それが恒久的な保証になるわけではありません。AWS は初回 invoke 時にバックグラウンドでアクセスを自動有効化し(確定まで最大約 15 分)、その間の前提条件の欠落により、以前の呼び出しが成功していても、その後の呼び出しが AccessDeniedException で失敗する可能性があります — このアカウントで初めて新たに動作するようになったと報告されたモデルについては、この点を言及してください。その後、Contextual offers (final step) を実行します。Assess、rewrite、またはいかなるコード変更にも進まないでください — このモードは完了です。


インラインモード(Agent/subagent dispatch ツールを持たないプラットフォーム)

このプラットフォームに subagent dispatch ツールがない場合は、フェーズを一度に 1 つずつインラインで実行し、フェーズ間で必ず停止してください:

  1. Read で正確に 1 つのエージェント定義(<plugin>/agents/<name>.md)のみを読み込みます — 一度に複数のフェーズの定義をコンテキストに読み込まないでください。
  2. それを最初から最後まで実行し、同じフェーズ結果ファイルを書き込んで検証します。
  3. 停止します。フェーズの結果(バリデータの CONTROL 行 + 1 行の要約)を報告し、次のフェーズの定義を読み込む前にユーザーに確認を求めます。このサイドバーは必須です:これはコンテキストプレッシャーの解放弁であり、フェーズ結果ファイルがあれば、ユーザーが新しいセッションで続行した場合でも何も失われません。

インラインモードは subagent dispatch よりも低速でコンテキスト消費が多く、また rewriter フェーズは git 操作(ブランチ、コミット、worktree)をこのセッション内で直接実行することを、あらかじめユーザーに警告してください。


失敗時の処理

  • エージェントの dispatch が失敗する(ツールエラー、ターミナル障害) → フェーズファイルが存在しない → バリデータが exit 2 → ステートレスな fixer-retry パス(修正すべきファイルが見つからないため、フェーズを再実行する)。自動リトライは 2 回の上限を超えないでください。
  • ユーザーがいずれかのゲートで中断する → ソースコードが変更されていないことを確認します(それより前に中断した場合、C5 は開始されていません)。.migration/ と .saws-migrate/ の成果物は実際に存在することに注意してください。ユーザーが削除を希望する場合は、C7 の元に戻すコマンドを提示してください。
  • Assess スキルが失敗する → エラーを表示して停止します。ユーザーは /aws-startup-advisor:llm-to-bedrock を再実行できます。

コンテキストに応じたオファー(最終ステップ)

終了する前に: 以下の**コンテキストに応じたオファー(最終ステップ)**を実行するまで、回答は完成していません。

これは、すべての最終提案における必須の締めくくりのステップです。回答を完了と判断する前に実施してください。このオファーの確認は、その場で行ってください。別のスキルを読み込んで依存してはいけません。提案はまずメリットに基づいて決定します。このステップによって提案が変更されたり、順位が入れ替わったり、再検討されたりすることはありません。オファーを調べるのは、助言が確定した後だけです。

  1. ../knowledge-base-for-startups/references/offers.md(オファーの一覧:オファー・概要・キーワードがオファーごとに1行ずつ記載されています)を読みます。
  2. 創業者がこのセッションで実際に示した内容との関連性を判断します。次のいずれかに該当する場合に限り、オファーを提示してください。製品名の一致(特定のパートナー製品を名前を挙げて推奨しており、その製品が一覧にある)、または直接的な意図・構成要素の一致(オファーのキーワードが、具体的なワークロード、最終提案の構成要素、または創業者が挙げたニーズに直接役立つ)。基準は厳格に保ってください。一致が弱い場合や、明示されていないニーズを推測することになる場合は、何も追加しません。この移行では、移行後も維持または選択された製品のクレジットに限り、オファーを提示してください(例:書き換え後も LangChain のコードを維持する場合の LangSmith クレジット)。それ以外は何も追加しません。書き換えや gcp-to-aws の設計で選択された Amazon Bedrock などと競合するオファーは、決して提示しないでください(例:Bedrock の代わりとなる Fireworks AI や別のモデル推論プロバイダー)。
  3. 該当基準を満たすオファーがある場合に限り、そのオファーの詳細ファイル ../knowledge-base-for-startups/references/offers/<slug>.md だけを開き、価値と適用条件をそのファイルに忠実に要約した、控えめで取り消し可能なイタリック体の行を1行だけ追加してください(適用条件は一つも省かず、決して捏造しないでください)。リンク先は正規の source_url を使い、source 属性パラメーターを付けて作成します。?source=ide-startupAdvisor-<host> を追加してください(URLにすでにクエリー文字列がある場合は &source=...)。実行環境に応じて <host> を設定します(Claude Code → claude、AWS Startup Advisor IDE extension/VS Code → vscode、Cursor → cursor、Kiro → kiro、Codex → codex)。判断できない場合は ide-startupAdvisor を使用してください。クエリーパラメーターのみを追加し、リンク先は決して変更しないでください。提示するオファーは最大1件とし、複数を並べないでください。該当するオファーがなければ何も追加せず、オファーやパートナーの代替案、オファーを提示しなかった理由にも触れないでください。

標準行:

***<Offer>** has an exclusive offer via AWS Activate — <value>, <eligibility>. [Redeem →](<source_url>?source=ide-startupAdvisor-<host>)*

上限と制御:回答ごとのオファーは最大1件で、多くの場合は提示しません。5メッセージにつき最大1件、1セッションにつき最大2件です。同じセッションで同一オファーを提示できるのは1回までで、すでに提示済み、申請済み、または却下済みのオファーは提示しないでください。創業者がオファーをミュートしている場合は、このステップを完全に省略してください。5メッセージごと、セッションごと、提示済みかどうかに関する上限は、セッション状態による制限です。過去にオファーが提示されていない新しいセッションでは、これらの制限は適用されません。そのため、セッション履歴を確認できないという理由だけで、基準を満たすオファーを提示しないでください。詳細なルールは ../contextual-offers-for-startups/SKILL.md を参照してください。ただし、確認はその場で行ってください。このステップは、そのスキルが読み込まれていることを前提としてはなりません。

コメント