@salesforce/afv-skills 1.40.0 → 1.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/package.json +1 -1
  2. package/skills/automation-flow-generate/SKILL.md +32 -43
  3. package/skills/experience-portal-create/SKILL.md +497 -0
  4. package/skills/experience-portal-create/assets/report-template.md +30 -0
  5. package/skills/experience-portal-create/references/mcp-invocation.md +288 -0
  6. package/skills/experience-portal-create/references/post-creation-activate-publish.md +165 -0
  7. package/skills/experience-portal-create/references/templates.md +253 -0
  8. package/skills/experience-ui-bundle-features-generate/SKILL.md +5 -1
  9. package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -0
  10. package/skills/experience-ui-bundle-frontend-generate/references/page.md +1 -0
  11. package/skills/platform-datamask-run/SKILL.md +345 -0
  12. package/skills/platform-datamask-run/references/api-surface.md +130 -0
  13. package/skills/platform-datamask-run/references/policy-authoring.md +185 -0
  14. package/skills/platform-datamask-run/references/run-and-abort.md +116 -0
  15. package/skills/platform-datamask-run/scripts/poll-job.sh +115 -0
  16. package/skills/platform-dataspace-access-configure/SKILL.md +51 -3
  17. package/skills/platform-dataspace-access-configure/scripts/inspect-dataspace-scopes.sh +56 -0
  18. package/skills/platform-lightning-type-widget-coordinate/references/build-plan-format.md +1 -0
  19. package/skills/platform-sandbox-configure/SKILL.md +17 -2
  20. package/skills/platform-trial-org-create/SKILL.md +175 -0
  21. package/skills/platform-trial-org-create/examples/create_request.json +9 -0
  22. package/skills/platform-trial-org-create/examples/error_response.json +41 -0
  23. package/skills/platform-trial-org-create/examples/success_response.json +27 -0
  24. package/skills/platform-trial-org-create/references/error_codes.md +42 -0
  25. package/skills/platform-trial-org-create/references/signup_request_fields.md +69 -0
  26. package/skills/platform-trial-org-create/scripts/create_signup_request.sh +175 -0
  27. package/skills/platform-trial-org-create/scripts/get_signup_request.sh +155 -0
  28. package/skills/platform-widget-generate/SKILL.md +47 -6
  29. package/skills/platform-widget-generate/examples/conditional.json +3 -3
  30. package/skills/platform-widget-generate/examples/list-with-foreach.json +2 -2
  31. package/skills/platform-widget-generate/examples/single-object.json +2 -2
  32. package/skills/platform-widget-generate/references/widget-bundle-layout.md +1 -1
  33. package/skills/service-agentforce-channel-configure/SKILL.md +271 -0
  34. package/skills/service-agentforce-channel-configure/references/agent-wiring.md +97 -0
  35. package/skills/service-agentforce-channel-configure/references/channel-branch-email.md +145 -0
  36. package/skills/service-agentforce-channel-configure/references/channel-branch-voice.md +69 -0
  37. package/skills/service-agentforce-channel-configure/references/channel-types.md +61 -0
  38. package/skills/service-agentforce-channel-configure/references/live-traffic-gate.md +86 -0
  39. package/skills/service-agentforce-channel-configure/references/queue-resolution.md +135 -0
  40. package/skills/service-agentforce-channel-configure/references/routing-flow.md +384 -0
  41. package/skills/service-catalog-template-deploy/SKILL.md +310 -0
  42. package/skills/service-catalog-template-deploy/references/cli-invocation.md +258 -0
  43. package/skills/service-catalog-template-deploy/scripts/activate-verify.mjs +164 -0
  44. package/skills/service-catalog-template-deploy/scripts/build-deploy-payload.mjs +94 -0
  45. package/skills/service-catalog-template-deploy/scripts/resolve-template.mjs +331 -0
  46. package/skills/service-catalog-template-search/SKILL.md +212 -0
  47. package/skills/service-catalog-template-search/references/cli-invocation.md +128 -0
  48. package/skills/service-catalog-template-search/scripts/classify-catalog.mjs +205 -0
  49. package/skills/service-concierge-portal-generate/SKILL.md +126 -0
  50. package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1428 -0
  51. package/skills/service-digital-engagement-channel-configure/SKILL.md +46 -6
  52. package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +2 -1
  53. package/skills/service-digital-engagement-channel-configure/examples/asa_agent_channel.xml +4 -1
  54. package/skills/service-helpagent-coordinate/README.md +8 -2
  55. package/skills/service-helpagent-coordinate/SKILL.md +126 -130
  56. package/skills/service-helpagent-coordinate/assets/help-agent-spec.md +70 -53
  57. package/skills/service-helpagent-coordinate/references/agent-script.md +571 -457
  58. package/skills/service-helpagent-coordinate/references/channel-voice.md +38 -9
  59. package/skills/service-helpagent-coordinate/references/channel-web-chat.md +173 -49
  60. package/skills/service-helpagent-coordinate/references/output-report-format.md +126 -0
  61. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +153 -0
  62. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +79 -0
  63. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +35 -0
  64. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +271 -0
  65. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/references/cli-invocation.md +265 -0
  66. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-enable-plan.mjs +220 -0
  67. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-final-report.mjs +102 -0
  68. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/record-enable-result.mjs +73 -0
  69. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/SKILL.md +206 -0
  70. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/references/cli-invocation.md +194 -0
  71. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/scripts/classify-readiness.mjs +223 -0
  72. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +45 -7
  73. package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +45 -5
  74. package/skills/service-itsm-agentic-setup-configure/SKILL.md +116 -0
  75. package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +64 -0
  76. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +158 -0
  77. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/cli-invocation.md +361 -0
  78. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/error-taxonomy.md +44 -0
  79. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/reactivation.md +66 -0
  80. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +66 -0
  81. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/specialized-templates.md +148 -0
  82. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +169 -0
  83. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/build-create-body.mjs +116 -0
  84. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-agent-existence.mjs +185 -0
  85. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-preflight.mjs +168 -0
  86. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/create-scratch-dir.mjs +58 -0
  87. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +197 -0
  88. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +186 -0
  89. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/action-availability.md +51 -0
  90. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/cli-invocation.md +345 -0
  91. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/error-taxonomy.md +44 -0
  92. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/reactivation.md +63 -0
  93. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +44 -0
  94. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +149 -0
  95. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/build-create-body.mjs +110 -0
  96. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-action-availability.mjs +201 -0
  97. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-activate-result.mjs +135 -0
  98. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-agent-existence.mjs +194 -0
  99. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-preflight.mjs +158 -0
  100. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/create-scratch-dir.mjs +58 -0
  101. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +191 -0
  102. package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +133 -0
  103. package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +71 -0
  104. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +308 -0
  105. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +23 -0
  106. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +193 -0
  107. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +57 -0
  108. package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +394 -0
  109. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md +266 -0
  110. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/cli-invocation.md +106 -0
  111. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/helper-contracts.md +142 -0
  112. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/permset-topology.md +82 -0
  113. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-action-surface.mjs +137 -0
  114. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-assignment-state.mjs +99 -0
  115. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-permset-availability.mjs +120 -0
  116. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/resolve-target-user.mjs +86 -0
  117. package/skills/service-itsm-agentic-setup-uel-user-create/SKILL.md +284 -0
  118. package/skills/service-itsm-agentic-setup-uel-user-create/references/mcp-invocation.md +302 -0
  119. package/skills/service-itsm-channels-coordinate/SKILL.md +472 -0
  120. package/skills/service-itsm-incident-mgmt-configure/SKILL.md +212 -0
  121. package/skills/service-itsm-incident-mgmt-configure/references/mcp-invocation.md +225 -0
  122. package/skills/service-itsm-incident-priority-configure/SKILL.md +53 -12
  123. package/skills/service-itsm-swarming-configure/SKILL.md +212 -0
  124. package/skills/service-itsm-teams-configure/SKILL.md +395 -0
  125. package/skills/service-itsm-teams-configure/references/azure-credential-population.md +213 -0
  126. package/skills/service-itsm-teams-configure/references/gotchas.md +23 -0
  127. package/skills/service-itsm-teams-coordinate/SKILL.md +175 -0
  128. package/skills/service-itsm-teams-coordinate/examples/output-templates.md +85 -0
  129. package/skills/service-itsm-teams-debug/SKILL.md +144 -0
  130. package/skills/service-itsm-teams-debug/references/configuration-checklists.md +277 -0
  131. package/skills/service-itsm-teams-debug/references/report-generation.md +95 -0
  132. package/skills/service-itsm-teams-employee-agent-configure/SKILL.md +139 -0
  133. package/skills/service-itsm-teams-employee-agent-configure/assets/Teams_AgentForce.EmbeddedServiceConfig-meta.xml +43 -0
  134. package/skills/service-itsm-teams-employee-agent-configure/references/teams-embedded-employee-agent.md +480 -0
  135. package/skills/service-itsm-teams-itdesk-configure/SKILL.md +232 -0
  136. package/skills/service-itsm-teams-itservice-configure/SKILL.md +391 -0
@@ -0,0 +1,361 @@
1
+ # CLI invocation reference — Create an IT Service Employee Agent (broad or specialized)
2
+
3
+ This skill uses the **Salesforce CLI (`sf`)** as its only transport:
4
+ `sf api request rest` for the NGA Connect API reads/writes, `sf data query` for the
5
+ `BotDefinition` idempotency + verify SOQL, and two Node helper scripts for the
6
+ deterministic decisions. It extracts no access tokens.
7
+
8
+ The agent is created as a **Next-Gen Authoring (NGA) native agent** via the
9
+ `/nextgen-authoring/*` Connect API — **not** via the legacy
10
+ `/connect/service-itsm/createAgent` route. That legacy route creates a
11
+ Setup-page bot that shows an external-link icon in Agentforce Studio and is
12
+ also listed on the old Setup > Agentforce Agents page; the NGA bundle pipeline
13
+ below produces an agent that is native to Agentforce Studio's Agents list with
14
+ no external-link icon, matching the platform's own Employee agents.
15
+
16
+ **Broad vs specialized:** the `agent-templates?agentType=AgentforceEmployeeAgent`
17
+ endpoint returns the broad `IT Service Employee` template plus ~78 specialized
18
+ Employee templates as siblings in `data[]`. This flow is byte-identical between
19
+ the two — the only difference is which `masterLabel` is passed to the
20
+ classifier and the body-builder (Phase 1 and Phase 4). See
21
+ `../references/specialized-templates.md` for the picker menu and the exclusion
22
+ list (non-Employee entries the endpoint leaks in).
23
+
24
+ ## Why `sf api request rest` / `sf data query`, never curl + token
25
+
26
+ Both commands authenticate using the CLI's stored session for the
27
+ `--target-org` alias — the CLI mints/refreshes the token internally and never
28
+ exposes it. **Do not** do:
29
+
30
+ <!-- skill-validate: ignore -->
31
+ ```bash
32
+ # FORBIDDEN — leaks a bearer token into shell context, bypasses the CLI session
33
+ TOKEN=$(sf org display --json -o <alias> | jq -r '.result.accessToken')
34
+ curl -X POST -H "Authorization: Bearer $TOKEN" .../nextgen-authoring/bundles
35
+ ```
36
+
37
+ Every call this skill makes is a plain `/services/data/v67.0/...` Connect API or
38
+ `/query` path — exactly what `sf api request rest` and `sf data query` proxy.
39
+ There is no reason to fall back to curl.
40
+
41
+ ## Target org, API version, and the `--json` split
42
+
43
+ - **Target org**: always `--target-org <alias>` (or `-o <alias>`). Resolve the
44
+ alias from the user or the default org (`sf config get target-org`).
45
+ - **API version**: pinned in the URL path (`/services/data/v67.0/...`). Do not
46
+ hand-edit it below `metadata.minApiVersion` (`67.0`).
47
+ - **`--json` rule** — the two commands differ:
48
+ - `sf api request rest` prints the **raw** Connect response body to stdout;
49
+ do **not** add `--json` (it is unsupported on some Connect endpoints and
50
+ errors). The stdout body is already JSON.
51
+ - `sf data query --json` **does** wrap results in a `{status, result:{records[]}}`
52
+ envelope — that envelope is exactly what `scripts/classify-agent-existence.mjs`
53
+ expects. Always pass `--json` to `sf data query`.
54
+
55
+ ## Thread the collected developerName / label through EVERY call
56
+
57
+ The `<developerName>` and `<label>` are collected from the user (defaults
58
+ `IT_Service_Employee_Agent` / `IT Service Employee Agent`). The **same**
59
+ `<developerName>` must appear in the idempotency SOQL, the `createBundleWithVersion`
60
+ body's outer `apiName` AND its `resourceContent`'s internal `config.developer_name`,
61
+ and the verify SOQL — otherwise a custom name creates one agent while the
62
+ idempotency/verify reads check a different one, or the bundle's outer identity
63
+ diverges from the script's internal identity.
64
+
65
+ ## The source content — the legacy template's `agentScript` field
66
+
67
+ The legacy `agent-templates` read (still used, read-only) returns each
68
+ template's full **Agent Script** (AFScript) in an `agentScript` field,
69
+ HTML-entity-encoded (sometimes double-encoded). This is the SAME content
70
+ format an NGA bundle version's `resourceContent` expects — there is no
71
+ separate "NGA template catalog" endpoint; the fix simply routes this existing
72
+ read's content into the NGA bundle pipeline instead of the legacy
73
+ `createAgent` call.
74
+
75
+ ```text
76
+ GET /services/data/v67.0/connect/service-itsm/agent-templates?agentType=AgentforceEmployeeAgent
77
+ ```
78
+
79
+ Response: `{data:[{id, masterLabel, agentScript, isInstalled, isActivated, botDefinitionId, ...}]}` — 79 entries on a fully-provisioned org (the broad `IT Service Employee` template + ~78 specialized Employee templates as siblings).
80
+ The classifier (`scripts/classify-preflight.mjs`) finds the item whose
81
+ `masterLabel` matches the resolved target (`"IT Service Employee"` for the
82
+ default broad path, or the picked specialized `masterLabel` for a specialized
83
+ path) and confirms `agentScript` is a non-empty string. `scripts/build-create-body.mjs`
84
+ re-reads the same captured file, re-locates the match, and does the actual
85
+ decode + substitution (see below) — the classifier only confirms presence, it
86
+ does not re-emit the ~70KB script content on stdout.
87
+
88
+ ## The NGA Connect API
89
+
90
+ All three calls live under `/nextgen-authoring/`, owning team **Agentforce
91
+ Platform**. Org access check: `NextGenAuthoring.orgHasNextGenAgentAuthoringEnabled
92
+ && NextGenAuthoring.userCanAccessNextGenAgentAuthoring`. User access check:
93
+ `NextGenAuthoring.userCanAccessAuthoringBundle` (create) /
94
+ `NextGenAuthoring.userCanEditAuthoringBundle` (publish/activate).
95
+
96
+ | Route | Method | Purpose |
97
+ |-------|--------|---------|
98
+ | `/services/data/v67.0/nextgen-authoring/bundles` | POST | `createBundleWithVersion` — create the bundle + its first DRAFT version from an Agent Script |
99
+ | `/services/data/v67.0/nextgen-authoring/bundle-versions/{bundleVersionId}/publish` | POST | `publishBundleVersion` — publish the version, creating the underlying `BotDefinition`/`BotVersion` |
100
+ | `/services/data/v67.0/nextgen-authoring/bundle-versions/{bundleVersionId}/activate` | POST | `activateBundleVersion` — activate the published version |
101
+ | `/services/data/v67.0/nextgen-authoring/bundles` | GET | List bundles (optional post-hoc check for `isLegacy:false`) |
102
+
103
+ > **The legacy `createAgent` / `create-agents` / `activate-agents` routes under
104
+ > `/connect/service-itsm/` are NOT part of this flow.** They create a
105
+ > Setup-page bot with an external-link icon in Agentforce Studio — the wrong
106
+ > kind of agent. Do not fall back to them even on an NGA-route error; surface
107
+ > the error and stop instead.
108
+
109
+ ## Preflight — Studio access + template's Agent Script presence (one classifier)
110
+
111
+ Capture both reads, then let `scripts/classify-preflight.mjs` make the
112
+ deterministic decisions (do not read `hasAccess` or search `data[]` in prose — A9):
113
+
114
+ ```bash
115
+ sf api request rest "/services/data/v67.0/agentforce-studio/access/Agents" \
116
+ --method GET --target-org <alias> > ${SCRATCH_DIR}/studio-access.json 2>${SCRATCH_DIR}/studio-access.err || true
117
+ sf api request rest "/services/data/v67.0/connect/service-itsm/agent-templates?agentType=AgentforceEmployeeAgent" \
118
+ --method GET --target-org <alias> > ${SCRATCH_DIR}/agent-templates.json 2>${SCRATCH_DIR}/agent-templates.err || true
119
+ node "<skill_dir>/scripts/classify-preflight.mjs" ${SCRATCH_DIR}/studio-access.json ${SCRATCH_DIR}/agent-templates.json "<masterLabel>"
120
+ ```
121
+
122
+ Pass the resolved `<masterLabel>` — `"IT Service Employee"` for the default
123
+ broad path, or the picked specialized `masterLabel` (e.g. `"Password Manager Assistance"`)
124
+ for a specialized path. The classifier matches `data[]` on `masterLabel`
125
+ case-insensitively.
126
+
127
+ **Studio access** body: `{ "hasAccess": true, "productName": "Agents" }`. The
128
+ classifier maps `hasAccess=true`→PASS, `false`→FAIL (offer the hand-off to
129
+ `service-itsm-agentic-setup-agentforce-studio-validate`), a **confirmed** `404`
130
+ (gate not wired, expected on scratch orgs)→CANNOT-CONFIRM (does not block — a
131
+ successful create/publish/activate is authoritative), and any other parseable
132
+ error body (`401`/`403`/unexpected)→**ERROR** (surface the raw response and
133
+ stop — do not treat an auth/permission failure as an unwired gate). The
134
+ product in the path must be `Agents` (any other value ⇒ `400 Invalid product name`).
135
+
136
+ **agent-templates**: the `agentType` query param is **required** — omitting it
137
+ returns `400 MISSING_ARGUMENT: agentType`; the value is `AgentforceEmployeeAgent`
138
+ for every Employee template (broad OR specialized — a wrong value returns an
139
+ empty `data[]`, since specialized Employee templates are siblings in the same
140
+ response, not behind different `agentType`s). The classifier finds the item
141
+ whose `masterLabel` matches the label arg — either the default broad
142
+ `"IT Service Employee"` or a user-picked specialized `masterLabel` from
143
+ `../references/specialized-templates.md` — and confirms its `agentScript`
144
+ field is a non-empty string; that field, not `id`, is what Phase 4 consumes.
145
+ Empty/no-match `data[]` ⇒ `template.signal=FAIL`; a `404` ⇒ CANNOT-CONFIRM —
146
+ hand off to the readiness check; a match with no/empty `agentScript` ⇒
147
+ CANNOT-CONFIRM (nothing to build the NGA bundle from).
148
+
149
+ Classifier output:
150
+
151
+ ```json
152
+ {
153
+ "studio": { "hasAccess": true, "signal": "PASS|FAIL|CANNOT-CONFIRM|ERROR", "reason": "..." },
154
+ "template": { "present": true, "id": "svc_emp_intelligence__ItEmployeeAssistance", "hasAgentScript": true, "botDefinitionId": "0Xx...", "signal": "PASS|FAIL|CANNOT-CONFIRM", "reason": "..." },
155
+ "verdict": "READY | NOT-READY | CANNOT-CONFIRM | ERROR",
156
+ "reasons": ["..."]
157
+ }
158
+ ```
159
+
160
+ `template.botDefinitionId` is copied from the matched `agent-templates` row. **`botDefinitionId` is the PRIMARY Phase-2 idempotency key** — a populated value means the template has already been instantiated into a live `BotDefinition` (the broad Employee agent ships pre-provisioned this way); `null` means either it has not been created yet OR it was created by this skill (a self-created agent never back-fills the template row — see Phase 2). Capture `botDefinitionId` for the Phase-2 read below and always carry the collected `<developerName>` as the fallback key. (`isInstalled`/`isActivated` are no longer emitted: they ride the same AgentTemplate join as `botDefinitionId`, so they read false for self-created agents and nothing consumes them.)
161
+
162
+ `verdict=ERROR` (`studio.signal="ERROR"` — a parseable non-404 Studio-access
163
+ error, e.g. `401`/`403`) ⇒ surface the raw error and stop; takes priority over
164
+ template state so a present template cannot outrun a failed prerequisite read.
165
+ `verdict=NOT-READY` (studio FAIL or template FAIL) ⇒ hand off / stop.
166
+ `verdict=READY` ⇒ proceed to Phase 2. It exits `0` on usable args.
167
+
168
+ ## Enumerate the existing agent — SOQL on `BotDefinition` BY Id (falling back to DeveloperName)
169
+
170
+ Idempotency is keyed **PRIMARILY** on the template's `botDefinitionId` (from the
171
+ Phase-1 row) and **FALLS BACK** to the collected `<developerName>`. The broad
172
+ "IT Service Employee" agent ships pre-provisioned+active under DeveloperName
173
+ `IT_Service_Employee`, which never matches this skill's default guess
174
+ `IT_Service_Employee_Agent`; a name-only read false-negatives on THAT agent
175
+ (`exists:false`) and the create then collides on `apiName` with
176
+ `DUPLICATE_VALUE` — so `botDefinitionId` (the platform's authoritative link from
177
+ the template to the `BotDefinition` it was instantiated into) is the primary key.
178
+ But that link is back-filled onto the template row **only** for pre-provisioned
179
+ agents: an agent THIS skill creates never stamps `templateName`, so its template
180
+ `botDefinitionId` stays `null` on every later read. For that self-created case a
181
+ `DeveloperName`-keyed read is the reliable guard — so use it as the fallback,
182
+ never short-circuit straight to create when `botDefinitionId` is absent.
183
+
184
+ - **`botDefinitionId` empty/null** (template row never joined — either not
185
+ created yet, or created by this skill) ⇒ fall back to a DeveloperName-keyed
186
+ read and let the classifier match on it:
187
+ ```bash
188
+ sf data query -q "SELECT Id,DeveloperName,MasterLabel,(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1) FROM BotDefinition WHERE DeveloperName='<developerName>'" \
189
+ --target-org <alias> --json > ${SCRATCH_DIR}/bot-existing.json 2>${SCRATCH_DIR}/bot-existing.err || true
190
+ node "<skill_dir>/scripts/classify-agent-existence.mjs" ${SCRATCH_DIR}/bot-existing.json "" "<developerName>"
191
+ ```
192
+ - **`botDefinitionId` present** ⇒ read the `BotDefinition` by Id **`OR` by the
193
+ collected `<developerName>`** in one query, then classify. The `OR DeveloperName=`
194
+ clause catches a **dangling** link — a `botDefinitionId` whose target row was
195
+ since deleted: the by-Id half returns nothing, the live same-name agent still
196
+ surfaces, and the classifier falls back to it (`matchedBy:"developerName"`)
197
+ rather than concluding `exists:false` and colliding with `DUPLICATE_VALUE`:
198
+ ```bash
199
+ sf data query -q "SELECT Id,DeveloperName,MasterLabel,(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1) FROM BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'" \
200
+ --target-org <alias> --json > ${SCRATCH_DIR}/bot-existing.json 2>${SCRATCH_DIR}/bot-existing.err || true
201
+ node "<skill_dir>/scripts/classify-agent-existence.mjs" ${SCRATCH_DIR}/bot-existing.json "<botDefinitionId>" "<developerName>"
202
+ ```
203
+
204
+ Only when **both** `botDefinitionId` and `<developerName>` are absent does the
205
+ classifier return `exists:false` without reading a query file — in practice the
206
+ collected `<developerName>` is always present, so the fallback read always runs.
207
+
208
+ The `BotVersions` subquery (child relationship on `BotDefinition`) is what lets
209
+ the classifier see the latest version's `Status` — omit it and
210
+ `latestVersionStatus`/`needsActivation` come back `null`/`false` even when the
211
+ existing agent is actually inactive. The classifier prints
212
+ `{ exists, count, matchedBy, agentId, botDefinitionId, developerName, latestVersionId, latestVersionStatus, needsActivation }`
213
+ (`matchedBy` is `"botDefinitionId"` | `"developerName"` | `null`; `developerName`
214
+ is the ACTUAL live agent's DeveloperName read from the record — surface it in the
215
+ report instead of the collected guess):
216
+ - `exists:false` ⇒ proceed to create.
217
+ - `exists:true` and `needsActivation:false` (latest version `Active`) ⇒
218
+ **ALREADY-CREATED** (skip the entire create/publish/activate sequence).
219
+ - `exists:true` and `needsActivation:true` (latest version `Inactive`) ⇒ do
220
+ **not** create a duplicate — take the reactivation path documented in
221
+ `references/reactivation.md` (direct `BotVersion` activation, skips
222
+ create + publish).
223
+ - **Exit 3** ⇒ the query itself failed (auth error, malformed SOQL) — surface
224
+ the raw CLI error and stop; do **not** assume the agent is absent.
225
+
226
+ On any `exists:true` hit reached via the `matchedBy:"developerName"` fallback
227
+ (the template `botDefinitionId` was `null`, or present-but-dangling), Phase 7
228
+ verifies the agent using the classifier's returned live `agentId` /
229
+ `botDefinitionId` — the actual matched `BotDefinition.Id` — **never** the Phase-1
230
+ template `botDefinitionId`, so the verify read never degrades to `WHERE Id=''`
231
+ and never false-fails after a successful skip or reactivation.
232
+
233
+ Use the skill's **absolute** `<skill_dir>` in the `node` invocation — a bare
234
+ `./scripts/...` resolves against the shell CWD, not the skill dir.
235
+
236
+ ## Create the NGA bundle — `createBundleWithVersion`
237
+
238
+ ```bash
239
+ node "<skill_dir>/scripts/build-create-body.mjs" ${SCRATCH_DIR}/agent-templates.json "<masterLabel>" "<developerName>" "<label>" ${SCRATCH_DIR}/create-bundle-body.json
240
+ sf api request rest "/services/data/v67.0/nextgen-authoring/bundles" \
241
+ --method POST \
242
+ --body @${SCRATCH_DIR}/create-bundle-body.json \
243
+ --target-org <alias> > ${SCRATCH_DIR}/create-bundle.json 2>${SCRATCH_DIR}/create-bundle.err || true
244
+ ```
245
+
246
+ Pass the same resolved `<masterLabel>` used in Phase 1 (broad or specialized).
247
+ `build-create-body.mjs` re-reads `${SCRATCH_DIR}/agent-templates.json` (the SAME file
248
+ captured in Phase 1), re-locates the item whose `masterLabel` matches the arg
249
+ (case-insensitive), and:
250
+ 1. Fully HTML-decodes its `agentScript` — named entities (`&amp;`, `&quot;`,
251
+ `&#39;`, `&lt;`, `&gt;`) AND numeric entities (`&#(\d+);` →
252
+ `String.fromCharCode`), applied in a loop (up to 4 passes) to fully unwind
253
+ double-encoding. A naive single-pass decode leaves artifacts (e.g.
254
+ `&amp;quot;`, an undecoded `&#92;` for a literal backslash) that break
255
+ AFScript parsing.
256
+ 2. Substitutes the script's `config.developer_name` / `config.agent_label`
257
+ with the collected `<developerName>` / `<label>` via a regex replace on the
258
+ `developer_name: "..."` / `agent_label: "..."` lines. If either
259
+ substitution doesn't land (pattern not found), the script exits 3 rather
260
+ than silently building a body with the wrong internal identity.
261
+ 3. Writes `{ apiName: <developerName>, label: <label>, assets: [{ resourceName:
262
+ "agentDefinition", resourceType: "agentDefinition", sections: [],
263
+ resourceContent: <decoded+substituted script> }] }` to the output path.
264
+
265
+ Response on success — a bundle-version detail:
266
+
267
+ ```json
268
+ {
269
+ "apiName": "IT_Service_Employee_Agent",
270
+ "label": "IT Service Employee Agent",
271
+ "bundleId": "1bY...",
272
+ "id": "1bZ...",
273
+ "versionStatus": "DRAFT",
274
+ "assets": [ { "resourceName": "agentDefinition", "resourceType": "agentDefinition", "resourceContent": "...", "sections": [] } ],
275
+ "publishedBotId": null,
276
+ "publishedBotVersionId": null
277
+ }
278
+ ```
279
+
280
+ **Capture `id` — that is the `bundleVersionId`** used in the publish/activate
281
+ calls below. `bundleId` is the bundle's own Id, not the version's; passing it
282
+ to `/bundle-versions/{...}` returns a 404.
283
+
284
+ Common errors:
285
+
286
+ | HTTP | Error code | Meaning | Action |
287
+ |------|-----------|---------|--------|
288
+ | 403 / 404 | `FUNCTIONALITY_NOT_ENABLED` / not found | NGA authoring namespace not provisioned on the org | Trigger the Phase-1 hand-off — `AskUserQuestion` → on Yes delegate to `service-itsm-agentic-setup-agentforce-studio-validate` |
289
+ | (script exit 3) | — | `build-create-body.mjs` couldn't find the template / its `agentScript` / couldn't substitute developer_name or agent_label in `${SCRATCH_DIR}/agent-templates.json` | Surface the script's stderr verbatim; re-verify Phase 1's `template.hasAgentScript:true` rather than hand-typing a body |
290
+
291
+ ## Publish the bundle version — `publishBundleVersion`
292
+
293
+ ```bash
294
+ sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/publish" \
295
+ --method POST --body '{}' \
296
+ --target-org <alias> > ${SCRATCH_DIR}/publish-bundle.json 2>${SCRATCH_DIR}/publish-bundle.err || true
297
+ ```
298
+
299
+ Path param only — the body is ignored by the endpoint but `--body '{}'` is
300
+ still required (see Gotchas). Response on success:
301
+
302
+ ```json
303
+ { "lastPublishedOn": "2026-08-05T01:22:54.278Z", "publishedBotId": "0Xx...", "publishedBotVersionId": "0X9..." }
304
+ ```
305
+
306
+ This is the call that creates the underlying `BotDefinition`/`BotVersion`. An
307
+ error here means the DRAFT version failed platform-side validation.
308
+
309
+ ## Activate the bundle version — `activateBundleVersion`
310
+
311
+ ```bash
312
+ sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/activate" \
313
+ --method POST --body '{}' \
314
+ --target-org <alias> > ${SCRATCH_DIR}/activate-bundle.json 2>${SCRATCH_DIR}/activate-bundle.err || true
315
+ ```
316
+
317
+ Success returns an **empty response body** (`EmptyRepresentation`) — do not
318
+ treat empty stdout as a failure signal. Check the CLI exit code, then confirm
319
+ success via the Phase-7 `BotDefinition`/`BotVersion` verify read, not by
320
+ parsing this call's output.
321
+
322
+ ## Verify the agent is live — SOQL on `BotDefinition` BY Id
323
+
324
+ ```bash
325
+ sf data query -q "SELECT Id,DeveloperName,MasterLabel,(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1) FROM BotDefinition WHERE Id='<verifyId>'" \
326
+ --target-org <alias> --json > ${SCRATCH_DIR}/bot-verify.json 2>${SCRATCH_DIR}/bot-verify.err || true
327
+ node "<skill_dir>/scripts/classify-agent-existence.mjs" ${SCRATCH_DIR}/bot-verify.json "<verifyId>"
328
+ ```
329
+
330
+ The verify `<verifyId>` is the create path's **`publishedBotId`** (captured from
331
+ the Phase-5 publish response) or, on the ALREADY-CREATED / reactivation path, the
332
+ **live matched Id the Phase-2 classifier returned** (its `botDefinitionId` /
333
+ `agentId` output — the actual `BotDefinition.Id` of the matched record) — **not**
334
+ the Phase-1 template `botDefinitionId`, which is `null` on a
335
+ `matchedBy:"developerName"` fallback hit (using it would run the verify as
336
+ `WHERE Id=''` and falsely report failure after a successful skip/activation).
337
+ Never the collected `<developerName>`.
338
+ Confirm `exists:true` with `count:1`, and — whether the create or the
339
+ reactivation path was taken — `latestVersionStatus:"Active"`. `exists:false`
340
+ after a successful activate ⇒
341
+ report the discrepancy verbatim, do not fabricate success. Optionally
342
+ cross-check
343
+ `GET /services/data/v67.0/nextgen-authoring/bundles` for an entry with
344
+ `apiName=<developerName>` and `isLegacy:false` — this is the same shape as the
345
+ platform's own "IT Service Employee Agent" entry and confirms the created
346
+ agent is NGA-native (no external-link icon in Agentforce Studio).
347
+
348
+ ## Idempotency semantics
349
+
350
+ The full `ALREADY-CREATED` / `ACTIVATED` / `CREATED` verdict table (Phase-2
351
+ classifier signal → verdict) — plus the note on how the Phase-2 SOQL read turns
352
+ the server's `DeveloperName`-keyed duplicate rejection into a graceful skip —
353
+ lives in `references/reactivation.md`.
354
+
355
+ ## Errors and gotchas
356
+
357
+ The response-body error codes each phase can return (auth, `FUNCTIONALITY_NOT_ENABLED`,
358
+ missing `agentType`, build-script exit codes, empty-response semantics) and the
359
+ recurring foot-guns (legacy-`createAgent`, `--body '{}'`, `bundleId` vs
360
+ `bundleVersionId`, multi-pass HTML decode, threading the collected
361
+ `<developerName>`, token+curl, …) live in `references/error-taxonomy.md`.
@@ -0,0 +1,44 @@
1
+ # Error taxonomy and gotchas — Create the IT Service Employee Agent
2
+
3
+ Split from `references/cli-invocation.md` — that file documents the per-phase
4
+ CLI call shapes and the classifier contracts; this file collects the errors
5
+ those calls can return and the recurring foot-guns.
6
+
7
+ ## Error taxonomy
8
+
9
+ - **Auth error / `401 Unauthorized`** — the org session is expired or the alias
10
+ is wrong. Re-run `sf org login web` for the target org; there is no token to
11
+ refresh by hand.
12
+ - **`401`/`403`/unexpected error body on the Phase-1 Studio-access read** — the
13
+ preflight classifier maps this to `studio.signal="ERROR"` / `verdict="ERROR"`
14
+ (distinct from a confirmed 404 gate). Surface the raw response and stop —
15
+ do not proceed to Phase 2 even if the template read succeeded.
16
+ - **`403`/`404` on `createBundleWithVersion` / `publish` / `activate`** — the
17
+ NGA authoring namespace isn't provisioned or enabled on the org. Trigger the
18
+ Phase-1 hand-off offer.
19
+ - **`400 MISSING_ARGUMENT: agentType`** on `agent-templates` — the required
20
+ `agentType` query param was omitted; pass `AgentforceEmployeeAgent`.
21
+ - **Build-script exit 3** — the template, its `agentScript`, or a successful
22
+ `developer_name`/`agent_label` substitution wasn't found in the captured
23
+ `agent-templates.json`; surface stderr, don't hand-author a body.
24
+ - **Classifier exit 3** on a `sf data query` read — the SOQL query failed
25
+ (auth/malformed); surface the raw CLI error, do not treat as NOT-EXISTS.
26
+ - **Empty stdout from `activate`** — this is the SUCCESS response
27
+ (`EmptyRepresentation`), not a failure; confirm via the Phase-7 verify SOQL.
28
+
29
+ ## Gotchas
30
+
31
+ | Issue | Resolution |
32
+ |-------|------------|
33
+ | Legacy `createAgent` produces the wrong kind of agent | Never call `/connect/service-itsm/createAgent` — it creates a Setup-page bot with an external-link icon in Agentforce Studio. Use the three `/nextgen-authoring/*` calls in `references/cli-invocation.md` |
34
+ | `sf api request rest --method POST` with no `--body` flag | Fails with `No 'mode' found in 'body' entry`, even for `publish`/`activate` which ignore the body — always pass `--body '{}'` explicitly |
35
+ | `sf api request rest --json` errors | Don't pass `--json` there — the raw stdout body is already JSON. `--json` is for `sf data query` (which needs the `.result.records[]` envelope) |
36
+ | Confusing `bundleId` with `bundleVersionId` | The `createBundleWithVersion` response's `id` field is the bundle **version** Id used in publish/activate; `bundleId` is the parent bundle's Id and 404s if passed to `/bundle-versions/{...}` |
37
+ | Naive single-pass HTML-entity decode leaves compile errors | `&amp;quot;` (double-encoded) and `&#92;` (numeric, backslash) require a multi-pass decode covering both named and numeric entities — see `build-create-body.mjs` |
38
+ | Bundle's outer `apiName` diverging from the script's internal `config.developer_name` | Always substitute both via `build-create-body.mjs` before the create call — a divergence is exactly the kind of mismatch that produces confusing platform behavior |
39
+ | Hardcoding `IT_Service_Employee_Agent` in one call but collecting it in another | Thread the collected `<developerName>` through the idempotency SOQL, the bundle body (outer + internal), AND the verify SOQL — a mismatch creates the wrong agent |
40
+ | Bare `./scripts/classify-agent-existence.mjs` "not found" | Use the skill's absolute `<skill_dir>` in the `node` invocation |
41
+ | `agent-templates` → `400 MISSING_ARGUMENT: agentType` | The `agentType` query param is required — pass `AgentforceEmployeeAgent` |
42
+ | `agent-templates` returns empty `data[]` | Wrong `agentType` value — use `AgentforceEmployeeAgent`; empty results are not the same as "not provisioned" |
43
+ | Treating `activate`'s empty response as a failure | It's the documented success response (`EmptyRepresentation`) — verify via the Phase-7 SOQL instead of parsing this call's stdout |
44
+ | Tempted to token+curl for any of the three writes | Never — `sf api request rest --method POST --body @<file>` (or `--body '{}'`) handles auth for `/services/data/...` writes; token extraction is forbidden |
@@ -0,0 +1,66 @@
1
+ # Reactivation path — activating an existing inactive IT Service Employee Agent
2
+
3
+ Split from `references/cli-invocation.md` — this file documents the direct
4
+ `BotVersion` activation call used when the Phase-2 classifier reports the agent
5
+ already exists but its latest version is `Inactive`. `cli-invocation.md` covers
6
+ the create/publish/activate happy path; this file covers "skip create/publish,
7
+ just reactivate what's already there".
8
+
9
+ ## When this path fires
10
+
11
+ `scripts/classify-agent-existence.mjs` (called with the template's
12
+ `botDefinitionId` as the PRIMARY idempotency key and the collected
13
+ `DeveloperName` as the FALLBACK — see `cli-invocation.md` → "Enumerate the
14
+ existing agent") returns
15
+ `{ exists:true, needsActivation:true, latestVersionId, latestVersionStatus:"Inactive" }`.
16
+ That means a `BotDefinition` matching the template (by `botDefinitionId`) or the
17
+ collected `DeveloperName` already exists (created on a prior run, or — for the
18
+ broad Employee agent — by the platform) but its most-recent `BotVersion` is
19
+ inactive; creating a new bundle would produce a duplicate. Instead, flip the
20
+ existing version to `Active`.
21
+
22
+ ## Activate an existing inactive version — `POST /connect/bot-versions/{id}/activation`
23
+
24
+ ```bash
25
+ sf api request rest "/services/data/v67.0/connect/bot-versions/<latestVersionId>/activation" \
26
+ --method POST --body '{"status":"Active"}' \
27
+ --target-org <alias> > ${SCRATCH_DIR}/activate-existing.json 2>${SCRATCH_DIR}/activate-existing.err || true
28
+ ```
29
+
30
+ `<latestVersionId>` is the captured `latestVersionId` from the Phase-2
31
+ classifier output — **not** a bundle version id. This is a direct
32
+ `BotVersion` activation toggle that bypasses the NGA bundle pipeline entirely,
33
+ because the `BotDefinition`/`BotVersion` records already exist. Skips create
34
+ (Phase 4) and publish (Phase 5) — go straight to activate, then verify.
35
+
36
+ ## Verify — same SOQL as the happy path
37
+
38
+ Run the Phase-7 verify read (see `cli-invocation.md` → "Verify the agent is
39
+ live"). Confirm `exists:true` with `count:1` **and**
40
+ `latestVersionStatus:"Active"`. If `latestVersionStatus` is still `Inactive`
41
+ after a successful activation call, report the discrepancy verbatim — do not
42
+ fabricate success.
43
+
44
+ ## Idempotency semantics
45
+
46
+ | Signal | Verdict |
47
+ |--------|---------|
48
+ | Neither the template's `botDefinitionId` nor the collected `DeveloperName` matches a live `BotDefinition` — classifier returns `exists:false` | proceed to CREATE |
49
+ | Phase-2 classifier returns `exists:true` and `needsActivation:false` (latest version `Active`), matched by `botDefinitionId` or the `DeveloperName` fallback | ALREADY-CREATED (skip create/publish/activate entirely) |
50
+ | Phase-2 classifier returns `exists:true` and `needsActivation:true` (latest version `Inactive`), user confirms reactivation, and the bot-version activation call succeeds | ACTIVATED (skip create/publish entirely — direct `BotVersion` activation only) |
51
+ | `createBundleWithVersion` → `publish` → `activate` all succeed and Phase-7 classifier (keyed on the publish `publishedBotId`) confirms `exists:true` with `latestVersionStatus:"Active"` | CREATED |
52
+
53
+ The server-side create path **does** reject a duplicate, but keyed on
54
+ `DeveloperName`, not `apiName`: a pre-validation lookup
55
+ (`lookupBotDefinitionIdByDeveloperName`) plus a publish-time `BotDefinition`
56
+ DeveloperName unique-constraint catch that cleans up the orphaned bundle version.
57
+ That guard fires only when the `DeveloperName` being created already exists — so
58
+ it catches a repeat run of THIS skill (same collected `developerName`), but it
59
+ does **not** catch the pre-provisioned broad Employee agent, whose live
60
+ `DeveloperName` (`IT_Service_Employee`) differs from this skill's guess
61
+ (`IT_Service_Employee_Agent`). The Phase-2 read closes that gap and upgrades the
62
+ outcome from a hard error to a graceful skip: it keys on the template's
63
+ `botDefinitionId` (primary — catches the pre-provisioned agent regardless of
64
+ name) and falls back to the collected `DeveloperName` (catches a self-created
65
+ repeat), so both surface as ALREADY-CREATED / reactivation instead of a
66
+ `DUPLICATE_VALUE` from the create call.
@@ -0,0 +1,66 @@
1
+ # Report Format — Employee Agent Create & Activate
2
+
3
+ The report layout is generated deterministically by `scripts/render-report.mjs` — the single source of report text for both the chat-turn response and the harness's `${outputDir}/report.md` file, so the two never diverge. Never hand-compose the layout, field placement, stage rows, or next-step wording in prose (authoring standard A9); always shell out to the helper.
4
+
5
+ ## Rendered shape
6
+
7
+ The helper reads a phase-state JSON and emits a report in this exact shape:
8
+
9
+ ```text
10
+ # Employee Agent — Create & Activate
11
+
12
+ IT Service Employee Agent Creation (via service-itsm-agentic-setup-employee-agent-configure)
13
+
14
+ Org: <org-alias> (API v67.0)
15
+ Template: <resolvedMasterLabel> (id=<resolvedId>) — <broad umbrella|specialized>
16
+ Source: <resolvedId> Agent Script
17
+ Agent: <developerName> ("<label>") — NGA-native bundle
18
+
19
+ Preflight ......................... Studio hasAccess=<true|false|cannot-confirm>; template agentScript present=<yes|no>
20
+ Enumerate ......................... target agent exists before write=<yes|no>; latest version status=<Active|Inactive|n/a>
21
+ Confirm-to-write ................... user-confirmed=<true|false|pending>
22
+ Create bundle ...................... <bundleVersionId=... | ALREADY-CREATED | skipped (reactivation path) | pending confirmation | FAILED>
23
+ Publish ............................ <publishedBotId=... | skipped | pending confirmation | FAILED>
24
+ Activate ........................... <succeeded (created) | succeeded (reactivated existing) | skipped | pending confirmation | FAILED>
25
+ Verify ............................. <BotDefinition present: yes|no; latest version Active: yes|no | skipped>
26
+
27
+ Verdict: CREATED | ALREADY-CREATED | ACTIVATED | PENDING CONFIRMATION | DECLINED | FAILED
28
+ Reason: <plain-language explanation naming the atomicity constraint, the idempotency decision, and any decline/skip reasoning — the caller populates this before invoking the helper, so it can be as rubric-facing as the situation warrants without repeating raw API calls>
29
+
30
+ Next steps:
31
+ - <helper-emitted next-step line for the emitted verdict>
32
+ ```
33
+
34
+ ## Report-state JSON schema (input to `render-report.mjs`)
35
+
36
+ The caller writes `${SCRATCH_DIR}/report-state.json` and passes it as the first arg:
37
+
38
+ ```json
39
+ {
40
+ "org": "<alias>",
41
+ "template": {"masterLabel": "...", "id": "...", "kind": "broad umbrella"|"specialized"},
42
+ "developerName": "...",
43
+ "label": "...",
44
+ "preflight": {"studioHasAccess": true|false|"cannot-confirm", "templateAgentScriptPresent": true|false},
45
+ "enumerate": {"existsBeforeWrite": true|false, "latestVersionStatus": "Active"|"Inactive"|"n/a"},
46
+ "confirmToWrite": "true"|"false"|"pending",
47
+ "verdict": "CREATED"|"ALREADY-CREATED"|"ACTIVATED"|"PENDING CONFIRMATION"|"DECLINED"|"FAILED",
48
+ "reason": "..."
49
+ }
50
+ ```
51
+
52
+ The helper enforces a validated verdict set and picks the `Next steps` line from the verdict, so the file never drifts from that shape.
53
+
54
+ ## Checkpoint writes (harness / non-interactive runs)
55
+
56
+ When `${outputDir}` is provided (via the harness's generated-file location directive), write the helper output to `${outputDir}/report.md` at three checkpoints so it always exists even when a run parks at a confirmation gate:
57
+
58
+ 1. **After Phase 2** — render with `verdict:"PENDING CONFIRMATION"` (create path) or the applicable ALREADY-CREATED / needsActivation state.
59
+ 2. **After Phase 6 (or Phase 2b activation)** — re-render with the create-succeeded (or reactivation-succeeded) state; leave `verify` as `pending`.
60
+ 3. **After Phase 8** — re-render with the final verdict (CREATED / ALREADY-CREATED / ACTIVATED / DECLINED / FAILED).
61
+
62
+ Each write overwrites the same file, so the last state on disk is always the most complete. The helper produces a ~30-line report — do NOT append extra sections (raw HTTP commands, full JSON bodies, per-phase narratives, remediation walkthroughs, session notes) to the report file; those belong in the assistant's turn-side response only.
63
+
64
+ ## Interactive runs
65
+
66
+ Skip these writes when running interactively for a user in a chat surface — write only when `${outputDir}` was passed as an explicit destination. In chat, the assistant may add turn-side narrative context above or below the helper output (raw command traces, error diagnostics, remediation walkthroughs) — the *report* is what the helper emits, the *turn* can be as rich as the situation warrants.