Create the IT Service Fulfiller Agent
Create and activate the
IT Service Fulfiller Agent as a
Next-Gen Authoring (NGA) native agent — Agent-Script-based (
/bundle), appearing natively in Agentforce Studio's Agents list with no external-link icon — entirely through the
Salesforce CLI ().
This skill does not call the legacy /connect/service-itsm/createAgent
; instead it reuses the shipped ITSM Fulfiller template's
and feeds it into the NGA bundle pipeline:
POST /nextgen-authoring/bundles
() — creates the bundle + first version from the template's Agent Script.
POST /nextgen-authoring/bundle-versions/{id}/publish
— publishes the version (creates the underlying /).
POST /nextgen-authoring/bundle-versions/{id}/activate
— activates it.
Commands:
for Connect API GET/POST;
for the SOQL idempotency + verify reads.
Helper scripts (invoked via
) hold every JSON-parsing / decision rule so the model never eyeballs a response body (A9):
(Studio-access + template-provisioning verdict),
classify-agent-existence.mjs
(idempotency + reactivation-need from the
SOQL),
(HTML-decodes and substitutes the template's
, writes the bundle-create body to a JSON file so large content and free-text quotes never hit an inline shell string),
(deterministic report renderer — single source of report text for chat-turn and harness file).
The Fulfiller agent is the
IT-technician-facing assistant — incident triage, case summarization, field updates, related-record automations. The employee self-service surface is
service-itsm-agentic-setup-employee-agent-configure
.
Scope
- In scope: Reading ; extracting the Fulfiller template's Agent Script (
svc_itsm_intelligence__ITSrvcMgmtFulfiller
); creating the Fulfiller agent as an NGA-native agent via → → ; SOQL-verifying live; idempotent skip on duplicate developer name — all via .
- Out of scope: The Employee agent — broad or ~47 specializations under (
service-itsm-agentic-setup-employee-agent-configure
); enabling org-level feature toggles (validated by service-itsm-agentic-setup-agentforce-studio-validate
); low-level topic/action authoring; perm-set assignment; content-bundle deployment; CMDB CRUD; Discovery / Service Graph; the legacy route.
Preconditions
If any of these are unmet,
surfaces an auth error or a
/
/
;
surface the raw error verbatim and stop — do not fabricate state.
- CLI authenticated to the target org (
sf org display -o <alias>
shows Connected). All calls use ; never extract the access token by hand.
- API v67.0+ — pinned in the URL path; do not hand-edit below the minimum.
- ITSM features + Fulfiller template provisioned (
svc_itsm_intelligence__ITSrvcMgmtFulfiller
). If returns nothing or the routes 404, run service-itsm-agentic-setup-agentforce-studio-validate
.
- ≥ 18 on PATH.
Operations at a glance
| Concern | Command | Notes |
|---|
| Studio access (precondition read) | sf api request rest "/services/data/v67.0/agentforce-studio/access/Agents" --method GET -o <alias>
| ⇒ prereq hand-off |
| List agent templates + Agent Script (read) | sf api request rest "/services/data/v67.0/connect/service-itsm/agent-templates?agentType=AgentforceEmployeeAgent" --method GET -o <alias>
| agentType=AgentforceEmployeeAgent
required; confirms Fulfiller template + non-empty |
| Enumerate the existing agent + latest version status (read) | 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>'" -o <alias> --json
| Keyed PRIMARILY on the template's (Phase-1 row); the clause is both the null- fallback (the normal Fulfiller case) AND the guard for a dangling Id link (deleted target). Classified by scripts/classify-agent-existence.mjs
; Active latest ⇒ ALREADY-CREATED; Inactive latest ⇒ offer reactivation |
| Create the NGA bundle (write) | sf api request rest "/services/data/v67.0/nextgen-authoring/bundles" --method POST --body @<body-file> -o <alias>
| Body built by scripts/build-create-body.mjs
; response = the bundle version Id |
| Publish the bundle version (write) | sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/publish" --method POST --body '{}' -o <alias>
| Returns / — creates the underlying / |
| Activate the bundle version (write) | sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/activate" --method POST --body '{}' -o <alias>
| Empty response on success; agent is now live and NGA-native |
| Activate an existing inactive version (write) | sf api request rest "/services/data/v67.0/connect/bot-versions/<latestVersionId>/activation" --method POST --body '{"status":"Active"}' -o <alias>
| Reactivation path only (Phase 2b) — skips create/publish |
| Verify agent is live (read) | sf data query -q "SELECT ... FROM BotDefinition WHERE Id='<verifyId>'" -o <alias> --json
| = create path's (Phase-5) or the Phase-2 classifier's returned live matched Id (its /) on ALREADY-CREATED / reactivation — not the null Phase-1 template , never the collected developerName; confirm present + latest version Active |
Full command shapes and the ITSM Connect API reference live in
references/cli-invocation.md
; the reactivation-path call + idempotency verdict table live in
references/reactivation.md
; the response-body error codes and recurring gotchas live in
references/error-taxonomy.md
.
Never extract the access token. Use
/
directly — they use the CLI's stored session for the target org. Do
not pull the
out of
and hand-build an HTTP request with it; that bypasses the CLI session and leaks a bearer token into shell context.
rule. takes (results come back in a
envelope — that's what the classifier expects).
does
not — omit
there; its raw stdout body is already JSON.
Shipped ITSM Fulfiller agent template
| Template identifier | Default developer name |
|---|
svc_itsm_intelligence__ITSrvcMgmtFulfiller
( "IT Service Fulfiller") | IT_Service_Fulfiller_Agent
|
The field is the source of truth for the NGA create — not . scripts/build-create-body.mjs
matches on
, HTML-decodes
, and substitutes the collected
/
into
/
before it becomes the bundle's
. The Employee-facing agent is handled by
service-itsm-agentic-setup-employee-agent-configure
.
Architecture — Creation stages
| Stage | What happens | Tool used |
|---|
| Preflight | Confirm Studio access (agentforce-studio/access/Agents
) and that the template's is present | () |
| Enumerate | Read the Fulfiller template () and existing agents + latest version status (SOQL on /); classify idempotency and reactivation-need via script | (, ) |
| Confirm-to-write | Present the exact developerName + label (the NGA create target), OR — if the existing agent is inactive — present the reactivation option instead, and require explicit "yes" either way | |
| Create (create path only) | POST (builds the NGA bundle + first version from the decoded, substituted template Agent Script) | (, ) |
| Publish (create path only) | POST .../bundle-versions/<id>/publish
(creates the underlying /) | () |
| Activate | POST .../bundle-versions/<id>/activate
(create path) OR POST .../connect/bot-versions/<latestVersionId>/activation
with (reactivation path — skips create/publish) | () |
| Verify | SOQL-read / and confirm the agent exists with an Active latest version | () |
Idempotency: keyed PRIMARILY on the
template's (Phase-1
row — the platform's authoritative template→
link) and FALLING BACK to the collected
. The Phase-2 read is
BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'
(the
half is both the null-
fallback — the normal Fulfiller case — AND the guard for a
dangling Id link whose target
was deleted, so a stale link can't slip through to create), + latest
(classified by the helper script). Outcomes: no match on either key ⇒
⇒ create;
latestVersionStatus:"Active"
⇒
ALREADY-CREATED (skip the write, fall through to Phase 7 verification);
(latest version
) ⇒
offer to activate the existing version instead of creating a new agent (Phase 2b) rather than silently skipping or duplicating.
Why the fallback matters: the Fulfiller is never pre-provisioned and this skill's create path never stamps
, so the template's
is always
— the
-keyed fallback is the guard that actually catches a repeat run; short-circuiting straight to create on a null
would re-create and collide with
. The server does reject a duplicate
at publish (unique-constraint → bundle cleanup), but only this Phase-2 read turns a repeat into a graceful skip instead of that hard error.
Clarifying Questions
Collect from the user (ask only what is not already in conversation context):
| Field | Description | Default |
|---|
| Target org | The org alias to create the agent in | Default org () |
| Developer name | Unique for the agent | IT_Service_Fulfiller_Agent
|
| Label | User-facing label for the agent | IT Service Fulfiller Agent
|
| Confirm the write | Explicit confirmation before the create/publish/activate sequence | REQUIRED — present the developerName + label and require "yes" via |
The
idempotency read keys PRIMARILY on the template's (Phase-1 row) and FALLS BACK to the collected
when that is null; the verify read keys on the publish response's
(create path) or the template's
(ALREADY-CREATED / reactivation). The collected
and
(defaults
IT_Service_Fulfiller_Agent
/
IT Service Fulfiller Agent
) also thread through the
body — both the outer
/
AND the substituted
/
inside the Agent Script. Never hardcode the name in one call and collect it in another — a mismatch between the bundle's outer
and the script's internal
causes the platform to diverge the two. Creating an agent provisions a live, activated agent on the org; the user must explicitly approve the write.
Workflow
Substitute
with the collected target org and
/
with the collected values. Full command shapes + per-phase verdict-branch handling live in
references/workflow-detail.md
— the phase summary below names each step and its load-bearing rule; the reference file holds the exact
/
invocations to copy.
- Phase 0 — Establish . Invoke the deterministic helper (path is skill-root-qualified so it resolves regardless of the shell's CWD):
SCRATCH_DIR="$(node "<skill_dir>/scripts/create-scratch-dir.mjs" "${outputDir:-}")"
. Helper picks the base dir (, else , else the harness last-resort — scratch stays OUT of the scored tree) and emits the created dir on stdout. All transient JSON lands under ; the durable stays under the harness dir.
- Phase 1 — Preflight. Capture the Studio-access read + read (with the required
agentType=AgentforceEmployeeAgent
query param) into ${SCRATCH_DIR}/agent-templates.json
, then classify via scripts/classify-preflight.mjs "IT Service Fulfiller"
. The classifier also emits from the matched row — capture it; it is the primary Phase-2 idempotency key (the collected is the fallback key). Branch on : ⇒ Phase 2; ⇒ prerequisite hand-off via (delegate to service-itsm-agentic-setup-agentforce-studio-validate
on "yes"); ⇒ surface + stop; studio.signal="CANNOT-CONFIRM"
(confirmed 404) does not block.
- Phase 2 — Idempotency (primary key , fallback key ). Take from Phase 1. Present ⇒ SOQL
BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'
with the subquery (subquery is required — otherwise is permanently false; the clause makes a dangling Id link — deleted target — fall back to the live same-name agent instead of a false → duplicate create). Empty/null (the normal Fulfiller case — the template row is never back-filled) ⇒ do NOT skip to create; fall back to BotDefinition WHERE DeveloperName='<developerName>'
(a self-created agent from a prior run has a null template but still exists). Either way classify via scripts/classify-agent-existence.mjs ${SCRATCH_DIR}/bot-existing.json "<botDefinitionId-or-empty>" "<developerName>"
. Branch: ⇒ Phase 2c (action-availability gate, then create); + ⇒ ALREADY-CREATED (skip straight to Phase 7 — no action-availability gate; a live active agent's actions are already wired); + ⇒ Phase 2b. Non-zero exit ⇒ surface CLI error; never assume absent. Why the fallback: the Fulfiller is never pre-provisioned, so is always null — a missing developerName check would re-create and hit .
- Phase 2b — Reactivation offer. : "Fulfiller agent exists but latest version is Inactive. Activate it?". On Yes:
POST /connect/bot-versions/<latestVersionId>/activation
with captured to ${SCRATCH_DIR}/activate-response.json
, then node "<skill_dir>/scripts/classify-activate-result.mjs" ${SCRATCH_DIR}/activate-response.json
— ⇒ Phase 7 (verdict ACTIVATED); ⇒ surface verbatim, offer the Phase 2c permset hand-off if a message names a missing invocable action, do NOT report ACTIVATED; ⇒ fall through to Phase 7 SOQL verify. On No: stop, no writes.
- Phase 2c — Action-availability preflight (create path only; reached only from Phase 2 ). Capture
sf api request rest "/services/data/v67.0/actions/custom/generatePromptResponse" --method GET
to ${SCRATCH_DIR}/generate-prompt-response.json
, then node "<skill_dir>/scripts/classify-action-availability.mjs" ${SCRATCH_DIR}/agent-templates.json "IT Service Fulfiller" ${SCRATCH_DIR}/generate-prompt-response.json
. Branch on : ⇒ Phase 3; ⇒ offering hand-off to service-itsm-agentic-setup-itsm-agentforce-permset-assign
(surface verbatim — do NOT proceed to write; the activate call would return HTTP 200 with a silent-failure body); ⇒ surface reasons and proceed with caution (Phase 6 activate-result classifier catches the silent-failure body). Full contract in references/action-availability.md
.
- Phase 3 — Confirm-to-Write (REQUIRED, create path only). If was provided, first render the checkpoint file via with
verdict:"PENDING CONFIRMATION"
(skip for interactive runs). THEN raise the gate presenting developerName + label + "NGA-native from the Fulfiller template's Agent Script". Proceed only on explicit "yes"; on "no", re-render with .
- Phase 4 — Create.
scripts/build-create-body.mjs ${SCRATCH_DIR}/agent-templates.json "IT Service Fulfiller" "<developerName>" "<label>" ${SCRATCH_DIR}/create-bundle-body.json
(helper re-reads Phase-1 templates JSON, HTML-decodes the matched , substitutes internal /, writes body to file), then POST /nextgen-authoring/bundles --body @${SCRATCH_DIR}/create-bundle-body.json
. Capture response — that is the for Phases 5–6, not . 403 FUNCTIONALITY_NOT_ENABLED
/ ⇒ trigger the Phase-1 hand-off; build-script exit 3 ⇒ surface stderr.
- Phase 5 — Publish.
POST /nextgen-authoring/bundle-versions/<bundleVersionId>/publish --body '{}'
(empty body required). Success: { lastPublishedOn, publishedBotId, publishedBotVersionId }
— this call creates the underlying /. Any error ⇒ surface verbatim; never activate an unpublished version.
- Phase 6 — Activate.
POST /nextgen-authoring/bundle-versions/<bundleVersionId>/activate --body '{}'
captured to ${SCRATCH_DIR}/activate-response.json
, then node "<skill_dir>/scripts/classify-activate-result.mjs" ${SCRATCH_DIR}/activate-response.json
— activate can return HTTP 200 with a silent-failure body when a referenced invocable action isn't surfaced; the classifier catches that. ⇒ Phase 7; ⇒ surface , offer Phase 2c permset hand-off if a message names a missing action, do NOT report CREATED; ⇒ fall through to Phase 7 SOQL verify.
- Phase 7 — Verify. SOQL
BotDefinition WHERE Id='<id>'
(+ subquery) and classify — is the create path's (captured from Phase 5) or, on the ALREADY-CREATED / reactivation path, the live matched Id the Phase-2 classifier returned (its / output — the actual of the matched record), not the Phase-1 template (which is always null for the Fulfiller, so on any existing-agent hit the verify would run and falsely report failure after a successful skip/activation). Confirm exists:true, count:1, latestVersionStatus:"Active"
. Any discrepancy ⇒ report verbatim, do not fabricate success.
- Phase 8 — Aggregate verdict. Emit CREATED / ALREADY-CREATED / ACTIVATED / FAILED (ACTIVATED on the Phase-2b path) + Id / bundle by re-invoking — the single source of report text. If was provided, overwrite ; otherwise emit stdout as the turn-side report.
Rules / Constraints
| Constraint | Rationale |
|---|
| All calls go through / ; never extract the access token | Leaks a bearer token into shell context; the CLI's stored session is the correct surface |
| Idempotency read keys PRIMARILY on the template's (Phase-1 row), falling back to the collected when null; the verify read keys on the publish / ; that same / also thread through the create body (outer / AND the substituted /) | The Fulfiller is never pre-provisioned and the create path omits , so its template is always null — the fallback is the guard that catches a repeat run (a name-only miss → ). A create-body hardcode/collect mismatch diverges the bundle's outer identity from the script's internal identity |
| Preflight, idempotency, bundle-body construction, and report rendering all live in , not prose (A9) | JSON parsing + matching + reads + verdict emission are deterministic; the ~70KB Agent Script and free-text apostrophes cannot be safely interpolated into a shell string — in the helper escapes them |
| Three-call sequence: → → , in that order, on the SAME captured (response , not ) | Platform enforces DRAFT → published → active; response-body / empty-body / / / HTML-decode gotchas live in references/error-taxonomy.md
|
| Enumerate with the subquery; skip create when Active; offer Phase-2b reactivation when Inactive — never silent skip, never duplicate create | Subquery is what distinguishes Active/Inactive; the server rejects a duplicate at publish (unique-constraint → bundle cleanup), so this read is what turns a repeat into a graceful skip instead of that hard error |
| REQUIRED confirm-to-write checkpoint before create sequence or reactivation call | Both change live org state — explicit user approval required |
On / 403 FUNCTIONALITY_NOT_ENABLED
, offer the readiness hand-off — never enable features here; never call legacy /connect/service-itsm/createAgent
| Enablement is a Setup-UI/admin action; produces a Setup-page bot with an external-link icon (wrong kind of agent for this skill) |
| Report exact CLI response text on any error | Enables support to diagnose failures |
Verification Checklist
Output Format
The report layout is generated deterministically by
scripts/render-report.mjs
— the single source of report text for both the chat turn and the harness's
. Never hand-compose the layout in prose (A9); always shell out to the helper. Full rendered shape, report-state JSON schema, and checkpoint-write rules live in
references/report-format.md
.
Terminal verdicts:
CREATED | ALREADY-CREATED | ACTIVATED | PENDING CONFIRMATION | DECLINED | FAILED
. When
is set, write at Phase 3, Phase 6 (or Phase 2b), and Phase 8 — each write overwrites the same file. Skip these writes in interactive/chat surfaces.
Reference File Index
| File | When to read |
|---|
references/workflow-detail.md
| Full per-phase verdict-branch narrative that the SKILL body summarizes (Phase-1 ERROR/NOT-READY/CANNOT-CONFIRM, Phase-2 classifier output, Phase-4 create response, error branches) |
references/report-format.md
| Every call — the rendered shape and the three-checkpoint write policy for |
references/cli-invocation.md
| Every phase — exact call shapes, the never-extract-token rule, ITSM Connect API reference, three helper-script contracts |
references/action-availability.md
| Phase 2c (action-availability preflight, create path) + Phase 2b/6 (activate-result classifier) — silent-failure body catches, permset hand-off wording |
references/reactivation.md
| Reactivation path () — the direct POST /connect/bot-versions/{id}/activation
call + full idempotency verdict table |
references/error-taxonomy.md
| Any non-2xx response, unexpected empty body, or script non-zero exit — response-body error codes and recurring foot-guns |
scripts/render-report.mjs
| Every checkpoint that writes (Phase-3 gate, Phase-6 create-succeeded, Phase-8 final) — deterministic renderer from a phase-state JSON |