llm-to-bedrock

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Migrate to Bedrock (Assess + Execute)

迁移到Bedrock(评估+执行)

Single-command AI migration: OpenAI / Gemini / Anthropic → Amazon Bedrock.
The skill base directory is given in the "Base directory for this skill: X" line the harness emits at load time. Call it
<SKILL_BASE>
. Derived paths:
  • $SCRIPTS
    =
    <SKILL_BASE>/scripts
  • $HELPERS
    =
    <SKILL_BASE>/references/helpers
    (the former helper skills, now references)

一键式AI迁移:OpenAI / Gemini / Anthropic → Amazon Bedrock。
技能基础目录由加载时工具输出的「Base directory for this skill: X」行给出,记为
<SKILL_BASE>
。派生路径:
  • $SCRIPTS
    =
    <SKILL_BASE>/scripts
  • $HELPERS
    =
    <SKILL_BASE>/references/helpers
    (原辅助技能,现为参考文件)

Step 0 — Check prerequisites

步骤0 — 检查先决条件

0a. Check that
uv
is available

0a. 检查
uv
是否可用

bash
uv --version 2>/dev/null || echo "MISSING"
If missing: "Install uv first — see the official install guide: https://docs.astral.sh/uv/getting-started/installation/ (e.g.
brew install uv
or
pipx install uv
)". Stop.

bash
uv --version 2>/dev/null || echo "MISSING"
如果缺失:请先安装uv——参考官方安装指南:https://docs.astral.sh/uv/getting-started/installation/(例如`brew install uv
pipx install uv`)。停止操作。

Step 1 — Collect source code path

步骤1 — 收集源代码路径

If
$ARGUMENTS
contains a path, use it as
$REPO
. Otherwise use AskUserQuestion: "Where is your source code? Enter a local path or GitHub URL."
If a GitHub URL,
git clone
it to a temp dir; use that path as
$REPO
.
Checks on $REPO:
  1. Git-root check (compare resolved paths — on macOS
    /tmp
    resolves to
    /private/tmp
    , so a raw string comparison false-positives):
    bash
    [ "$(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
      → proceed.
    • GIT_ROOT_MISMATCH
      and the command errored (not a git repo at all) → tell the user the path must be a git repository (the deliverable is a git branch); re-ask.
    • GIT_ROOT_MISMATCH
      but inside a repo (user pointed at a subdirectory) → AskUserQuestion: "Use the repo root instead" (recommended) / "Continue with this subdirectory" / "Abort".
  2. Dirty-tree check:
    bash
    git -C <REPO> status --porcelain
    If uncommitted changes exist, show them and AskUserQuestion: "Continue anyway" or "Let me clean up first".
Record
$REPO
for all subsequent steps.

如果
$ARGUMENTS
包含路径,则将其用作
$REPO
。否则使用AskUserQuestion询问: "你的源代码在哪里?请输入本地路径或GitHub URL。"
如果是GitHub URL,使用
git clone
将其克隆到临时目录;将该路径用作
$REPO
对$REPO的检查:
  1. Git根目录检查(比较解析后的路径——在macOS上
    /tmp
    会解析为
    /private/tmp
    ,因此原始字符串比较会出现误判):
    bash
    [ "$(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. 脏树检查:
    bash
    git -C <REPO> status --porcelain
    如果存在未提交的更改,显示这些更改并使用AskUserQuestion询问:"继续操作"或"我先清理一下"。
记录
$REPO
供后续所有步骤使用。

Phase A — Assess (MANDATORY: delegate to the gcp-to-aws skill)

阶段A — 评估(必填:委托给gcp-to-aws技能)

CRITICAL: You MUST use the Skill tool to invoke
migration-to-aws:gcp-to-aws
(a sibling skill in this same plugin). Do NOT perform the Assess phase yourself. Do NOT read source code, detect AI SDKs, or ask Clarify questions manually. The entire Assess phase is handled by the gcp-to-aws skill — you only invoke it and wait for completion.
关键:必须使用Skill工具调用
migration-to-aws:gcp-to-aws
(此插件中的同级技能)。请勿自行执行评估阶段。请勿手动读取源代码、检测AI SDK或提出澄清问题。整个评估阶段由gcp-to-aws技能处理——你只需调用它并等待完成。

A1 — Invoke the Assess skill

A1 — 调用评估技能

Call the Skill tool with skill name
migration-to-aws:gcp-to-aws
.
Before invoking, tell the user:
"I'm now invoking the gcp-to-aws Assess skill to discover your AI workloads and design the Bedrock migration. It will ask you some questions — please answer them. (Don't be confused by the skill's
gcp-to-aws
name — it also covers pure AI/LLM migrations with no GCP or infrastructure component, which is how it's being used here.)"
After invoking the Skill tool, the
gcp-to-aws
skill instructions will load into context. Follow those instructions exactly — they will drive the Discover, Clarify, Design, Estimate, and Generate phases. The source code to scan is at
$REPO
.
Important context for the gcp-to-aws skill execution:
  • Source code is at
    $REPO
    — when the skill asks for GCP sources or scans for files, point it there
  • This is an AI/LLM workload migration — the AI path is the goal
  • Unless Terraform/IaC files are actually present in
    $REPO
    , skip IaC discovery
  • Unless the user offers billing data, skip billing discovery. If the source provider is OpenAI, the skill may instead offer its OpenAI Admin API usage discovery (
    discover-openai-api.md
    — read-only, consent-gated, needs an Admin key with Usage set to Read); accepting it gives Estimate real spend and token volumes without manual CSV exports
使用技能名称
migration-to-aws:gcp-to-aws
调用Skill工具。
调用前告知用户:
"我现在将调用gcp-to-aws评估技能来发现你的AI工作负载并设计Bedrock迁移方案。它会向你提出一些问题——请回答。(不要被技能的
gcp-to-aws
名称混淆——它也适用于没有GCP或基础设施组件的纯AI/LLM迁移,本次就是这样使用的。)"
调用Skill工具后,
gcp-to-aws
技能的指令将加载到上下文中。严格遵循这些指令——它们将驱动发现、澄清、设计、估算和生成阶段。要扫描的源代码位于
$REPO
gcp-to-aws技能执行的重要上下文:
  • 源代码位于
    $REPO
    ——当技能请求GCP源或扫描文件时,指向该路径
  • 这是AI/LLM工作负载迁移——AI路径是目标
  • 除非
    $REPO
    中实际存在Terraform/IaC文件,否则跳过IaC发现
  • 除非用户提供计费数据,否则跳过计费发现。如果源提供商是OpenAI,技能可能会提供其OpenAI Admin API使用情况发现(
    discover-openai-api.md
    ——只读,需要同意,需要将Usage设置为Read的Admin密钥);接受它无需手动导出CSV即可获得估算的实际支出和令牌量

A2 — Wait for Assess completion

A2 — 等待评估完成

The
gcp-to-aws
skill is a state machine. After each phase completes, it may stop and wait for the next invocation. Check progress against the LATEST run directory only (older
.migration/
runs may contain a stale "completed" status):
bash
MIGRATION_DIR=$(ls -td "$REPO/.migration"/*/ 2>/dev/null | head -1)
gcp-to-aws
技能是一个状态机。每个阶段完成后,它可能会停止并等待下一次调用。仅根据最新的运行目录检查进度(旧的
.migration/
运行可能包含过时的"completed"状态):
bash
MIGRATION_DIR=$(ls -td "$REPO/.migration"/*/ 2>/dev/null | head -1)

Stdlib-only JSON read — no boto3, so bare python3 is fine here (no pinned env needed).

仅使用标准库读取JSON——无需boto3,因此纯python3即可(无需固定环境)。

python3 -c "import json,sys; print(json.load(open('$MIGRATION_DIR/.phase-status.json'))['phases'].get('generate','missing'))" 2>/dev/null || echo "no-status-file"

- `completed` → proceed to A3.
- Anything else (including `no-status-file`) → the skill needs to run again. Re-invoke
  `migration-to-aws:gcp-to-aws` via the Skill tool — it picks up where it left off.

**Cap: at most 6 re-invocations.** If `generate` is still not `completed` after 6, stop and
show the user the last status output — the Assess skill is stuck and needs manual attention;
looping further just burns context.
python3 -c "import json,sys; print(json.load(open('$MIGRATION_DIR/.phase-status.json'))['phases'].get('generate','missing'))" 2>/dev/null || echo "no-status-file"

- `completed` → 进入A3。
- 其他任何情况(包括`no-status-file`)→ 需要重新运行技能。通过Skill工具重新调用`migration-to-aws:gcp-to-aws`——它会从上次中断的地方继续。

**上限:最多重新调用6次。**如果6次后`generate`仍未变为`completed`,则停止并向用户显示最后一次状态输出——评估技能已卡住,需要手动干预;继续循环只会消耗上下文资源。

A3 — Locate Assess output

A3 — 定位评估输出

Find
$MIGRATION_DIR
(the
.migration/<MMDD-HHMM>/
directory that was created):
bash
ls -td "$REPO/.migration"/*/ 2>/dev/null | head -1
Verify these files exist in
$MIGRATION_DIR
:
  • aws-design-ai.json
    (model mapping + architecture)
  • ai-workload-profile.json
    (detected workloads)
  • preferences.json
    (user preferences from Clarify)
If
aws-design-ai.json
is missing, Assess did not complete the AI path correctly. Show the error and stop.

找到
$MIGRATION_DIR
(即创建的
.migration/<MMDD-HHMM>/
目录):
bash
ls -td "$REPO/.migration"/*/ 2>/dev/null | head -1
验证
$MIGRATION_DIR
中存在以下文件:
  • aws-design-ai.json
    (模型映射+架构)
  • ai-workload-profile.json
    (检测到的工作负载)
  • preferences.json
    (来自澄清阶段的用户偏好)
如果
aws-design-ai.json
缺失,则评估未正确完成AI路径。显示错误并停止。

Phase B — Execute Prep

阶段B — 执行准备

B1 — Read Assess outputs

B1 — 读取评估输出

Read
$MIGRATION_DIR/aws-design-ai.json
and extract:
  • ai_architecture.bedrock_models[]
    → array of
    {source_model, aws_model_id, use_case}
  • Collect all
    aws_model_id
    values into
    $TARGET_MODELS
    (array). Keep the
    use_case
    of each: the preflight script probes each model by the right API automatically (Converse for chat, InvokeModel for embeddings), but the evaluator's quality scoring only applies to chat models — embedding targets get format/dimension validation only.
Read
$MIGRATION_DIR/ai-workload-profile.json
and extract:
  • summary.ai_source
    → source provider
Read
$MIGRATION_DIR/preferences.json
and extract:
  • design_constraints.target_region
    $REGION
    (default
    us-east-1
    if absent)
Validation: If
aws-design-ai.json
has no
ai_architecture.bedrock_models[]
array, or the array is empty, STOP: "Assess output incomplete — model mapping missing."
读取
$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[]
数组,或数组为空,停止操作:"评估输出不完整——模型映射缺失。"

B2 — AWS identity confirmation

B2 — AWS身份确认

bash
aws sts get-caller-identity 2>&1
If the command fails (no credentials, expired SSO token): show the error and tell the user to run
aws configure
or
aws sso login
(suggest typing
! aws sso login
to run it in this session), then re-run B2. Do not proceed without a confirmed identity.
On success, show Account, Arn, UserId via AskUserQuestion: "This AWS identity will be used for Bedrock calls. Is this correct?"
Options:
  • Yes, use this identity → proceed
  • Use a different AWS profile → ask which profile, record it as
    $AWS_PROFILE_CHOICE
    , re-run B2 as
    aws sts get-caller-identity --profile $AWS_PROFILE_CHOICE
    , and re-confirm. Do NOT rely on exporting
    AWS_PROFILE
    — env vars do not persist across Bash tool calls or into workflow subagents (see B3). Instead pass the choice explicitly everywhere:
    --profile
    on every aws CLI call, and prepend
    AWS_PROFILE=$AWS_PROFILE_CHOICE
    inline on the B4 preflight command and inside the workflow args (
    awsProfile
    field) so subagents can do the same.
Also confirm region: "Bedrock region will be
$REGION
. OK or override?"
bash
aws sts get-caller-identity 2>&1
如果命令失败(无凭据、SSO令牌过期):显示错误并告知用户运行
aws configure
aws sso login
(建议输入
! aws sso login
在此会话中运行),然后重新运行B2。未确认身份前请勿继续。
成功后,通过AskUserQuestion显示账户、Arn、UserId: "此AWS身份将用于Bedrock调用。是否正确?"
选项:
  • 是,使用此身份 → 继续
  • 使用其他AWS配置文件 → 询问配置文件名称,将其记录为
    $AWS_PROFILE_CHOICE
    ,使用
    aws sts get-caller-identity --profile $AWS_PROFILE_CHOICE
    重新运行B2,并重新确认。 请勿依赖导出
    AWS_PROFILE
    ——环境变量不会在Bash工具调用之间或工作流子Agent中持久化(见B3)。而是在所有地方显式传递选择:在每个aws CLI调用上添加
    --profile
    ,并在B4预飞命令和工作流参数(
    awsProfile
    字段)中内联添加
    AWS_PROFILE=$AWS_PROFILE_CHOICE
    ,以便子Agent也能这样做。
同时确认区域:"Bedrock区域将设置为
$REGION
。确认还是修改?"

B3 — Source API key (optional)

B3 — 源API密钥(可选)

First, create the artifact directory and make it self-ignoring IMMEDIATELY — before any key exists, so the secret is never sitting in an unignored working tree (even if the user aborts before the rewriter runs):
bash
mkdir -p "$REPO/.saws-migrate" && printf '*\n' > "$REPO/.saws-migrate/.gitignore"
Determine
$KEY_ENV_VAR
from B1's source provider (this is the env-var name the baseline skill's parser expects — a bare key without the
NAME=
prefix will NOT be parsed):
  • openai
    OPENAI_API_KEY
  • anthropic
    ANTHROPIC_API_KEY
  • google
    /
    gemini
    GEMINI_API_KEY
The key must never enter this conversation (HARD RULE). Do not ask the user to paste the key in chat, and never echo, cat, or interpolate its VALUE into any command, question, or output — the agent only ever handles the file path. If the user pastes a key into the chat unprompted, do not use it: tell them it is now part of the transcript, recommend rotating it, and continue with one of the paths below.
First check whether the key is already present in the shell environment (each Bash call initializes from the user's profile, so a profile-exported key is visible to every call). POSIX-safe —
printenv
works in bash and zsh alike (
${!VAR}
indirection is bash-only and zsh errors on it). This prints presence only, never the value:
bash
[ -n "$(printenv "$KEY_ENV_VAR")" ] && echo ENV_KEY_PRESENT || echo ENV_KEY_ABSENT
AskUserQuestion: "Do you have an API key for the source model (e.g. OpenAI key for GPT-4o)? Providing it enables side-by-side quality comparison. Without it, evaluation uses absolute scoring only."
Options (offer the first only on
ENV_KEY_PRESENT
):
  • Use the
    $KEY_ENV_VAR
    already in my environment
    → materialize env var to file in one command — the value never appears in the transcript:
    bash
    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"
    Then run the format check below and set
    sourceBaselineAvailable = true
    ,
    sourceKeyRef = "$REPO/.saws-migrate/.source-provider-env"
    .
  • I'll write it to a file myself → give the user this command to run in THEIR OWN terminal (not through the agent; in Claude Code an
    !
    prefix runs it in-session) —
    read -rs
    collects the key without echoing it:
    bash
    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
    Substitute the literal env-var name and repo path when presenting it (those are not secrets). Then run the format check below and set the same flags as above.
  • Skip
    sourceBaselineAvailable = false
    ,
    sourceKeyRef = ""
    .
Whichever path wrote the file, verify the format (never prints the key; catches a value written without the
NAME=
prefix, which the baseline parser would silently miss):
bash
grep -qE '^(OPENAI|ANTHROPIC|GEMINI)_API_KEY=.+' "$REPO/.saws-migrate/.source-provider-env" && echo KEY_FORMAT_OK || echo KEY_FORMAT_BAD
On
KEY_FORMAT_BAD
, have the same path that wrote the file rewrite it (do not echo its contents).
(
.saws-migrate/
is already self-ignoring from the first command above; the rewriter re-asserts this before any commit as a second layer.)
IMPORTANT: The file is the handoff mechanism — do NOT rely on
export
to carry the key into later steps. Shell state set in one Bash call does not persist into other calls or into workflow subagents; only a profile-exported variable (the
ENV_KEY_PRESENT
path above) is reliably visible, and even that must be materialized to the file for the baseline runner.
首先,立即创建工件目录并设置自忽略——在任何密钥存在之前,确保密钥永远不会存放在未被忽略的工作树中(即使用户在重写器运行前中止):
bash
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
**密钥绝不能进入此对话(硬性规则)。**请勿要求用户在聊天中粘贴密钥,永远不要在任何命令、问题或输出中回显、打印或插入其值——Agent仅处理文件路径。如果用户未经提示将密钥粘贴到聊天中,请勿使用:告知用户它已成为对话记录的一部分,建议轮换密钥,然后继续以下路径之一。
首先检查密钥是否已存在于shell环境中(每次Bash调用都会从用户配置文件初始化,因此配置文件中导出的密钥对每个调用都可见)。符合POSIX标准——
printenv
在bash和zsh中都有效(
${!VAR}
间接引用仅适用于bash,zsh会报错)。此命令仅打印存在性,绝不打印值:
bash
[ -n "$(printenv "$KEY_ENV_VAR")" ] && echo ENV_KEY_PRESENT || echo ENV_KEY_ABSENT
AskUserQuestion询问: "你有源模型的API密钥吗(例如GPT-4o的OpenAI密钥)?提供密钥可实现并排质量比较。没有密钥的话,评估仅使用绝对评分。"
选项(仅当
ENV_KEY_PRESENT
时提供第一个选项):
  • 使用我环境中已有的
    $KEY_ENV_VAR
    → 通过一个命令将环境变量写入文件——值永远不会出现在对话记录中:
    bash
    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"
  • 我会自己写入文件 → 给用户此命令让他们在自己的终端中运行(不是通过Agent;在Claude Code中
    !
    前缀会在会话中运行)——
    read -rs
    会收集密钥而不回显:
    bash
    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=
前缀的写入值,这会被基线解析器忽略):
bash
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/
已通过上面的第一个命令设置为自忽略;重写器在任何提交前会再次确认这一点,作为第二层保障。)
**重要:**文件是传递机制——请勿依赖
export
将密钥带入后续步骤。在一个Bash调用中设置的shell状态不会持久化到其他调用或工作流子Agent中;只有配置文件中导出的变量(上述
ENV_KEY_PRESENT
路径)是可靠可见的,即使如此也必须将其写入文件供基线运行器使用。

B4 — Bedrock preflight

B4 — Bedrock预飞检查

bash
uv run --project $SCRIPTS python $SCRIPTS/preflight_bedrock.py --region $REGION --models <comma-separated $TARGET_MODELS> --dataset-size 200
(
--dataset-size 200
matches the golden-dataset cap, so the quota warning reflects the worst case. Prefix with
AWS_PROFILE=$AWS_PROFILE_CHOICE
if B2 chose a non-default profile.)
Parse the JSON output. On failure the TOP LEVEL carries
reason
/
detail
(lifted from the first failing model) plus
failing_models
(all failing ids); per-model verdicts are in
models[]
:
  • ok == false
    +
    reason: credentials
    → show the detail (configure/refresh credentials), stop; user re-runs after fixing.
  • ok == false
    +
    reason: model_access
    → model access not enabled in the Bedrock console (NOT an IAM problem): point the user at the console Model access page for the failing models, stop; re-run B4 after they enable it.
  • ok == false
    +
    reason: authz
    → IAM denies
    bedrock:InvokeModel
    : tell user the IAM action to grant; stop.
  • ok == false
    +
    reason: model_unavailable
    → Read the
    resolve-bedrock-model-id
    reference at
    $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md
    and follow its procedure with each ID from
    failing_models
    + region. AskUserQuestion with the candidates: "Use
    <candidate>
    (cross-region inference profile)" / "Paste a different model ID" / "Abort". On a choice, replace the ID in
    $TARGET_MODELS
    and re-run B4.
  • ok == false
    + any other
    reason
    → show
    detail
    and stop.
  • ok == true
    → proceed. Surface any
    quota_warning
    , and any model whose
    reason
    is
    embedding_unprobed
    (embedding family the preflight can't probe — remind the user to confirm model access in the console).

bash
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输出。失败时,顶层包含
reason
/
detail
(来自第一个失败模型)以及
failing_models
(所有失败的ID);每个模型的结果在
models[]
中:
  • ok == false
    +
    reason: credentials
    → 显示详细信息(配置/刷新凭据),停止;用户修复后重新运行。
  • ok == false
    +
    reason: model_access
    → 未在Bedrock控制台启用模型访问(不是IAM问题):将用户指向失败模型的控制台模型访问页面,停止;启用后重新运行B4。
  • ok == false
    +
    reason: authz
    → IAM拒绝
    bedrock:InvokeModel
    :告知用户需要授予的IAM操作;停止。
  • 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
    的模型(预飞检查无法探测的嵌入系列——提醒用户在控制台确认模型访问)。

Phase C — Execute

阶段C — 执行

Phase C dispatches the five plugin agents sequentially via the Agent tool (subagent types
migration-to-aws:llm2bedrock-code-analyzer
,
migration-to-aws:llm2bedrock-log-ingestor
,
migration-to-aws:llm2bedrock-prompt-evaluator
,
migration-to-aws:llm2bedrock-code-rewriter
,
migration-to-aws:llm2bedrock-report-generator
). Each agent writes its result to a file under
$PHASE_DIR = $REPO/.saws-migrate/phase-results/
; you validate every file with the bundled validator before moving on. There is no workflow runtime — the files ARE the state.
阶段C通过Agent工具依次调度五个插件Agent(子Agent类型为
migration-to-aws:llm2bedrock-code-analyzer
migration-to-aws:llm2bedrock-log-ingestor
migration-to-aws:llm2bedrock-prompt-evaluator
migration-to-aws:llm2bedrock-code-rewriter
migration-to-aws:llm2bedrock-report-generator
)。每个Agent将结果写入
$PHASE_DIR = $REPO/.saws-migrate/phase-results/
下的文件;在进入下一步之前,你需要使用捆绑的验证器验证每个文件。没有工作流运行时——文件就是状态。

The validator (used at every step)

验证器(每个步骤都使用)

bash
uv run --project $SCRIPTS python $SCRIPTS/validate_result.py --schema <analysis|ingestion|eval|rewrite|delta-decisions> <file>
  • Exit 0 +
    RESULT=valid CONTROL=ok
    → phase completed; proceed.
  • Exit 0 +
    CONTROL=blocked REASON=<r>
    → blocked flow (below).
  • Exit 0 +
    CONTROL=partial COMPLETED=<n> TOTAL=<m>
    → partial flow (eval only).
  • Exit 1 (
    RESULT=invalid
    + error lines) or exit 2 (file missing) → stateless fixer retry: dispatch a FRESH agent of the same type whose prompt is the original context block + the file path + the validator's verbatim error output + the instruction "fix ONLY the output file at
    <path>
    so it validates; do not redo the phase's work unless a required field is genuinely missing from it". Cap 2 retries per phase; then stop and show the errors.
bash
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>
    → 流程部分完成(仅评估阶段)。
  • 退出码1(
    RESULT=invalid
    + 错误行)或退出码2(文件缺失)→ 无状态修复重试:调度一个相同类型的新Agent,其提示包含原始上下文块+文件路径+验证器的原始错误输出+指令"仅修复
    <path>
    处的输出文件使其通过验证;除非确实缺少必填字段,否则不要重新执行阶段工作"。每个阶段最多重试2次;然后停止并显示错误。

The context block (instantiated at every dispatch)

上下文块(每次调度时实例化)

Build this exact line format (agents parse the labels). Omit lines marked optional when empty:
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>
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>
Prior-phase results are passed as FILE PATHS — never inline their JSON into the prompt.
Helper references (the former helper skills, now under
$HELPERS
).
Agents no longer load skills by name; instead the agent Reads a helper reference at an absolute path you inject. For each dispatch, add ONLY the helper lines that agent uses (per its
# 4
section):
Agent (dispatch)Helper-reference lines to add
C1 llm2bedrock-code-analyzer
behavior-delta-detection reference: $HELPERS/behavior-delta-detection/behavior-delta-detection.md
<br>
resolve-bedrock-model-id reference: $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md
C5 llm2bedrock-code-rewriter
bedrock-known-fixes reference: $HELPERS/bedrock-known-fixes/bedrock-known-fixes.md
<br>
behavior-delta-detection reference: $HELPERS/behavior-delta-detection/behavior-delta-detection.md
<br>
dependency-conflict-resolution reference: $HELPERS/dependency-conflict-resolution/dependency-conflict-resolution.md
C3 llm2bedrock-prompt-evaluator
bedrock-known-fixes reference: $HELPERS/bedrock-known-fixes/bedrock-known-fixes.md
<br>
resolve-bedrock-model-id reference: $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md
<br>
run-source-model-baseline reference: $HELPERS/run-source-model-baseline/run-source-model-baseline.md
C2 llm2bedrock-log-ingestor, C6 llm2bedrock-report-generator(none — these agents load no helpers)
Expand
$HELPERS
to its absolute path (you have
<SKILL_BASE>
) so the subagent — where
${CLAUDE_PLUGIN_ROOT}
is empty — receives a resolvable absolute path.
构建此精确的行格式(Agent会解析标签)。空值时省略标记为可选的行:
Repository: <$REPO>
AWS region: <$REGION>
AWS profile (pass as --profile / AWS_PROFILE= inline on every aws/boto3 invocation): <$AWS_PROFILE_CHOICE — 默认时省略此行>
Target Bedrock model(s): <逗号分隔的$TARGET_MODELS,已应用所有已解析的覆盖>
Migration plan dir: <$MIGRATION_DIR>
Resolved target model id: <主聊天模型的覆盖——无则省略>
Scripts directory (pinned uv toolchain): <$SCRIPTS>
Report date suffix: <运行上下文中保存的后缀——仅C5/C6调度使用>
Source baseline available: <true|false>
Source provider env file: <路径——无则省略>
User-supplied log files: <逗号分隔——无则省略>
Golden dataset cap (max cases the ingestor may emit): 200
Phase results directory: <$PHASE_DIR>
Prior phase results (Read these files): <已验证的阶段JSON文件路径>
Confirmed behavior-delta decisions file (Read it): <$PHASE_DIR/delta-decisions.json — 仅C5使用>
<helper-reference lines — 仅注入此Agent需要的行,如下表>
前期阶段结果以文件路径传递——绝不将其JSON内联到提示中。
**辅助参考(原辅助技能,现位于
$HELPERS
下)。**Agent不再按名称加载技能;而是Agent读取你注入的绝对路径下的辅助参考。每次调度时,仅添加该Agent使用的辅助行(根据其
# 4
部分):
Agent(调度)要添加的辅助参考行
C1 llm2bedrock-code-analyzer
behavior-delta-detection reference: $HELPERS/behavior-delta-detection/behavior-delta-detection.md
<br>
resolve-bedrock-model-id reference: $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md
C5 llm2bedrock-code-rewriter
bedrock-known-fixes reference: $HELPERS/bedrock-known-fixes/bedrock-known-fixes.md
<br>
behavior-delta-detection reference: $HELPERS/behavior-delta-detection/behavior-delta-detection.md
<br>
dependency-conflict-resolution reference: $HELPERS/dependency-conflict-resolution/dependency-conflict-resolution.md
C3 llm2bedrock-prompt-evaluator
bedrock-known-fixes reference: $HELPERS/bedrock-known-fixes/bedrock-known-fixes.md
<br>
resolve-bedrock-model-id reference: $HELPERS/resolve-bedrock-model-id/resolve-bedrock-model-id.md
<br>
run-source-model-baseline reference: $HELPERS/run-source-model-baseline/run-source-model-baseline.md
C2 llm2bedrock-log-ingestor, C6 llm2bedrock-report-generator(无——这些Agent不加载任何辅助参考)
$HELPERS
展开为绝对路径(你已有
<SKILL_BASE>
),以便子Agent(其中
${CLAUDE_PLUGIN_ROOT}
为空)收到可解析的绝对路径。

C0 — Run-context gate (resume safety)

C0 — 运行上下文门(恢复安全性)

The Eval phase makes one paid Bedrock call per golden case (and, with a source key, one paid source-provider call per case). Before any dispatch, tell the user evaluation will invoke Bedrock at their expense, capped at 200 cases.
  1. mkdir -p $PHASE_DIR
    . Build
    $PHASE_DIR/current-context.json
    with exactly these fields (hashes via
    shasum -a 256
    ; key hash is a fingerprint — never store the key value):
json
{
  "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>",
  "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. Stage 0 (post-C5 normalization). If
    $PHASE_DIR/rewrite.json
    exists and validates as a payload (
    CONTROL=ok
    ), do NOT use live
    repo_*
    values. Run three integrity checks: (1)
    rewrite.baseline_parent_sha
    equals the SAVED
    repo_head_sha
    ; (2)
    git rev-parse <rewrite.branch_name>
    equals
    rewrite.branch_tip_sha
    ; (3)
    git status --porcelain
    (with the artifact exclusions) is empty. All pass → copy the saved
    repo_*
    values into current-context verbatim, continue to step 3. Check 2 fails (tip moved) → STOP and AskUserQuestion: "Keep your commits (regenerate report only, with a mixed-authorship note)" / "Reset the branch to the rewriter's tip and regenerate from C6" / "Abort". Check 3 fails (dirty tree) → STOP and ask: commit/stash (then re-check) or discard the edits. Check 1 fails → treat as a full
    repo_*
    mismatch in step 3.
  2. If
    $PHASE_DIR/run-context.json
    exists, compare:
bash
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
    → resume: walk C1→C2→C3→(C4: delta-decisions.json)→C5→(C6: report file) in order; a phase counts completed iff its file validates with
    CONTROL=ok
    (C6: iff
    MIGRATION_REPORT_<saved suffix>.md
    exists while rewrite.json is payload-valid). STOP the walk at the first missing/invalid/control-state file — blocked/partial files route to their flows below, NEVER count as completed. Offer the user "skip completed phases X..Y, resume at Z". Files after an unexplained gap: archive them with the gap.
  • RUN_CONTEXT=mismatch
    → scoped invalidation. Map each MISMATCH line through this table, archive the named units to
    $REPO/.saws-migrate/phase-results-archive/<saved suffix>-$(date +%H%M%S)/
    (a SIBLING of phase-results/ — never nest it inside), then immediately overwrite run-context.json with current-context.json (carrying forward the saved
    report_date_suffix
    unless REPORT itself is being invalidated), then re-run the invalidated phases in order. Tell the user which fields differed and what re-runs.
Mismatched field(s)Archive (units)Keep
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
Units: ANALYSIS = analysis.json · INGESTION = ingestion.json +
.saws-migrate/golden-dataset/
· EVAL = eval.json +
.saws-migrate/eval-results/
(minus cost_compare.py) · REWRITE = rewrite.json + delta-decisions.json · REPORT =
MIGRATION_REPORT_<saved suffix>.md
.
Post-C5 reruns of C1–C3 need the pre-migration tree. If rewrite.json was payload-valid and the table invalidates ANALYSIS/INGESTION/EVAL: confirm with the user that the old migration branch will be discarded (keep-or-reset flow first if the tip moved), then
git checkout <saved repo_branch>
, delete the old branch and the
saws-migrate-baseline
tag, and re-run from C1. If the user declines, stop — re-analyzing a tree that contains the rewrite produces garbage.
  1. No saved run-context → fresh run: write current-context.json as run-context.json, dispatch C1.
评估阶段会为每个黄金案例调用一次付费的Bedrock(如果有源密钥,还会为每个案例调用一次付费的源提供商)。在任何调度之前,告知用户评估将以他们的费用调用Bedrock,上限为200个案例。
  1. mkdir -p $PHASE_DIR
    。构建
    $PHASE_DIR/current-context.json
    ,包含以下精确字段(通过
    shasum -a 256
    生成哈希;密钥哈希是指纹——绝不存储密钥值):
json
{
  "repo_root": "<cd $REPO && pwd -P>",
  "migration_dir": "<$MIGRATION_DIR>",
  "region": "<$REGION>",
  "aws_profile": "<$AWS_PROFILE_CHOICE or \"\">",
  "aws_account": "<B2中的Account>",
  "repo_head_sha": "<git -C $REPO rev-parse HEAD>",
  "repo_branch": "<git -C $REPO rev-parse --abbrev-ref HEAD>",
  "repo_dirty_sha256": "<以下内容的sha256:git status --porcelain + git diff + git diff --cached,每个都带有路径规范 -- . ':(exclude).saws-migrate' ':(exclude).migration' ':(exclude)MIGRATION_REPORT_*.md';当三者都为空时为\"\">",
  "target_models": [{"source_model": "...", "aws_model_id": "...", "use_case": "..."}],
  "resolved_model_overrides": {},
  "source_provider": "<来自B1>",
  "source_baseline_available": <来自B3的true|false>,
  "source_key_sha256": "<.source-provider-env内容的sha256,不存在时为\"\">",
  "log_files": [{"path": "...", "sha256": "..."}],
  "max_golden_cases": 200,
  "assess_design_sha256": "<$MIGRATION_DIR/aws-design-ai.json的sha256>",
  "report_date_suffix": "<date +%Y-%m-%d>",
  "schema_version": 1,
  "plugin_version": "<来自<plugin>/.claude-plugin/plugin.json的版本>"
}
  1. 阶段0(C5后规范化)。如果
    $PHASE_DIR/rewrite.json
    存在并验证为有效负载(
    CONTROL=ok
    ),请勿使用实时
    repo_*
    值。运行三个完整性检查:(1)
    rewrite.baseline_parent_sha
    等于保存的
    repo_head_sha
    ;(2)
    git rev-parse <rewrite.branch_name>
    等于
    rewrite.branch_tip_sha
    ;(3)
    git status --porcelain
    (排除工件)为空。全部通过→将保存的
    repo_*
    值逐字复制到current-context,继续步骤3。检查2失败(分支尖端已移动)→停止并使用
    AskUserQuestion
    询问:"保留你的提交(仅重新生成报告,添加混合作者注释)" / "将分支重置为重写器的尖端并从C6重新生成" / "中止"。检查3失败(脏树)→停止并询问:提交/暂存(然后重新检查)或丢弃编辑。检查1失败→在步骤3中视为完全的
    repo_*
    不匹配。
  2. 如果
    $PHASE_DIR/run-context.json
    存在,进行比较:
bash
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
    → 范围失效。将每个不匹配的行映射到下表,将指定单元归档到
    $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_version所有内容
repo_head_sha / repo_branch / repo_dirty_sha256所有内容
target_models / resolved_model_overridesANALYSIS, EVAL, REWRITE, REPORTINGESTION
log_files / max_golden_cases所有内容
source_key_sha256 / source_baseline_availableANALYSIS, EVAL, REWRITE, REPORTINGESTION
单元: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
**C1–C3在C5后的重新运行需要迁移前的代码树。**如果rewrite.json是有效负载且表格失效ANALYSIS/INGESTION/EVAL:与用户确认旧的迁移分支将被丢弃(如果尖端已移动,先执行保留或重置流程),然后
git checkout <saved repo_branch>
,删除旧分支和
saws-migrate-baseline
标签,然后从C1重新运行。如果用户拒绝,停止——分析包含重写的代码树会产生无效结果。
  1. 无保存的运行上下文→全新运行:将current-context.json写入run-context.json,调度C1。

C1 — Analyzer · C2 — Ingestor · C3 — Evaluator

C1 — 分析器 · C2 — 摄取器 · C3 — 评估器

For each phase in order, dispatch the agent with the context block (listing all prior-phase file paths), then validate its output file:
StepagentTypeOutput fileSchema
C1
migration-to-aws:llm2bedrock-code-analyzer
$PHASE_DIR/analysis.json
analysis
C2
migration-to-aws:llm2bedrock-log-ingestor
$PHASE_DIR/ingestion.json
ingestion
C3
migration-to-aws:llm2bedrock-prompt-evaluator
$PHASE_DIR/eval.json
eval
Blocked flow (
CONTROL=blocked
): resolve with the user per REASON —
  • model_access
    → user enables the model in the Bedrock console (nothing fingerprinted changes; re-dispatch the blocked phase only)
  • model_unresolvable
    → user picks/pastes an ID → record it in
    resolved_model_overrides
    , fold it into the Target line
  • source_key_auth
    → user supplies a new key (re-run B3) or sets baseline unavailable
  • assess_output_missing
    → re-run Phase A, then restart Phase C at C0
After ANY resolution, re-run the C0 recipe (rebuild current-context, apply the invalidation table, overwrite run-context) and re-dispatch from the earliest invalidated phase — the table, not the block location, decides where execution resumes.
Partial flow (eval only,
CONTROL=partial
): AskUserQuestion —
  • Continue remaining cases → re-dispatch the evaluator with the extra context line:
    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
  • Proceed with partial pass rate → re-dispatch the evaluator with:
    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)'
    . Then C4 runs normally.
  • Abort → stop; the files stay on disk for a later C0 resume.
按顺序对每个阶段,使用上下文块(列出所有前期阶段文件路径)调度Agent,然后验证其输出文件:
步骤agentType输出文件Schema
C1
migration-to-aws:llm2bedrock-code-analyzer
$PHASE_DIR/analysis.json
analysis
C2
migration-to-aws:llm2bedrock-log-ingestor
$PHASE_DIR/ingestion.json
ingestion
C3
migration-to-aws:llm2bedrock-prompt-evaluator
$PHASE_DIR/eval.json
eval
阻塞流程
CONTROL=blocked
):根据REASON与用户解决——
  • model_access
    → 用户在Bedrock控制台启用模型(指纹未更改;仅重新调度阻塞的阶段)
  • model_unresolvable
    → 用户选择/粘贴ID → 将其记录到
    resolved_model_overrides
    ,合并到Target行
  • source_key_auth
    → 用户提供新密钥(重新运行B3)或设置基线不可用
  • assess_output_missing
    → 重新运行阶段A,然后从C0重新开始阶段C
任何解决后,重新运行C0流程(重建current-context,应用失效表格,覆盖run-context)并从最早的失效阶段重新调度——表格而非阻塞位置决定执行恢复点。
部分完成流程(仅评估阶段,
CONTROL=partial
):使用AskUserQuestion询问——
  • 继续剩余案例 → 重新调度评估器,添加额外上下文行:
    Resume: raw_results.jsonl已包含完成的案例——仅评估未出现在其中的prompt ID,然后重新评分并覆盖eval.json
  • 以部分通过率继续 → 重新调度评估器,添加:
    Finalize partial: 不再调用Bedrock——对raw_results.jsonl中已有的案例评分,并仅针对这些案例生成完整的eval有效负载,total_cases = 已评分的数量,notes前缀行'partial_coverage: <completed>/<total> cases (throttled)'
    。然后C4正常运行。
  • 中止 → 停止;文件保留在磁盘上供以后通过C0恢复。

C4 — Sidebar (two gates) + persist decisions

C4 — 侧边栏(两个门)+ 持久化决策

Gate (a) — Quality go/no-go. Read
$PHASE_DIR/eval.json
. The threshold is pass rate >= 0.9 AND
source_baseline_quality != 'poor'
(with
no_golden_cases: true
in the notes there is no quality signal — always ask). At or above → proceed silently. Below, AskUserQuestion:
  • Proceed anyway → gate (b)
  • Change target model → record in
    resolved_model_overrides
    , re-run C0 (the table invalidates ANALYSIS/EVAL and execution resumes at C1). Cap: 2 retries.
  • Abort → stop, no code touched.
Gate (a.5) — Rewrite strategy (from migration plan). Read
migration_path
from
$MIGRATION_DIR/aws-design-ai.json
ai_architecture.code_migration.migration_path
. If the value is
"mantle"
, set
rewrite_strategy = "mantle"
. Otherwise (value is
"converse"
,
"gpt-oss"
, or the field is absent), set
rewrite_strategy = "converse"
. No user question needed — the decision was already made during the Assess/Design phase.
Gate (b) — Behavior-delta resolution. For each
analysis.behavior_deltas[]
with
user_visible == true
, AskUserQuestion with the options from the
behavior-delta-detection
reference (Read
$HELPERS/behavior-delta-detection/behavior-delta-detection.md
, and the
source_provider
sub-reference under its
references/
dir).
Persist: write the decisions array (entries
{delta_type, location, resolution_chosen, source}
;
[]
when there were no user-visible deltas) to
$PHASE_DIR/delta-decisions.json
and validate it (
--schema delta-decisions
). The file must exist before C5 — it is what makes a C5 retry or a post-crash resume self-sufficient.
门(a) — 质量通过/不通过。读取
$PHASE_DIR/eval.json
。阈值为
通过率 >= 0.9 且
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
中的
migration_path
ai_architecture.code_migration.migration_path
。如果值为
"mantle"
,设置
rewrite_strategy = "mantle"
。否则(值为
"converse"
"gpt-oss"
或字段缺失),设置
rewrite_strategy = "converse"
。无需询问用户——决策已在评估/设计阶段确定。
**门(b) — 行为差异解决。**对于每个
analysis.behavior_deltas[]
user_visible == true
的条目,使用
behavior-delta-detection
参考中的选项询问用户(读取
$HELPERS/behavior-delta-detection/behavior-delta-detection.md
及其
references/
目录下的
source_provider
子参考)。
**持久化:**将决策数组(条目
{delta_type, location, resolution_chosen, source}
;当没有用户可见差异时为
[]
)写入
$PHASE_DIR/delta-decisions.json
并验证(
--schema delta-decisions
)。C5之前必须存在此文件——它使C5重试或崩溃后恢复能够自给自足。

C5 — Rewriter · C6 — Report

C5 — 重写器 · C6 — 报告

StepagentTypeOutputSchema
C5
migration-to-aws:llm2bedrock-code-rewriter
$PHASE_DIR/rewrite.json
rewrite
C6
migration-to-aws:llm2bedrock-report-generator
MIGRATION_REPORT_<saved suffix>.md
in repo root
(none — file existence is the completion check)
C5's context block includes the
Confirmed behavior-delta decisions file
line and the
Report date suffix
line (from run-context, NOT today's date on a resume). C6's context block lists all four phase-result file paths.
When
rewrite_strategy == "mantle"
, C5's context block ALSO includes:
  • Rewrite strategy: mantle
    (omit this line entirely for Converse — its absence is the signal for the default Converse path)
  • Mantle model map: <source-model> -> <bedrock-model-id>
    — sourced from the plan's
    ai_architecture.bedrock_models[]
    entries (each
    source_model
    aws_model_id
    pair).
步骤agentType输出Schema
C5
migration-to-aws:llm2bedrock-code-rewriter
$PHASE_DIR/rewrite.json
rewrite
C6
migration-to-aws:llm2bedrock-report-generator
仓库根目录中的
MIGRATION_REPORT_<saved suffix>.md
(无——文件存在即为完成检查)
C5的上下文块包含
Confirmed behavior-delta decisions file
行和
Report date suffix
行(来自运行上下文,不是恢复时的当天日期)。C6的上下文块列出所有四个阶段结果文件路径。
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
    对)。

C7 — Render summary

C7 — 渲染摘要

bash
uv run --project $SCRIPTS python $SCRIPTS/render_report.py --phase-results $PHASE_DIR --repo $REPO --date-suffix <saved suffix>
Print the summary. Point the user at
rewrite.branch_name
(usually
bedrock-migration
, but a collision-suffixed variant like
bedrock-migration-2
when they already had that branch) and the report file. Tell them how to undo — substitute the ACTUAL branch name from
rewrite.branch_name
, never a hardcoded one (on a collision run,
bedrock-migration
is the user's own pre-existing branch and deleting it would destroy their work):
To discard:
git checkout <your original branch>
,
git branch -D <rewrite.branch_name>
,
git tag -d saws-migrate-baseline
, and
rm -rf .saws-migrate .migration
removes all migration artifacts (including the API key file).

bash
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 <你的原始分支>
git branch -D <rewrite.branch_name>
git tag -d saws-migrate-baseline
,然后
rm -rf .saws-migrate .migration
删除所有迁移工件(包括API密钥文件)。

Inline mode (platforms without an Agent/subagent dispatch tool)

内联模式(无Agent/子Agent调度工具的平台)

If this platform has no subagent dispatch tool, run phases inline ONE AT A TIME, with a mandatory stop between phases:
  1. Read
    exactly ONE agent definition (
    <plugin>/agents/<name>.md
    ) — never load more than one phase's definition into context at once.
  2. Follow it start-to-finish; write and validate the same phase-result file.
  3. STOP. Report the phase outcome (validator CONTROL line + one-line summary) and ask the user to confirm before loading the next phase's definition. This sidebar is mandatory: it is the context-pressure release valve, and the phase-result file means nothing is lost if the user continues in a fresh session instead.
Warn the user up front that inline mode is slower and context-heavier than subagent dispatch, and that the rewriter phase performs git operations (branch, commits, worktree) directly in this session.

如果此平台没有子Agent调度工具,一次运行一个阶段,阶段之间必须停止:
  1. Read恰好一个Agent定义(
    <plugin>/agents/<name>.md
    )——永远不要同时加载多个阶段的定义到上下文中。
  2. 从头到尾遵循它;写入并验证相同的阶段结果文件。
  3. 停止。报告阶段结果(验证器CONTROL行+一行摘要)并询问用户确认后再加载下一个阶段的定义。此侧边栏是强制性的:它是上下文压力释放阀,阶段结果文件意味着如果用户在新会话中继续,不会丢失任何内容。
提前警告用户内联模式比子Agent调度更慢且上下文负载更重,并且重写器阶段会在此会话中直接执行git操作(分支、提交、工作树)。

Failure handling

故障处理

  • An agent dispatch dies (tool error, terminal failure) → the phase file is missing → validator exit 2 → the stateless fixer-retry path (which, finding no file to fix, re-runs the phase). Do not auto-retry more than the 2-retry cap.
  • User aborts at any gate → confirm no SOURCE CODE was modified (C5 never started if aborted before then). Note that
    .migration/
    and
    .saws-migrate/
    artifacts do exist; show the undo commands from C7 if the user wants them gone.
  • Assess skill fails → show the error and stop. User can re-run
    /migration-to-aws:llm-to-bedrock
    .
  • Agent调度失败(工具错误、终端故障)→ 阶段文件缺失→验证器退出码2→无状态修复重试路径(由于找不到要修复的文件,会重新运行阶段)。自动重试不超过2次上限。
  • 用户在任何门处中止→确认未修改任何源代码(如果在C5之前中止,C5从未启动)。注意
    .migration/
    .saws-migrate/
    工件确实存在;如果用户希望删除它们,显示C7中的撤销命令。
  • 评估技能失败→显示错误并停止。用户可以重新运行
    /migration-to-aws:llm-to-bedrock