Create the IT Service Fulfiller Agent
SkillProductivityCreate and activate the IT Service Fulfiller agent as a Next-Gen Authoring (NGA) native agent from the shipped ITSM Fulfiller template's Agent Script, using the Salesforce CLI (sf): read the template, check idempotency, create the NGA bundle then publish and activate it, then verify it is live. Idempotent per developer name. The Fulfiller agent is the IT-technician-facing assistant for incident triage, case summarization, field updates, and related-record automations. Use when asked to create the Fulfiller agent, set up the IT Service Fulfiller agent, provision the fulfiller assistant, or activate the Fulfiller agent. Triggers: create fulfiller agent, set up fulfiller agent, provision fulfiller agent, activate fulfiller agent. DO NOT TRIGGER: checking org prerequisites (service-itsm-agentic-setup-agentforce-studio-validate), or CMDB CRUD.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the Create the IT Service Fulfiller Agent skill
What this skill tells your AI
The instructions your AI receives, as published by forcedotcom/sf-skills in skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md and read by ahel’s review.
Create and activate the IT Service Fulfiller Agent as a Next-Gen Authoring (NGA) native agent — Agent-Script-based (AiAuthoringBundleDefVer/bundle), appearing natively in Agentforce Studio's Agents list with no external-link icon — entirely through the Salesforce CLI (sf). This skill does not call the legacy /connect/service-itsm/createAgent; instead it reuses the shipped ITSM Fulfiller template's agentScript and feeds it into the NGA bundle pipeline:
POST /nextgen-authoring/bundles(createBundleWithVersion) — creates the bundle + first version from the template's Agent Script.POST /nextgen-authoring/bundle-versions/{id}/publish— publishes the version (creates the underlyingBotDefinition/BotVersion).POST /nextgen-authoring/bundle-versions/{id}/activate— activates it.
Commands: sf api request rest for Connect API GET/POST; sf data query for the SOQL idempotency + verify reads.
Helper scripts (invoked via Bash) hold every JSON-parsing / decision rule so the model never eyeballs a response body (A9): classify-preflight.mjs (Studio-access + template-provisioning verdict), classify-agent-existence.mjs (idempotency + reactivation-need from the BotDefinition SOQL), build-create-body.mjs (HTML-decodes the template's agentScript, normalizes it for the org's enabled features via strip-release-management.mjs, substitutes config.developer_name/config.agent_label, writes the bundle-create body to a JSON file so large content and free-text quotes never hit an inline shell string), render-report.mjs (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
agent-templates; extracting the Fulfiller template's Agent Script (svc_itsm_intelligence__ITSrvcMgmtFulfiller); creating the Fulfiller agent as an NGA-native agent viacreateBundleWithVersion→publish→activate; SOQL-verifying live; idempotent skip on duplicate developer name; normalizing the created Agent Script so it activates cleanly on any Agentforce-for-IT-Service org (internal step, never surfaced to the user — see below) — all viasf. - Out of scope: The Employee agent — broad or ~47 specializations under
svc_emp_intelligence__(service-itsm-agentic-setup-employee-agent-configure); enabling org-level feature toggles (validated byservice-itsm-agentic-setup-agentforce-studio-validate); low-level topic/action authoring; perm-set assignment; content-bundle deployment; CMDB CRUD; Discovery / Service Graph; the legacycreateAgentroute.
Preconditions
If any of these are unmet, sf surfaces an auth error or a 401/403/404; surface the raw error verbatim and stop — do not fabricate state.
sfCLI authenticated to the target org (sf org display -o <alias>shows Connected). All calls use--target-org <alias>; 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). Ifagent-templatesreturns nothing or the routes 404, runservice-itsm-agentic-setup-agentforce-studio-validate. node≥ 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> | hasAccess=false ⇒ prerequisite 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 agentScript |
| Enumerate the existing agent + latest version status (read) | sf data query -q "SELECT Id,DeveloperName,MasterLabel,AgentTemplate,(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1) FROM BotDefinition WHERE Id='<botDefinitionId>' OR AgentTemplate='<agentTemplate>' OR DeveloperName='<developerName>'" -o <alias> --json | Keyed PRIMARILY on the template's botDefinitionId (Phase-1 row); OR AgentTemplate= is a defensive fallback that would catch a live agent instantiated from the OOTB source template (svc_itsm_intelligence__ITSrvcMgmtFulfiller = Phase-1 template.id) regardless of its DeveloperName; OR DeveloperName= is the real guard here — the normal Fulfiller case (never pre-provisioned; null AgentTemplate) 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 id = 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 publishedBotId/publishedBotVersionId — creates the underlying BotDefinition/BotVersion |
| 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 | <verifyId> = create path's publishedBotId (Phase-5) or the Phase-2 classifier's returned live matched Id (its botDefinitionId/agentId) on ALREADY-CREATED / reactivation — not the null Phase-1 template botDefinitionId, never the collected developerName; confirm BotDefinition 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
sf api request rest/sf data querydirectly — they use the CLI's stored session for the target org. Do not pull theaccessTokenout ofsf org displayand hand-build an HTTP request with it; that bypasses the CLI session and leaks a bearer token into shell context.
--jsonrule.sf data querytakes--json(results come back in a.result.records[]envelope — that's what the classifier expects).sf api request restdoes not — omit--jsonthere; its raw stdout body is already JSON.
Shipped ITSM Fulfiller agent template
| Template identifier | Default developer name |
|---|---|
svc_itsm_intelligence__ITSrvcMgmtFulfiller (masterLabel "IT Service Fulfiller") | IT_Service_Fulfiller_Agent |
The
agentScriptfield is the source of truth for the NGA create — notid.scripts/build-create-body.mjsmatches onmasterLabel, HTML-decodesagentScript, and substitutes the collected<developerName>/<label>intoconfig.developer_name/config.agent_labelbefore it becomes the bundle'sresourceContent. The Employee-facing agent is handled byservice-itsm-agentic-setup-employee-agent-configure.
Internal template normalization — never surfaced to the user. Before the decoded script becomes
resourceContent,scripts/strip-release-management.mjsremoves thetopic ReleaseManagement:block — plus itsgo_to_ReleaseManagement:selector transition and routing bullet. That topic's only action,svc_itsm_intelligence__SummarizeRelease, is gated behind an org preference (ReleaseManagementPref) and is not surfaced by/actions/custom/generatePromptResponseon an org that has not enabled it; shipping it would makeactivatereturn HTTP 200 with a{success:false, "... does not exist"}silent-failure body.classify-action-availability.mjsapplies the identical transform so Phase 2c scans the same normalized script — the two callers must stay in lock-step. The transform is a no-op if the block is absent (safe against future template revisions). This normalization is an implementation detail: do NOT mention it, the removed subagent, or Release Management in chat narration, the confirm-to-write step, or the report — the admin only ever sees that the agent was created and activated.
Architecture — Creation stages
| Stage | What happens | Tool used |
|---|---|---|
| Preflight | Confirm Studio access (agentforce-studio/access/Agents) and that the template's agentScript is present | Bash (sf api request rest) |
| Enumerate | Read the Fulfiller template (agent-templates) and existing agents + latest version status (SOQL on BotDefinition/BotVersions); classify idempotency and reactivation-need via script | Bash (sf, node) |
| 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 | AskUserQuestion |
| Create (create path only) | POST createBundleWithVersion (builds the NGA bundle + first version from the decoded, substituted template Agent Script) | Bash (sf api request rest, node) |
| Publish (create path only) | POST .../bundle-versions/<id>/publish (creates the underlying BotDefinition/BotVersion) | Bash (sf api request rest) |
| Activate | POST .../bundle-versions/<id>/activate (create path) OR POST .../connect/bot-versions/<latestVersionId>/activation with {"status":"Active"} (reactivation path — skips create/publish) | Bash (sf api request rest) |
| Verify | SOQL-read BotDefinition/BotVersions and confirm the agent exists with an Active latest version | Bash (sf data query) |
Idempotency: keyed PRIMARILY on the template's botDefinitionId (Phase-1 agent-templates row — the platform's authoritative template→BotDefinition link), FALLING BACK first to the BotDefinition's AgentTemplate (the OOTB namespaced source template = Phase-1 template.id) and then to the collected <developerName>. The Phase-2 read is BotDefinition WHERE Id='<botDefinitionId>' OR AgentTemplate='<agentTemplate>' OR DeveloperName='<developerName>' (the OR AgentTemplate= half is a defensive key that would catch a live agent instantiated from the source template regardless of its DeveloperName; the OR DeveloperName= half is both the null-botDefinitionId fallback — the normal Fulfiller case — AND the guard for a dangling Id link whose target BotDefinition was deleted), + latest BotVersion.Status (classified by the helper script). Outcomes: no match on any key ⇒ exists:false ⇒ create; latestVersionStatus:"Active" ⇒ ALREADY-CREATED (skip the write, fall through to Phase 7 verification); needsActivation:true (latest version Inactive) ⇒ offer to activate the existing version instead of creating a new agent (Phase 2b) rather than silently skipping or duplicating. Why the fallbacks matter: the Fulfiller is never pre-provisioned and this skill's create path never stamps templateName, so BOTH the template's botDefinitionId AND the agent's AgentTemplate are always null — the <developerName>-keyed fallback is the guard that actually catches a repeat run; short-circuiting straight to create on a null botDefinitionId would re-create and collide with DUPLICATE_VALUE. The server does reject a duplicate DeveloperName 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 sf org alias to create the agent in | Default org (sf config get target-org) |
| Developer name | Unique DeveloperName 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 AskUserQuestion |
The idempotency read keys PRIMARILY on the template's botDefinitionId (Phase-1 row) and FALLS BACK to the BotDefinition's AgentTemplate (defensive — null on the never-pre-provisioned Fulfiller) and then to the collected <developerName>, the guard that actually catches a repeat here, when that is null; the verify read keys on the publish response's publishedBotId (create path) or the template's botDefinitionId (ALREADY-CREATED / reactivation). The collected <developerName> and <label> (defaults IT_Service_Fulfiller_Agent / IT Service Fulfiller Agent) also thread through the createBundleWithVersion body — both the outer apiName/label AND the substituted config.developer_name/config.agent_label inside the Agent Script. Never hardcode the name in one call and collect it in another — a mismatch between the bundle's outer apiName and the script's internal developer_name 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 <alias> with the collected target org and <developerName> / <label> 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 sf / node invocations to copy.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 1k
- Forks
- 348
- Last commit
- Sep 2026
ahel review
K2info
exfiltration (in references/cli-invocation.md)
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Item type
- skill
- Key
service-itsm-agentic-setup-fulfiller-agent-configure- Source
- github.com/forcedotcom/sf-skills