automation-sandbox-post-copy-configure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAutomation: Sandbox Post-Copy Configure
自动化:沙箱复制后配置
Apply a Salesforce sandbox post-copy automation JSON config to a target
org. The skill pins the Tooling API sobject and the record-lookup
SOQL filter for the two canonical values it has
been calibrated against (, ); for
any other it derives a candidate from the entry
value and verifies it against the live org's describe endpoint. Every
entry — pinned or derived — must still pass Step B (describe returns
200 with a compound field) before any PATCH is planned.
Entries whose API cannot be identified or verified are surfaced in the
summary and skipped — they are never guessed at.
ConfigurationNameOutboundMessagesRemoteSiteSettingsConfigurationNameMetadata将Salesforce沙箱复制后自动化JSON配置应用到目标组织。该技能针对已校准的两个标准值(、),固定对应的Tooling API sobject以及记录查找SOQL过滤器;对于其他任何,它会从条目值推导候选对象,并针对实时组织的describe端点进行验证。无论条目是固定类型还是推导类型,在计划执行任何PATCH操作前,都必须通过步骤B(describe返回200状态且包含复合字段)。无法识别或验证API的条目会在摘要中显示并被跳过——绝不进行猜测。
ConfigurationNameOutboundMessagesRemoteSiteSettingsConfigurationNameMetadataTool Restrictions
工具限制
Use ONLY the Bash tool to execute CLI commands (, , ). Do NOT
use MCP tools like — ignore them completely; the
compound PATCH pattern this skill requires is not available
through MCP tool wrappers. If the target org alias is not explicitly
named by the user, invoke commands without —
the harness has already set the CLI's default target-org. Never pass
— is not an alias and will fail with
.
sfsf data query --use-tooling-apisf api request restsf org displayexecute_soqlMetadatasf--target-org--target-org defaultdefaultNamedOrgNotFoundErrorSOQL-over-REST () is treated as
an API call — same OAuth session, same authorization boundary as the
subsequent PATCH. No direct database / non-Salesforce SQL access.
sf data query --use-tooling-api ...仅使用Bash工具执行 CLI命令(、、)。请勿使用MCP工具如——完全忽略它们;该技能所需的复合 PATCH模式无法通过MCP工具包装器实现。如果用户未明确指定目标组织别名,执行命令时不要添加参数——运行环境已设置CLI的默认目标组织。绝不要传递——不是有效的别名,会触发错误。
sfsf data query --use-tooling-apisf api request restsf org displayexecute_soqlMetadatasf--target-org--target-org defaultdefaultNamedOrgNotFoundErrorSOQL-over-REST()被视为API调用——使用相同的OAuth会话和授权边界,与后续的PATCH操作一致。不允许直接访问数据库或非Salesforce SQL。
sf data query --use-tooling-api ...STOP — do this before making any API call
停止——执行任何API调用前请完成以下步骤
Never call the org from memory. Before the first request:
- Read the config JSON end-to-end from the exact path the user gave
(default ). Every entry must have all five keys (
./post-copy-config.json,ConfigurationName,Label,Fields,IsActive). If any entry is malformed, abort and surface the file path + entry index — do not partially apply. Do not invent entries. If the file is missing, stop and ask; never fabricate a plan against synthetic labels.ExecutionOrder - For each distinct in the config, run the derivation + describe-verify step (below) before planning any PATCH. An entry whose API cannot be verified must never appear as a planned PATCH — it is rejected up front.
ConfigurationName - Confirm the target org alias with the user unless they supplied one explicitly. This skill mutates a live org — writing to the wrong org (e.g., a production alias set as default) is the most expensive failure mode.
If you announce "I will apply … now" without having read the config
file and run the describe-verify for every distinct
, stop and do those first.
ConfigurationName绝不要凭记忆调用组织接口。首次请求前:
- 从用户指定的精确路径(默认值)完整读取配置JSON。每个条目必须包含全部五个键(
./post-copy-config.json、ConfigurationName、Label、Fields、IsActive)。如果任何条目格式错误,立即终止操作并显示文件路径+条目索引——不要部分应用。请勿自行创建条目。如果文件缺失,停止操作并询问用户;绝不要基于虚构标签制定执行计划。ExecutionOrder - 针对配置中的每个唯一,在计划任何PATCH操作前,先运行推导+验证步骤(如下)。无法验证API的条目绝不能出现在计划的PATCH操作中——需提前拒绝。
ConfigurationName - 除非用户明确提供目标组织别名,否则请与用户确认该信息。该技能会修改实时组织——写入错误的组织(例如设置为默认的生产环境别名)是代价最高的故障场景。
如果您在未读取配置文件且未对每个唯一执行describe验证的情况下宣布“我将立即应用……”,请停止操作并先完成这些步骤。
ConfigurationNamePer-entry procedure (the core of this skill)
每条目执行流程(技能核心)
The skill carries a pinned mapping for the canonical types below, and
a derive-then-verify path for anything else. Follow these steps for
every entry, in order. (describe-verify) is mandatory
regardless of whether the mapping came from the pinned table or the
derive path — its HTTP status must appear in the summary.
Step B该技能针对以下标准类型包含固定映射,对其他类型则采用“推导+验证”流程。请按顺序为每个条目执行以下步骤。无论映射来自固定表还是推导路径,步骤B(describe验证)都是强制性的——其HTTP状态必须显示在摘要中。
Step A — Resolve the Tooling API sobject and lookup filter
步骤A——解析Tooling API sobject和查找过滤器
Pinned canonicals (authoritative — use these exactly, do NOT
substitute a different sobject name):
| ConfigurationName | Tooling API sobject | Record-lookup SOQL |
|---|---|---|
| | |
| | |
For canonical entries use the pinned sobject and SOQL as-is; skip
"derive". Do not invent , , or
variants — plausible-looking but wrong.
OutboundMessageRemoteSiteSettingMasterLabelField-name resolution (overrides + case rule + existence check) is
owned by .
scripts/map-metadata-key.mjsNon-canonical: derive a candidate (usually singular of the
Metadata API type name, sometimes prefixed); Step B rules out wrong
guesses. Use the generic SOQL patterns in Step C.
标准固定映射(权威——请严格使用,不要替换为其他sobject名称):
| ConfigurationName | Tooling API sobject | 记录查找SOQL |
|---|---|---|
| | |
| | |
对于标准条目,请直接使用固定的sobject和SOQL;跳过“推导”步骤。请勿自行创建、或等变体——这些看似合理但实际错误。
OutboundMessageRemoteSiteSettingMasterLabel字段名称解析(覆盖规则+大小写规则+存在性检查)由负责。
scripts/map-metadata-key.mjs非标准条目:推导候选对象(通常是Metadata API类型名称的单数形式,有时带前缀);步骤B会排除错误猜测。使用步骤C中的通用SOQL模式。
Step B — Verify the candidate exists and supports Metadata writes
步骤B——验证候选对象是否存在并支持Metadata写入
For each candidate, GET the describe:
bash
sf api request rest \
"/services/data/v<apiVersion>/tooling/sobjects/<Candidate>/describe/"Accept the candidate only if both are true:
- HTTP 200 (the sobject exists on this org's Tooling API), AND
- The describe response's array contains a field named
fields(compound field — this is what PATCH writes through).Metadata
If no candidate passes both gates, mark the entry
and skip. Do not guess a REST path — the
wrong path 404s in the best case and updates the wrong record in the
worst case.
API_NOT_IDENTIFIED针对每个候选对象,执行describe GET请求:
bash
sf api request rest \\
"/services/data/v<apiVersion>/tooling/sobjects/<Candidate>/describe/"仅当以下两个条件同时满足时,才接受候选对象:
- HTTP状态码为200(该sobject在当前组织的Tooling API中存在),并且
- describe响应的数组中包含名为
fields的字段(复合字段——PATCH操作将通过该字段写入)。Metadata
如果没有候选对象通过这两个检查,标记该条目为并跳过。请勿猜测REST路径——错误路径在最佳情况下会返回404,最坏情况下会更新错误的记录。
API_NOT_IDENTIFIEDStep C — Resolve the record Id (SOQL-over-REST)
步骤C——解析记录ID(SOQL-over-REST)
For pinned canonicals: run the SOQL from the Step A table
verbatim (substituting / ). Do not
substitute a different filter column such as — the
pinned SOQL is the tested-and-correct filter for that sobject.
<Label><Fields.Object>MasterLabelFor non-canonical (derived) sobjects: query the verified sobject
for the record identified by the entry's (and
when present):
LabelFields.Objectbash
undefined标准固定条目:严格执行步骤A表格中的SOQL(替换/)。不要替换为其他过滤列如——固定的SOQL是针对该sobject经过测试的正确过滤方式。
<Label><Fields.Object>MasterLabel非标准(推导)sobject:查询已验证的sobject,找到与条目中(若存在则包含)匹配的记录:
LabelFields.Objectbash
undefinedSOQL to a variable + separate jq call — avoids the most common
将SOQL存入变量 + 单独调用jq — 避免该技能中最常见的shell引号错误。
shell-quoting failure in this skill.
—
SOQL='SELECT Id, FullName FROM <VerifiedSobject> WHERE <UniqueFilter>'
sf data query --use-tooling-api --json --query "$SOQL" \
/tmp/entry-<Slug>-lookup.json ID=$(jq -r '.result.records[0].Id // empty' /tmp/entry-<Slug>-lookup.json)
Pick `<UniqueFilter>` based on the queryable fields shown in the
describe response from Step B. If the row contains a `FullName` field,
SOQL usually rejects a direct `FullName = ...` filter — filter by
whichever direct column the describe surfaces (e.g.
`EntityDefinition.QualifiedApiName`, `DeveloperName`, `SiteName`) and
apply the `FullName` match client-side (`jq -r
'.result.records[] | select(.FullName == "<Object>.<Label>") | .Id'`).
Outcomes:
- Zero rows → `NOT_FOUND` (never fall back to insert).
- Multiple rows after client-side filtering → `AMBIGUOUS` (surface
all Ids in the summary and skip; a wrong Id is worse than no Id).
- Exactly one row → proceed to Step D.SOQL='SELECT Id, FullName FROM <VerifiedSobject> WHERE <UniqueFilter>'
sf data query --use-tooling-api --json --query "$SOQL" \
/tmp/entry-<Slug>-lookup.json ID=$(jq -r '.result.records[0].Id // empty' /tmp/entry-<Slug>-lookup.json)
根据步骤B中describe响应显示的可查询字段选择`<UniqueFilter>`。如果行包含`FullName`字段,SOQL通常会拒绝直接使用`FullName = ...`过滤——请使用describe返回的直接列进行过滤(例如`EntityDefinition.QualifiedApiName`、`DeveloperName`、`SiteName`),然后在客户端进行`FullName`匹配(`jq -r '.result.records[] | select(.FullName == "<Object>.<Label>") | .Id'`)。
结果:
- 零行 → `NOT_FOUND`(绝不回退到插入操作)。
- 客户端过滤后有多行 → `AMBIGUOUS`(在摘要中显示所有ID并跳过;错误ID比无ID更糟糕)。
- 恰好一行 → 进入步骤D。Step D — GET current Metadata, mutate, PATCH back
步骤D——获取当前Metadata、修改并PATCH回传
Metadata"<preserved-from-GET>"Every Step D filename must include the record from Step C
(e.g. ) — phase-parallel entries share
the working directory and would clobber a shared name.
<Id>/tmp/entry-<Id>-meta.json- GET current →
Metadata./tmp/entry-<Id>-meta.json - Resolve the mutation key — for each , run
Fields.<Xxx>. Onnode scripts/map-metadata-key.mjs "<ConfigurationName>" "<ConfigFieldName>" /tmp/entry-<Id>-meta.jsonuse the returned key. On{"status":"OK","key":...}mark the entry and skip.{"status":"FIELD_MAP_UNKNOWN",...} - PATCH — heredoc-build , merge with
/tmp/entry-<Id>-mutation.json(preserves JSON types), PATCH withjq --slurpfile m /tmp/entry-<Id>-mutation.json '. + $m[0] | {Metadata: .}' /tmp/entry-<Id>-meta.json > /tmp/entry-<Id>-patch.json, capture the response body to-b @/tmp/entry-<Id>-patch.json. Full bash in/tmp/entry-<Id>-response.json§Step D. Never usereferences/api_endpoints.md(stringifies booleans/numbers, breaks on special chars). Wrap the PATCH in--arg— retry once on shell/jq quoting failure (non-zero exit before the HTTP call goes out).for attempt in 1 2; do <cmd> && break; done - Classify — . Exit 0 →
node scripts/classify-patch-result.mjs "<httpCode>" /tmp/entry-<Id>-response.json; exit 2 →SUCCESS(parsed error on stdout). 204 with a non-empty body isFAILED.FAILED
Metadata"<preserved-from-GET>"每个步骤D的文件名必须包含步骤C中获取的记录(例如)——并行阶段的条目共享工作目录,共享名称会导致文件覆盖。
<Id>/tmp/entry-<Id>-meta.json- GET当前→
Metadata。/tmp/entry-<Id>-meta.json - 解析修改键 — 针对每个,运行
Fields.<Xxx>。如果返回node scripts/map-metadata-key.mjs "<ConfigurationName>" "<ConfigFieldName>" /tmp/entry-<Id>-meta.json,使用返回的键。如果返回{"status":"OK","key":...},标记该条目并跳过。{"status":"FIELD_MAP_UNKNOWN",...} - PATCH — 通过heredoc构建,使用
/tmp/entry-<Id>-mutation.json进行合并(保留JSON类型),使用jq --slurpfile m /tmp/entry-<Id>-mutation.json '. + $m[0] | {Metadata: .}' /tmp/entry-<Id>-meta.json > /tmp/entry-<Id>-patch.json执行PATCH,将响应体保存到-b @/tmp/entry-<Id>-patch.json。完整的bash命令见/tmp/entry-<Id>-response.json的步骤D。绝不要使用references/api_endpoints.md(会将布尔值/数字转为字符串,特殊字符会导致错误)。将PATCH命令包裹在--arg中——如果shell/jq引号错误(HTTP请求发送前返回非零退出码),重试一次。for attempt in 1 2; do <cmd> && break; done - 分类结果 — 运行。退出码0 →
node scripts/classify-patch-result.mjs "<httpCode>" /tmp/entry-<Id>-response.json;退出码2 →SUCCESS(标准输出会解析错误信息)。状态码204但响应体非空 →FAILED。FAILED
Step E — Verify the change landed
步骤E——验证修改是否生效
Re-read the record to confirm the PATCH stuck:
- If the mutated field is a direct-queryable SOQL column on the
sobject (rare — most -writable fields are not), a SELECT by Id is enough.
Metadata - Otherwise GET the record and inspect the corresponding key inside
.
.Metadata
If the read-back value doesn't match the requested value, record
— the PATCH returned 204 but the effect is not
visible (usually a naming or permission issue).
FAILED_VERIFY重新读取记录以确认PATCH操作成功:
- 如果修改的字段是该sobject上可直接查询的SOQL列(罕见——大多数可通过写入的字段无法直接查询),通过ID执行SELECT即可。
Metadata - 否则,GET该记录并检查中对应的键。
.Metadata
如果读取的值与请求的值不匹配,记录为——PATCH返回204但效果不可见(通常是命名或权限问题)。
FAILED_VERIFYIsActive semantics
IsActive语义
- → apply the PATCH as described in Steps A–E.
IsActive: true - → do not PATCH. Record
IsActive: falsefor the entry and add a bullet under Follow-ups in the summary file listing the entry'sSKIPPED_INACTIVE+ConfigurationNameso the customer notices that a config-declared inactive record was left untouched on the target org.Label
Rationale: means "not active in this sandbox",
not "deactivate the existing record". Silently deactivating a live
integration is a much bigger blast radius than leaving it alone.
IsActive: false- → 按步骤A–E执行PATCH操作。
IsActive: true - → 不执行PATCH。标记该条目为
IsActive: false,并在摘要文件的后续操作部分添加项目符号,列出条目的SKIPPED_INACTIVE+ConfigurationName,以便客户注意到配置中声明为非活动的记录在目标组织中未被修改。Label
原理:表示“在此沙箱中不激活”,而非“停用现有记录”。静默停用实时集成的影响远大于保持原样。
IsActive: falseCanonical output shape (always emit this)
标准输出格式(必须严格遵循)
Single Markdown summary written to
(mode is or ) AND printed to the user. No JSON
side-files (, , etc.) —
inline every planned/actual request in the Markdown.
./post-copy-<mode>-summary.mddry-runapplyplan/phases.jsonrequests/*.request.jsonPhase enumeration is script-owned. Run and consume its output verbatim. Each entry
carries (1-indexed phase number) and (raw
value, for the heading annotation). Sparse
values collapse ( → ordinals ).
entries are pre-marked . See
for the worked example.
node scripts/plan-phases.mjs <config.json>phases[]ordinalexecutionOrder(ExecutionOrder = <raw>)1, 2, 51, 2, 3IsActive:falseSKIP_INACTIVEreferences/execution_phasing.mdFor dry-run entries the column is (em-dash). End the
summary with:
HTTP—No PATCH requests were issued. To apply, re-run without the dry-run flag.Target-org resolution is script-owned. Run ; substitute the returned
into the header. Never emit or
verbatim.
node scripts/resolve-target-org.mjs.alias<env:SF_TARGET_ORG>$SF_TARGET_ORGmarkdown
undefined生成单个Markdown摘要文件保存到(mode为或),同时打印给用户。不要生成JSON辅助文件(、等)——将所有计划/实际请求内联到Markdown中。
./post-copy-<mode>-summary.mddry-runapplyplan/phases.jsonrequests/*.request.json阶段枚举由脚本负责。运行并直接使用其输出。每个条目包含(从1开始的阶段编号)和(原始值,用于标题注释)。稀疏值会自动合并(例如 → 序号)。的条目会被预先标记为。示例见。
node scripts/plan-phases.mjs <config.json>phases[]ordinalexecutionOrder(ExecutionOrder = <raw>)1, 2, 51, 2, 3IsActive:falseSKIP_INACTIVEreferences/execution_phasing.md对于试运行条目,列显示(破折号)。摘要结尾需添加:
HTTP—未发出任何PATCH请求。如需应用,请重新运行并移除试运行标志。目标组织解析由脚本负责。运行;将返回的替换到标题中。绝不要直接输出或。
node scripts/resolve-target-org.mjs.alias<env:SF_TARGET_ORG>$SF_TARGET_ORGmarkdown
undefinedPost-Copy Configure Run — <N> entries <planned|applied> against <alias>
<alias>复制后配置执行 — 针对<alias>
组织<计划|应用>了<N>个条目
<alias>Config file:
Target org:
Mode: <dry-run|apply>
<path><alias>配置文件:
目标组织:
模式:<dry-run|apply>
<path><alias>Phase <ExecutionOrder> — <count> entr(y|ies)
阶段<ExecutionOrder> — <count>个条目
Planned request:
- Method:
PATCH - Path:
/services/data/v<apiVersion>/tooling/sobjects/<VerifiedSobject>/<Id> - Body:
<JSON — the FULL merged Metadata object: every existing key from the Step D-1 GET, overlaid with the mutated keys from the config. Preserved keys with verbose or org-specific values may appear as "<preserved-from-GET>" placeholder strings, but every key must be present. NEVER emit a minimal body containing only the mutated keys.>
| ConfigurationName | Label | Object | Sobject | Describe | Outcome | HTTP |
|---|---|---|---|---|---|---|
| <name> | <lbl> | <obj> | <VerifiedSobject> | <200 or 404> | <outcome> | <code> |
计划请求:
- 方法:
PATCH - 路径:
/services/data/v<apiVersion>/tooling/sobjects/<VerifiedSobject>/<Id> - 请求体:
<JSON — 完整的合并Metadata对象:包含步骤D-1 GET请求返回的所有现有键,叠加配置中的修改键。冗长或组织特定的保留键可能显示为"<preserved-from-GET>"占位符字符串,但必须包含所有键。绝不允许仅包含修改键的极简请求体。>
| ConfigurationName | Label | 对象 | Sobject | Describe | 结果 | HTTP |
|---|---|---|---|---|---|---|
| <name> | <lbl> | <obj> | <VerifiedSobject> | <200或404> | <outcome> | <code> |
Totals
总计
| Outcome | Count |
|---|---|
| <state> | <n> |
| 结果 | 数量 |
|---|---|
| <state> | <n> |
Follow-ups
后续操作
- <bullet per SKIPPED_INACTIVE / API_NOT_IDENTIFIED / AMBIGUOUS / FIELD_MAP_UNKNOWN / NOT_FOUND entry>
Column semantics: `Object` = the entry's `Fields.Object` if present,
`—` otherwise. `Sobject` = the Step A resolved sobject. `Describe` =
the Step B describe HTTP status (`200` for verified, `404` for
`API_NOT_IDENTIFIED`) — mandatory so skipped Step Bs are visible at a
glance. Outcome vocabulary: `SUCCESS`, `NOT_FOUND`, `AMBIGUOUS`,
`API_NOT_IDENTIFIED`, `FIELD_MAP_UNKNOWN`, `FAILED`, `FAILED_VERIFY`,
`SKIPPED_INACTIVE`, `SKIPPED`, `DRY_RUN`, `DELETE_NOT_SUPPORTED`,
`NOT_ATTEMPTED`.
**Scripts are internal.** The `plan-phases.mjs`, `map-metadata-key.mjs`,
`classify-patch-result.mjs`, `resolve-target-org.mjs` invocations are
implementation detail — do **not** inline their raw stdout, JSON
output, or "I ran node …" narration into the summary Markdown or
the printed response. Consume the JSON, use the returned values, and
render the summary in the exact shape above.- <每个SKIPPED_INACTIVE / API_NOT_IDENTIFIED / AMBIGUOUS / FIELD_MAP_UNKNOWN / NOT_FOUND条目对应一个项目符号>
列语义:`对象` = 条目中的`Fields.Object`(若存在),否则为`—`。`Sobject` = 步骤A解析的sobject。`Describe` = 步骤B的describe HTTP状态码(验证通过为`200`,`API_NOT_IDENTIFIED`为`404`)——必须显示,以便一眼看出哪些条目跳过了步骤B。结果词汇:`SUCCESS`、`NOT_FOUND`、`AMBIGUOUS`、`API_NOT_IDENTIFIED`、`FIELD_MAP_UNKNOWN`、`FAILED`、`FAILED_VERIFY`、`SKIPPED_INACTIVE`、`SKIPPED`、`DRY_RUN`、`DELETE_NOT_SUPPORTED`、`NOT_ATTEMPTED`。
**脚本为内部实现**。`plan-phases.mjs`、`map-metadata-key.mjs`、`classify-patch-result.mjs`、`resolve-target-org.mjs`的调用属于实现细节——**不要**将其原始标准输出、JSON输出或“我运行了node……”的描述内联到摘要Markdown或打印给用户的响应中。请解析JSON,使用返回的值,并严格按照上述格式生成摘要。Scope
范围
- In scope: Reading a post-copy config JSON (the shape produced
by ), grouping entries into
automation-sandbox-post-copy-config-generatephases, deriving+verifying the Tooling API sobject for each entry, resolving Ids via SOQL-over-REST, PATCHing via compoundExecutionOrder, and reporting per-entry outcomes.Metadata - Out of scope: Generating the config JSON from an SOP (delegate
to ); deploying metadata XML; running the Async Task Framework (ATF) orchestrator itself (that is the platform-side Java implementation); inventing API paths for
automation-sandbox-post-copy-config-generatevalues whose describe probe fails (surface asConfigurationNameand stop).API_NOT_IDENTIFIED
Every API call is against a live org. Treat this skill as a mutation
tool: prefer first, confirm the target org alias, and
never silently retry a failed entry against a different endpoint.
--dry-run- 包含范围:读取复制后配置JSON(由生成的格式),将条目按
automation-sandbox-post-copy-config-generate分组为阶段,推导+验证每个条目的Tooling API sobject,通过SOQL-over-REST解析ID,通过复合ExecutionOrder执行PATCH,以及报告每条目的结果。Metadata - 排除范围:从标准操作流程(SOP)生成配置JSON(委托给);部署元数据XML;运行异步任务框架(ATF)编排器本身(这是平台端的Java实现);为describe探测失败的
automation-sandbox-post-copy-config-generate值自行创建API路径(标记为ConfigurationName并停止)。API_NOT_IDENTIFIED
所有API调用都针对实时组织。请将该技能视为修改工具:优先使用,确认目标组织别名,绝不要针对不同端点静默重试失败的条目。
--dry-runRequired Inputs
必填输入
Gather or infer before applying:
- Config file path: Path to the JSON produced by
(default:
automation-sandbox-post-copy-config-generatein the current directory). If the file does not exist, stop and ask../post-copy-config.json - Target org alias / username: The CLI alias or username of the target sandbox. Never assume the default org — always confirm. If the user has not supplied one, list available orgs with
sfand ask which to use.sf org list --json - Dry-run flag (optional, default ): Semantics — reads are ALLOWED, writes are FORBIDDEN. Dry-run means the run produces no mutation on the target org; it does NOT mean "no network calls". You MUST still execute every read against the org: the describe probe (Step B,
false), the SOQL Id lookup (Step C,GET), and the record fetch (Step D-1,sf data query) — because the plan's "would-be PATCH body" can only be accurate if the agent has read the currentGETblock from the live record. The ONLY skipped calls are the writes: Step D-3 (Metadata) and Step E (post-PATCH verification). Never fabricate the current Metadata; never emit a body containing invented keys. If a read fails (401, 404,PATCH), surface the error and stop — do not fall back to a from-memory plan. Use dry-run on the first pass unless the user has explicitly asked to apply.NamedOrgNotFoundError - Continue-on-error (optional, default ): When true, a failing entry does not abort the phase — the remaining entries in the phase still execute, and the failure is reported in the summary. When false, a failure aborts execution mid-phase.
true
If the user supplies a clear config path and target alias, proceed
without further questions.
应用前需收集或推断:
- 配置文件路径:由生成的JSON文件路径(默认:当前目录下的
automation-sandbox-post-copy-config-generate)。如果文件不存在,停止操作并询问用户。./post-copy-config.json - 目标组织别名/用户名:目标沙箱的CLI别名或用户名。绝不要假设默认组织——始终确认。如果用户未提供,使用
sf列出可用组织并询问用户选择哪个。sf org list --json - 试运行标志(可选,默认):语义——允许读取,禁止写入。试运行意味着操作不会修改目标组织;并不意味着“无网络调用”。您仍必须针对组织执行所有读取操作:describe探测(步骤B,
false)、SOQL ID查找(步骤C,GET)、记录获取(步骤D-1,sf data query)——因为只有从实时记录读取当前GET块,计划的“拟执行PATCH体”才能准确。唯一跳过的调用是写入操作:步骤D-3(Metadata)和步骤E(PATCH后验证)。绝不要虚构当前Metadata;绝不要输出包含虚构键的请求体。如果读取失败(401、404、PATCH),显示错误并停止——不要回退到基于记忆的计划。除非用户明确要求应用,否则首次运行请使用试运行模式。NamedOrgNotFoundError - 错误继续(可选,默认):设为true时,失败的条目不会终止阶段——阶段中的剩余条目仍会执行,失败情况会在摘要中报告。设为false时,失败会立即终止阶段执行。
true
如果用户提供了明确的配置路径和目标别名,可直接继续操作,无需进一步询问。
Workflow
工作流程
Every step executes real CLI commands via the Bash tool. Do NOT
narrate the plan without actually running the commands — the point of
this skill is to mutate the target org, not to describe how.
sf-
Read and validate the config JSON — load the file with the Read tool. Every entry must be a JSON object with the five top-level keys (,
ConfigurationName,Label,Fields,IsActive). Malformed entries are a hard stop.ExecutionOrder -
Resolve the target org and API version — run. Parse the JSON to confirm the alias resolves and to capture
sf org display --json(e.g.result.apiVersion). Do not print the raw JSON — it contains the access token.62.0 -
Plan phases — runand iterate its
node scripts/plan-phases.mjs <config.json>output. Seephases[]for the concurrency cap.references/execution_phasing.md -
Per-entry describe-verify pass — for each distinct, run Step A + Step B once and cache the verified sobject. Any
ConfigurationNamefailing Step B marks every entry with that name asConfigurationName.API_NOT_IDENTIFIED -
Per-entry apply pass — for each entry inside each phase:
- Entries pre-marked by plan-phases → record
SKIP_INACTIVE, add a Follow-ups bullet, continue.SKIPPED_INACTIVE - Else run Step C (resolve Id), then Step D (GET+mutate+PATCH),
then Step E (verify). If is true, still run Step C and D-1/D-2 so the printed plan reflects the real merged payload — skip only D-3 (the PATCH) and Step E, then record
--dry-run.DRY_RUN
- Entries pre-marked
-
Between phases — wait for every entry in the current phase to complete before starting the next.
-
Write the summary file to disk — the final deliverable is a Markdown file at, following the shape in the "Canonical output shape" section. Also print it to the user. Never write access tokens or full
./post-copy-<mode>-summary.mdoutput. If a URL contains embedded credentials, mask them in the summary (sf org display); the actual PATCH body carries the verbatim URL.https://user:***@host/...
每个步骤都通过Bash工具执行真实的 CLI命令。不要仅描述计划而不实际运行命令——该技能的目的是修改目标组织,而非描述操作方式。
sf-
读取并验证配置JSON — 使用读取工具加载文件。每个条目必须是包含五个顶级键(、
ConfigurationName、Label、Fields、IsActive)的JSON对象。格式错误的条目会导致操作立即终止。ExecutionOrder -
解析目标组织和API版本 — 运行。解析JSON以确认别名有效,并捕获
sf org display --json(例如result.apiVersion)。不要打印原始JSON——其中包含访问令牌。62.0 -
计划阶段 — 运行并遍历其
node scripts/plan-phases.mjs <config.json>输出。并发限制见phases[]。references/execution_phasing.md -
每条目describe验证遍历 — 针对每个唯一的,执行一次步骤A + 步骤B,并缓存已验证的sobject。任何未通过步骤B的
ConfigurationName会将所有对应条目标记为ConfigurationName。API_NOT_IDENTIFIED -
每条目应用遍历 — 针对每个阶段中的每个条目:
- 被plan-phases预先标记为的条目 → 记录为
SKIP_INACTIVE,添加后续操作项目符号,继续执行下一个条目。SKIPPED_INACTIVE - 其他条目执行步骤C(解析ID),然后执行步骤D(GET+修改+PATCH),再执行步骤E(验证)。如果为true,仍需执行步骤C和D-1/D-2,以便打印的计划反映真实的合并负载——仅跳过D-3(PATCH)和步骤E,然后记录为
--dry-run。DRY_RUN
- 被plan-phases预先标记为
-
阶段间等待 — 等待当前阶段的所有条目完成后,再开始下一个阶段。
-
将摘要文件写入磁盘 — 最终交付物是保存到的Markdown文件,严格遵循“标准输出格式”部分的要求。同时打印给用户。绝不要写入访问令牌或完整的
./post-copy-<mode>-summary.md输出。如果URL包含嵌入的凭据,请在摘要中屏蔽(sf org display);实际PATCH请求体保留原始URL。https://user:***@host/...
Rules and Gotchas
规则与注意事项
Load-bearing invariants (never insert; describe-gate every
; compound PATCH preserves the full
existing block; → ; never print
raw access tokens; cap intra-phase concurrency at 5) and the
canonical response for each runtime failure (401 mid-run, 429,
credential-bearing URLs, , describe 404,
zero/many SOQL rows) live in . Read
that file before deviating from the Step A–E procedure.
ConfigurationNameMetadataIsActive: falseSKIPPED_INACTIVEFields.Action = "Delete"references/rules_gotchas.md核心不变量(绝不插入;对每个进行describe验证;复合 PATCH保留完整现有块; → ;绝不打印原始访问令牌;阶段内并发限制为5)以及每个运行时故障的标准响应(运行中401、429、包含凭据的URL、、describe 404、SOQL零行/多行)均在中。在偏离步骤A–E流程前,请先阅读该文件。
ConfigurationNameMetadataIsActive: falseSKIPPED_INACTIVEFields.Action = "Delete"references/rules_gotchas.mdCross-Skill Integration
跨技能集成
| Need | Delegate to |
|---|---|
| Turn a customer SOP into the JSON config this skill consumes | |
| Deploy Salesforce metadata XML (Custom Labels, Named Credentials, etc.) that lives outside the compound-Metadata Tooling API pattern | The matching |
| Create new records that do not yet exist on the target org | |
| Assign permission sets required to run the API calls | |
| 需求 | 委托给 |
|---|---|
| 将客户的标准操作流程(SOP)转换为该技能可使用的JSON配置 | |
| 部署复合Metadata Tooling API模式之外的Salesforce元数据XML(自定义标签、命名凭据等) | 匹配的 |
| 在目标组织中创建不存在的新记录 | 生成元数据XML后使用 |
| 分配运行API调用所需的权限集 | |
Reference File Index
参考文件索引
| File | When to read |
|---|---|
| Steps A–E — the full generic recipe with worked examples (OBM, RSS) and the camelCase-field convention |
| Step 3 (workflow) — the grouping rules and the intra-phase concurrency cap. |
| Step 3 (workflow) — deterministic phase planner (invoke, then read its output) |
| Step D-2 — deterministic Metadata-key resolver (override table + case rule + existence check) |
| Step D-4 — deterministic HTTP-outcome classifier (SUCCESS vs FAILED) |
| Canonical output shape — deterministic target-org alias resolver |
| Step 2 (workflow) — for the session-check recipe and how to handle 401 mid-run |
| Before deviating from Step A–E — load-bearing invariants and canonical runtime-failure responses |
| Steps A–E — the generic template for describe / lookup / GET+PATCH with placeholder keys |
| Step 1 (workflow) — shape of the config JSON this skill consumes |
| Step 7 (workflow) — the shape of the summary report shown to the user |
| 文件 | 读取时机 |
|---|---|
| 步骤A–E — 包含完整通用流程和示例(OBM、RSS)以及驼峰式字段约定 |
| 步骤3(工作流程) — 分组规则和阶段内并发限制。 |
| 步骤3(工作流程) — 确定性阶段规划器(调用后读取其输出) |
| 步骤D-2 — 确定性Metadata键解析器(覆盖表+大小写规则+存在性检查) |
| 步骤D-4 — 确定性HTTP结果分类器(SUCCESS vs FAILED) |
| 标准输出格式 — 确定性目标组织别名解析器 |
| 步骤2(工作流程) — 会话检查流程以及运行中401错误的处理方式 |
| 偏离步骤A–E流程前 — 核心不变量和标准运行时故障响应 |
| 步骤A–E — describe / 查找 / GET+PATCH的通用模板,包含占位符键 |
| 步骤1(工作流程) — 该技能可使用的配置JSON格式示例 |
| 步骤7(工作流程) — 展示给用户的摘要报告格式示例 |