service-itsm-agentic-setup-itsm-agentforce-permset-assign
Resolve missing ITSM Intelligence invocable actions so a Fulfiller NGA agent can activate. Reads which of the three Core Fulfiller persona permsets …
它会碰到什么
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
Assign an ITSM Fulfiller Persona Permission Set (Prompt-Template Access)
Grants the running user one of the Core-shipped Fulfiller persona permission sets that expose the svc_itsm_intelligence__* prompt-template invocable actions on the target org — the actions the Fulfiller NGA agent scripts reference via source: / target: generatePromptResponse://.... When those invocables are not surfaced by /services/data/v67.0/actions/custom/generatePromptResponse for the running user, the Fulfiller agent-configure skill's Phase 6 activate call returns HTTP 200 with a silent {success:false, messages:[{... "does not exist"}]} body and the agent never becomes usable. This skill fixes that gap by assigning the correct Fulfiller persona permset (and its backing license when one exists) — or, when no Fulfiller persona permset is provisioned on the org at all, hands off to the Agentforce Studio configure/validate skill so the ITSM AddOn(s) can be enabled first.
The three Fulfiller persona permsets, their AddOns, PSLs, and the userPerms they grant are documented in references/permset-topology.md. All are Core-shipped in namespace force — there is no managed-package namespaced permset for this feature.
Employee agent is out of scope. The Employee NGA agent's access model is separate (org-preferences + a different persona layer) and does not map onto these three persona permsets.
Every call runs through the Salesforce CLI (sf):
sf api request rest— authenticated Connect API GET (identity, verify read).sf data query— SOQL onPermissionSet(persona presence),PermissionSetAssignment/PermissionSetLicenseAssign(idempotency).sf org assign permset— assigning the permission set for the running user.- No token is ever extracted; no MCP is used.
Scope
- In scope: detecting which of the three Fulfiller persona permsets (
IncidentFulfiller,ProblemFulfillerPermSet,ChangeRequestFulfillerPermSet) are provisioned on the org, letting the user pick which persona to assign, checking existing assignments, assigning the permission-set license (when the persona is license-gated) and permission set to the running user (or a named user), verifying the targetsvc_itsm_intelligence__*invocable actions surface via a follow-up/actions/custom/generatePromptResponseread. - Out of scope: Employee-agent access (different access model, different skill), installing/enabling the ITSM AddOn(s) or content bundle (hand off to
service-itsm-agentic-setup-agentforce-studio-validate), enabling org-level Agentforce feature toggles, creating a permission set, creating or activating the Fulfiller agent (that'sservice-itsm-agentic-setup-fulfiller-agent-configure), CMDB access (service-itsm-agentic-setup-cmdb-access-assign), generic non-ITSM permission-set assignment (dx-org-permission-set-assign).
Mechanism
Two branches, decided by a read-only detection step first:
- Branch A — one or more Fulfiller persona permsets exist on the org. Ask the user which persona to assign (do not auto-select — a Fulfiller commonly needs only one). Idempotent assign: PSL first when the persona is license-gated, then permission set, verified by read-back and by a follow-up
/actions/custom/generatePromptResponseread. - Branch B — none of the three Fulfiller persona permsets exist on the org. The ITSM AddOn(s) are not provisioned; permset-assign is a no-op. STOP and hand off to
service-itsm-agentic-setup-agentforce-studio-validateso the AddOn(s) can be enabled first.
The two-branch shape is deliberate — the failure signature ("svc_itsm_intelligence__X does not exist" on activate) looks identical whether a persona is present-and-unassigned or the AddOn is absent entirely, and there is no way to tell from the activate response alone. The pre-check on the three persona PermissionSet names is what disambiguates them.
Four helper scripts (all invoked via Bash) hold every deterministic decision (A9). Full I/O contracts in references/helper-contracts.md; workflow-level usage summarized below:
scripts/classify-permset-availability.mjs— Branch A vs B and the per-personaneedsPslflag. Returns the fullcandidates[](personas actually on the org) for the caller to prompt on.scripts/resolve-target-user.mjs— extracts005…running-user Id from the API-rootidentityURL. Fails closed on any malformed shape.scripts/classify-assignment-state.mjs— idempotency; pass the sentinelNO-PSLin place of the PSLA path when the selected persona'sneedsPsl:false.scripts/classify-action-surface.mjs— Phase 4 verify verdict from the/actions/custom/generatePromptResponsecapture (with optional expected-actions CSV).
Preconditions
sfCLI installed and authenticated to the target org (sf org display -o <alias>shows Connected). All calls use--target-org <alias>; never extract or pass the access token by hand.- API v67.0+.
node≥ 18 on PATH.
If a precondition fails, sf surfaces an auth or 401/403/404; report the raw response verbatim and stop.
Clarifying questions
Ask only what cannot be inferred from conversation:
- Target org — the
sfalias. Default tosf config get target-orgif unset. - Target user — default to the running user (resolved via
scripts/resolve-target-user.mjs). If the user asks to assign on behalf of a named user, resolve them byUsernamefirst. - Which Fulfiller persona? Incident / Problem / Change. Only ask about personas that are actually provisioned on the org (from
candidates[]). Do not auto-select — a Fulfiller commonly needs only one persona (e.g. Incident) even when others are provisioned. - Confirm the write — assigning a permission-set license consumes a seat and takes effect for a live user session. Present the target user + org + persona permset name, and require an explicit "yes" via
AskUserQuestionbefore writing.
Workflow
All calls go through sf; substitute <alias> with the target org.
Phase 1 — Read: which Fulfiller persona permsets are provisioned on this org?
- Query
PermissionSetfor the three known Fulfiller persona DeveloperNames:
sf data query \
-q "SELECT Id, Name, Label, LicenseId FROM PermissionSet WHERE Name IN ('IncidentFulfiller','ProblemFulfillerPermSet','ChangeRequestFulfillerPermSet')" \
--target-org <alias> --json > /tmp/itsm-personas.json 2>/tmp/itsm-personas.err || true
(The PermissionSet namespace on all three is force — do NOT filter by NamespacePrefix.)
- Classify:
node "<skill_dir>/scripts/classify-permset-availability.mjs" /tmp/itsm-personas.json
The classifier prints { personasFound, personasMissing, candidates, verdict, reasons }, where each candidates[] row is {Id, Name, Label, LicenseId, needsPsl}:
verdict:"ASSIGN"(≥1 persona present) ⇒ continue to Phase 2. Present thepersonasFoundlist to the user viaAskUserQuestionand get the selected persona; record itsId,LicenseId, andneedsPsl— they drive whether Phase 2b/2d touch the PSL at all.verdict:"HAND-OFF"(none of the three personas present) ⇒ Phase 2 is impossible on this org; go to Phase 3 (Branch B hand-off).verdict:"CANNOT-CONFIRM"(query failed) ⇒ surface the raw CLI error verbatim; stop.
Phase 2 — Assign path (Branch A)
2a. Resolve the target user. Read the identity URL, then extract the user Id via the resolver (do NOT parse the URL by hand; do NOT use USER_ID() — Apex-only, rejected by REST; do NOT rely on /chatter/users/me — 403 when Chatter is off):
sf api request rest "/services/data/v67.0/" --method GET --target-org <alias> > /tmp/api-root.json 2>/tmp/api-root.err || true
node "<skill_dir>/scripts/resolve-target-user.mjs" /tmp/api-root.json
The resolver prints { userId, identity, verdict, reasons }. On verdict:"RESOLVED" use userId as the running user; on verdict:"CANNOT-CONFIRM" surface the reasons verbatim and stop — do NOT guess.
If the user asks to assign on behalf of a named user instead, resolve by Username:
sf data query \
-q "SELECT Id, Username, Name, IsActive FROM User WHERE Username = '<username>'" \
--target-org <alias> --json > /tmp/user-lookup.json 2>/tmp/user-lookup.err || true
2b. Idempotency read. Query the PermissionSetAssignment for the target user + selected persona's Id (SOQL shape in references/cli-invocation.md), and then branch on the selected persona's needsPsl:
needsPsl:true— query thePermissionSetLicenseAssignfor the target user + the persona'sLicenseId, then classify:
node "<skill_dir>/scripts/classify-assignment-state.mjs" /tmp/psa-existing.json /tmp/psla-existing.json
needsPsl:false— skip the PSLA query entirely; pass the sentinel:
node "<skill_dir>/scripts/classify-assignment-state.mjs" /tmp/psa-existing.json NO-PSL
The classifier prints { permsetAssigned, licenseAssigned, needsWrite, verdict, reasons }. If needsWrite:false ⇒ Phase 4 (verify only). Else continue to Phase 2c.
2c. Confirm-to-write checkpoint (REQUIRED). Present the target user + org + persona permset name and require an explicit "yes" via AskUserQuestion. On "no", stop and report the current state without any writes.
2d. Assign — order depends on the selected persona's needsPsl:
needsPsl:true— POST the PSL to/sobjects/PermissionSetLicenseAssignFIRST, then runsf org assign permset --name <permsetName> --on-behalf-of <userId>. Assigning the permission set without the PSL sticks the assignment but the license backing it never activates. Exact call shapes:references/cli-invocation.md.needsPsl:false— SKIP the PSL POST entirely; runsf org assign permsetonly. (A persona whosePermissionSethas no backingLicenseIdis not license-gated — there is no PSL seat to hold, so assigning the permset alone is the correct and complete write.) _Retained defensively:_ every shipped persona is now PSL-backed (needsPslis derived per-row fromLicenseId), so thisfalsebranch and itsNO-PSLwiring are currently unexercised by shipped data — kept for correctness against a future persona whosePermissionSetcarries no backingLicenseId.
Response handling:
201on POST /success:trueonsf org assign permset⇒ assigned.400 DUPLICATE_VALUEon the PSL POST ⇒ user already had it; treat as success, not error.400 INSUFFICIENT_ACCESS/ seat-exhaustion on the PSL POST ⇒ STOP for this write; tell the user the PSL has no seats available.
Phase 3 — Hand-off path (Branch B: no Fulfiller persona provisioned)
- When Phase 1 returns
verdict:"HAND-OFF", none of the three Fulfiller persona permsets exist on this org — the ITSM AddOn(s) are not provisioned. Permset-assign is a no-op in this state. Present the discovery viaAskUserQuestion:
_"None of the Fulfiller persona permission sets (Incident, Problem, Change) is provisioned on this org — no permset can grant access to actions that don't exist yet. Run service-itsm-agentic-setup-agentforce-studio-validate to diagnose which AddOn needs enabling?"_ (options: Yes, run the readiness check / No, stop here).
- On Yes: delegate to
service-itsm-agentic-setup-agentforce-studio-validateand let it recommend the configure/bundle-deploy skill. - On No: stop and report the current state (no persona provisioned, cannot assign) — no writes.
Phase 4 — Verify
- Regardless of write vs skip, re-read
/actions/custom/generatePromptResponseand classify via the helper (never by prose grep — A9). CSV shape and both invocation forms live inreferences/helper-contracts.md/references/cli-invocation.md:
sf api request rest "/services/data/v67.0/actions/custom/generatePromptResponse" \
--method GET --target-org <alias> > /tmp/generate-prompt-response.json 2>/tmp/generate-prompt-response.err || true
node "<skill_dir>/scripts/classify-action-surface.mjs" /tmp/generate-prompt-response.json [expectedActions-csv]
The helper prints { present, missing, totalItsmActionsSeen, verdict, reasons }. On SURFACED proceed to Phase 5; on PARTIAL / MISSING after a successful assign, tell the user the write succeeded but the actions are not surfaced — session refresh or wrong persona. Do not falsely report success. On CANNOT-CONFIRM surface the reasons verbatim.
Phase 5 — Aggregate verdict
- Report one of:
- ASSIGNED — Branch A wrote, verify saw the target actions surface.
- ALREADY-ASSIGNED — Branch A found
needsWrite:false; verify saw the target actions surface. (Assignment is already in place; no writes needed.) - HAND-OFF — Branch B; no Fulfiller persona is provisioned. Named the follow-up skill.
- VERIFY-INCONCLUSIVE — write completed but the verify read didn't surface the expected action set. Surface the observed state verbatim; do not report success.
- FAILED — any Phase 2d write returned an error other than
DUPLICATE_VALUE. Report the raw error.
Rules / Constraints
| Constraint | Rationale |
|-----------|-----------|
| Detect Fulfiller persona presence via the three fixed PermissionSet.Name values BEFORE any permset write | The failure signature ("action does not exist" on activate) is identical for AddOn-absent and permset-not-assigned; only the pre-check disambiguates them. The three personas are Core-shipped in namespace force — a NamespacePrefix filter never returns them |
| Ask the user which persona to assign — never auto-select | A Fulfiller commonly needs only one persona (e.g. Incident). Auto-assigning the first row returned would over-grant |
| All decisions are made by helper scripts, never by prose | Assignment/idempotency logic is deterministic; prose interpretation is not (A9) |
| Assign the PSL before the permission set — ONLY when the selected persona's needsPsl:true | The permission set is license-backed; the license seat must be held before the assignment sticks. When the selected persona has no LicenseId, needsPsl:false and the PSL POST is skipped entirely |
| Read needsPsl from the SELECTED persona's LicenseId, per-row — never from a namespace-wide PSL query | Different personas can have different license shapes on the same org; falling back to a namespace-wide PSL would POST a wrong PermissionSetLicenseAssign |
| Resolve the running-user Id via scripts/resolve-target-user.mjs — never by prose parsing the identity URL | The identity URL's segment shape (005…, 15 or 18 chars) is a hard rule; the classifier validates and fails closed |
| Classify the Phase 4 action surface via scripts/classify-action-surface.mjs — never by prose grep of the response | Verify is the gate for reporting SUCCESS vs VERIFY-INCONCLUSIVE; the decision must be deterministic |
| Treat 400 DUPLICATE_VALUE on PSL POST as success | It means the user already has that assignment — idempotent, not an error |
| Never create or edit a permission set | This skill only assigns the standard Fulfiller persona permission set(s); authoring perm sets is out of scope |
| Never install the AddOn / never toggle org-level Agentforce features | That is the service-itsm-agentic-setup-agentforce-studio-validate / -configure scope; this skill hands off, it does not enable |
| Verify after write via /actions/custom/generatePromptResponse — never trust POST return code alone | The assignment can succeed while the target action surface still doesn't include what the Fulfiller template needs (wrong persona, cache) |
| Confirm-to-write checkpoint before Phase 2d | A permset assign consumes a license seat and takes effect for a live user session |
| Never extract the access token | Use sf api request rest / sf data query / sf org assign permset — they use the CLI's stored session |
| Report exact error text from the CLI response | Enables support to diagnose failures |
Verification Checklist
- [ ] Persona availability classified by
scripts/classify-permset-availability.mjsagainst the three fixed persona Names — never by prose scanning the query output. - [ ] User was asked to pick a persona from
personasFound[]— no auto-selection. - [ ] Target user Id resolved by
scripts/resolve-target-user.mjs— never by prose splitting the identity URL. - [ ] The SELECTED persona's
needsPsldrove Phase 2b/2d: PSL SOQL + POST were performed whentrueand skipped whenfalse. - [ ]
permsetLicenseIdused for the PSL POST came from the SELECTED persona's ownLicenseId— never a fallback from a namespace-wide query. - [ ] On Branch A: existing assignments read via
sf data querybefore any write, classified byscripts/classify-assignment-state.mjs(withNO-PSLsentinel whenneedsPsl:false). - [ ] On Branch A: user confirmed the write at the Phase 2c checkpoint.
- [ ] On Branch A +
needsPsl:true: PSL was POSTed before the permission set was assigned. - [ ]
DUPLICATE_VALUEon the PSL POST was treated as success, not failure. - [ ] On Branch B: no write was attempted; the hand-off to
service-itsm-agentic-setup-agentforce-studio-validatewas offered. - [ ] Phase 4 verify classified via
scripts/classify-action-surface.mjs— no false ASSIGNED without the helper returningverdict:"SURFACED". - [ ] Aggregate verdict reported (ASSIGNED / ALREADY-ASSIGNED / HAND-OFF / VERIFY-INCONCLUSIVE / FAILED).
Output Format
ITSM Fulfiller Persona Permset Assignment (via service-itsm-agentic-setup-itsm-agentforce-permset-assign)
Org: <org-alias> (API v67.0)
Target user: <username> (<userId>)
Persona: <Incident | Problem | Change>
PermSet: <DeveloperName>
Personas provisioned on org ...... <comma-separated list | none>
Existing PSL assignment .......... <yes | no | n/a>
Existing permset assignment ...... <yes | no>
Write PSL ........................ <succeeded | already-had | skipped | FAILED>
Write permset .................... <succeeded | already-had | skipped | FAILED>
Verify actions surface ........... <yes | partial | no>
Verdict: ASSIGNED | ALREADY-ASSIGNED | HAND-OFF | VERIFY-INCONCLUSIVE | FAILED
Reason: <plain-language explanation, or empty on success>
Next steps:
- <If ASSIGNED / ALREADY-ASSIGNED: "Re-run service-itsm-agentic-setup-fulfiller-agent-configure — the invocable actions should now surface, and the activate call will succeed.">
- <If HAND-OFF: "No Fulfiller persona is provisioned on this org. Run service-itsm-agentic-setup-agentforce-studio-validate to identify which AddOn needs enabling.">
- <If VERIFY-INCONCLUSIVE: list the observed state verbatim; a session refresh or a different persona may be required>
- <If FAILED: list the observed error verbatim + remediation>
Keep internal jargon (record Ids, HTTP status codes, FUNCTIONALITY_NOT_ENABLED, DUPLICATE_VALUE, object/developer names, sf api request rest) out of user-facing output.
Reference File Index
| File | When to read |
|------|--------------|
| references/permset-topology.md | Any change to the persona list — the three Core-shipped Fulfiller permsets, their AddOns/PSLs/userPerms, and the fixed-lookup discovery query |
| references/cli-invocation.md | Every phase — exact sf api request rest / sf data query / sf org assign permset call shapes, the never-extract-token rule, response envelopes |
| references/helper-contracts.md | The input/output shapes of all four helper scripts (classify-permset-availability.mjs, resolve-target-user.mjs, classify-assignment-state.mjs, classify-action-surface.mjs) and how to interpret each verdict |
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。
它属于哪个仓库
skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md同一个仓库里的其他技能
- commerce-b2b-open-code-components-integrate
- commerce-b2b-open-code-components-replace
- dx-devops-conflict-resolve
- dx-devops-pipeline-manage
- dx-devops-test-failures-analyze
- dx-devops-test-pipeline-configure
- dx-devops-test-suite-assignments-configure
- dx-devops-test-suite-run
- dx-devops-work-item-manage
- dx-app-analytics-query
- platform-agentexchange-partner-offers-configure
- automation-sandbox-post-copy-config-generate