Skill v1.0.0
currentAutomated scan97/100version: "1.0.0" name: sales-call-scoring-configure description: "Configure, set up, or repair AI Call Scoring (a.k.a. Call Coaching / Coaching Competencies) on an ECI-enabled Salesforce org. Flips ECICallScoringEnabled via SOAP Metadata API, enables Einstein Generative AI Platform if off, and manages Coaching Competency records (EnablementCompetencyDef Tooling API): install the 6 OOTB set, the 7 Momentum best-practice prompts, or conversationally author/edit/activate/deactivate custom competencies (8-active + 16000/255-char caps). TRIGGER when: user wants to turn on AI Call Scoring or Call Coaching, install OOTB or best-practice competencies, create/edit custom competencies, re-enable after sandbox refresh, or verify/repair partial Call Coaching setup on a 68+ ECI org. DO NOT TRIGGER when: no ECI license (direct to Agentforce for Sales), user wants to enable ECI/Momentum themselves (out of scope — Setup), Pipeline Management (use sales-agentforce-pipeline-management-configure), or custom agent (use agentforce-generate)." metadata: version: "1.0" domains: ["Sales"] minApiVersion: "68.0" relatedSkills:
- "sales-agentforce-pipeline-management-configure"
- "agentforce-generate"
cliTools:
- tool: ["sf"]
semver: ">=2.0.0"
- tool: ["jq"]
semver: ">=1.6.0"
- tool: ["curl"]
semver: ">=7.0.0" accessCheck:
- type: "orgPref"
value: "ConversationPilotPref"
- type: "userPerm"
value: "ModifyAllData"
Sales Call Scoring — Configure
Configure Call Coaching (a.k.a. AI Call Scoring / Coaching Competencies) on a Salesforce org. Detects the org's current state, enables dependent features it is authorized to enable, and flips the ECICallScoringEnabled org preference via the SOAP Metadata API.
Scope
In scope
- ECI-enabled orgs only. The skill supports orgs on the ECI (Einstein
Conversation Insights) arm (spike scope: ECI-only for MVP).
- Detect which of the 4 PRD-scoped org states the org is in.
- Enable Einstein Generative AI Platform if off (PRD-authorized dependency).
- Flip
enableECICallScoringtotruevia SOAP Metadata API v68. - Verify the change took effect.
- Idempotent — clean exit on states 3 and 4 (already enabled).
Out of scope
- River Rush / Momentum detection. Deferred until that arm goes live —
see Key Considerations. A Momentum-only org today is not distinguished from any other ECI-off org; it gets the generic "ECI is not enabled" message from Phase 3, not a Momentum-specific one.
- Enabling ECI or Momentum themselves. PRD-explicit out-of-scope; the skill
detects and messages the admin to enable ECI via Setup.
- License provisioning. Missing base licenses (Agentforce for Sales, ECI
license) require an account-team ticket.
- Competency CRUD. Handled by sibling scripts in this same skill — see "Competency CRUD workflow" below (§S3-§S10) and the "Execution sequence" matrix.
Prerequisites
- `sf` CLI authenticated —
sf org login web --alias <org-alias>. - ECI arm licensed and enabled:
ConversationPilotorg permission (Phase 0
purchase gate) and enableCallCoaching pref (Phase 1, the ConversationPilotPref preference). (River Rush/Momentum is a separate arm covered by the same server-side gate but not checked by this skill yet — see Key Considerations.)
- Site gate
com.salesforce.eci.callScoringEnabledopen on the org's pod
(RelEng-controlled; not admin-toggleable).
Einstein GenAI Platform is a soft prerequisite — the skill enables it automatically when off.
Clarifying Questions
Ask the admin: target org alias? Sandbox refresh scenario? (The pref has disableOnSandboxCopy=true, so it must be re-flipped after every refresh — that's normal, not a failure.)
Admin Communication Guidelines
CRITICAL: This skill serves admin users, not developers. The full 13-rule spec with rationale for each rule lives in `references/admin-communication.md` — consult it before your first response in this skill. Summary of the load-bearing rules:
- Run all bash commands in background (
run_in_background: true). - Speak admin language, not entity language — "Call Coaching", "Coaching Competency", "active/inactive". Never
EnablementCompetencyDef,enableECICallScoring,EvaluationInstructions,SourceCompetencyTemplatein primary chat text. - Hide technical details — no record Ids, DeveloperNames, Template enum keys, HTTP codes, SOAP responses, curl/jq internals, script paths, or phase numbers. Exception: the S9 verify markdown table (see `references/competency-crud.md` §S9).
- Chain automatically — when a script prints
Next: <script>, run it in the same turn without asking. Exception: State 3 → rule #13. - Ask OOTB-vs-custom once — on first-time competency setup (State 3, unqualified intent), render
install-ootb-competencies.sh --listand let the admin choose. Only checkpoint in this skill where Claude asks before writing. - Idempotency is silent — if already on/installed, say so briefly and move on.
See `references/admin-communication.md` for the full 13-rule spec, including error-surfacing, outcome-vs-steps reporting, and the S9 carve-out rationale.
Workflow
Phase 0 — Auth
Resolves org auth via the shared scripts/shared/auth.sh helper (resolve_org_auth "$ORG_ALIAS"), which every script in this skill sources: validate the alias format, call sf org display for instanceUrl and accessToken (falling back to sf org auth show-access-token when the CLI redacts the token), refuse a non-HTTPS instance URL, and fail closed with an explicit sf org login web --alias <alias> instruction if the org isn't reachable or no token can be extracted. If ACCESS_TOKEN/INSTANCE_URL are already exported for the same alias — e.g. a parent shell already resolved auth and is chaining multiple of these scripts in one session — resolution is skipped and the cached values are reused. orgId is not part of this helper; enable-call-scoring.sh fetches it separately (via its own sf org display) purely for the status banner.
Phase 0 — ECI purchase gate
Before any state detection, query the ConversationPilot OrgPermission via Tooling API (OrganizationSettingsDetail, same pattern as the ECICallScoringAI gate in Phase 3). This is a license/purchase check, distinct from enableCallCoaching below (the admin's Setup toggle for an org that's already licensed):
- Not enabled: exit with: "Call Coaching couldn't be turned on because
this org doesn't have Einstein Conversation Insights, which is required to use Call Coaching. To proceed, an admin can go to Setup → Salesforce Go → Einstein Conversation Insights, or contact their sales representative, to understand how to purchase ECI." Non-zero exit.
- Enabled: proceed to Phase 1's
enableCallCoachingcheck.
Phase 1 — State detection
SOAP readMetadata at /services/Soap/m/68.0 against two settings types:
ConversationalIntelligenceSettings→ readenableCallCoaching(ECI arm)
and enableECICallScoring (current Call Coaching state).
EinsteinGptSettings→ readenableEinsteinGptPlatform.
(RiverRushSettings/riverRushEnabled — Momentum — is NOT read. That detection is deferred until the River Rush arm goes live; see Key Considerations for where to re-add it.)
Query existing competencies via Tooling API: SELECT COUNT() FROM EnablementCompetencyDef.
Classify the org into one of 4 states:
| State | Detection | |
|---|---|---|
| 1a. Not available (no ECI license) | Cannot read ConversationalIntelligenceSettings | |
| 2. Available, not enabled | enableCallCoaching=true AND enableECICallScoring=false | |
| 3. Enabled, no competencies | enableECICallScoring=true AND count = 0 | |
| 4. Enabled, with competencies | enableECICallScoring=true AND count > 0 |
Phase 2 — Route by state
- State 1a: Exit with PRD-verbatim message: "AI call coaching is not
available in this org and they need Agentforce for Sales." Non-zero exit.
- State 3 / State 4: Exit 0 with a ready-for-competency-setup message.
- State 2: Proceed.
Phase 3 — Prerequisite enablement (State 2 only)
- License gate (checked first): query
OrganizationSettingsDetail
(Tooling API) for the ECICallScoringAI OrgPermission. If it isn't true, exit with: "AI call coaching is not available in this org and org requires Agentforce for Sales license." Non-zero exit. This runs even when enableCallCoaching/enableECICallScoring already read favorably, since those settings don't by themselves confirm the org is licensed. Must run before the ECI-off check below — a genuinely unlicensed org and a licensed-but-toggled-off org both read enableCallCoaching=false, so checking ECI first would misdiagnose a licensing gap as a self-serve Setup toggle (the regression the NoLicense eval dataset guards against).
- If ECI is off: refuse with a Setup pointer, exit non-zero. This skill
does NOT enable ECI (PRD explicit). (A Momentum-only org lands here too, since Momentum isn't detected separately — it gets this same generic message, not a Momentum-specific one.)
- If Einstein GenAI off: SOAP
updateMetadataonEinsteinGptSettings
with enableEinsteinGptPlatform=true. PRD explicitly authorizes this. If it's already on, skip the updateMetadata call and tell the admin it's already enabled. If the update fails because the org isn't licensed for EinsteinGptSettings (or is explicitly refused with no fault): tell the admin they need Agentforce for Sales to enable AI Call Scoring, and that without it they can still set up manual call scoring via Salesforce Go setup. A distinct auth/permission or network/timeout failure gets its own message (check CLI session / retry) rather than the licensing message, since those aren't licensing gaps.
Phase 4 — Enable Call Coaching (State 2 only)
If enableECICallScoring already reads true (e.g. it changed out-of-band between Phase 1's read and here), skip the update and tell the admin it's already enabled. Otherwise SOAP updateMetadata on ConversationalIntelligenceSettings with enableECICallScoring=true. Require <success>true</success>.
Phase 5 — Verify (State 2 only)
Re-read enableECICallScoring. Require true. Print SOAP response on failure.
Key Considerations
- API version is v68.0, not v64.0.
enableECICallScoringis not
present in the ConversationalIntelligenceSettings schema at lower API versions on some builds — v68 is the safe minimum. The Pipeline skill uses v64 because its target field (SalesDealAgentSettings.enableDealAgent) is present there; Call Scoring is not.
- Do NOT use `sf mdapi deploy` for this pref. It has a silent failure
mode where the CLI reports success but the pref doesn't flip. Use raw SOAP updateMetadata — the response's <success> boolean is authoritative.
- The server-side gate is broader than this skill's scope. The
orgHasCallScoring access check allows the ECI arm OR the River Rush (Momentum) arm — see CoachingCompetenciesFeature.isFeatureAvailableInOrg(). This skill deliberately narrows to the ECI arm (MVP scope per the spike).
- River Rush (Momentum) detection is deliberately absent right now, not
an oversight — the arm isn't live yet. enable-call-scoring.sh used to read RiverRushSettings.riverRushEnabled and refuse Momentum-only orgs with a distinct "State 1b" message / emit a Momentum-available-but-off advisory; both were removed. Re-add them (the read, the State 1b branch, and the Phase 3 advisory) once River Rush ships — the removed code is recoverable from git history on this file.
- `disableOnSandboxCopy=true` — every sandbox refresh disables this pref.
Admins re-running the skill after a refresh is the expected pattern; the idempotency check makes that safe.
- Site switch
com.salesforce.eci.callScoringEnabledmust be open on
the org's pod. It's not admin-toggleable and not readable via SOAP. If closed, updateMetadata returns a well-formed response with <success>false</success> and an <errors><statusCode>…</statusCode></errors> block — it does NOT emit a SOAP <Fault>. parse_soap_response extracts the statusCode and surfaces it via the WRITE_ERROR:… classification.
- ECI provisioning is asynchronous. For a short window after
enableCallCoaching flips on, the dependent enableECICallScoring field is server-side read-only and updateMetadata returns INSUFFICIENT_ACCESS_OR_READONLY. enable-call-scoring.sh maps this to a transient "still finishing turning on — wait a few minutes and re-run" message rather than a terminal failure (W-23968462).
- Every SOAP call is bounded by a 30s timeout (
CURL_TIMEOUTin
enable-call-scoring.sh, matching the only existing timeout precedent in this repo — the Pipeline skill's setup-all.sh) and classified via shared/soap.sh's parse_soap_response into true / false / AUTH_ERROR:... / TYPE_UNAVAILABLE:... / WRITE_ERROR:… / NETWORK_ERROR. This distinguishes "org isn't licensed for this setting" from "auth/permission fault" from "server refused the write with a specific statusCode" from "network/timeout error" — instead of collapsing them into an empty string or dumping raw SOAP XML at the admin.
- `enable-call-scoring.sh` uses raw SOAP, not `sf api request rest`.
Every other script in this skill uses sf api request rest so the CLI manages auth end-to-end. enable-call-scoring.sh is the sole exception: it calls the SOAP Metadata API (readMetadata/updateMetadata) directly, because no non-beta Salesforce CLI command exposes SOAP Metadata reads/ writes for ConversationalIntelligenceSettings et al., and sf mdapi deploy has the silent-failure mode noted above for this exact field. This is a deliberate, scoped exception, not an oversight.
References
- Reference skill (canonical single-OrgPref pattern):
skills/sales-agentforce-pipeline-management-configure/
- SOAP helpers:
scripts/shared/soap.sh(copied from the Pipeline skill —
redact_token, parse_soap_response)
- Server-side gate (declarative access check):
core/conversation-udd/java/resources/udd/conversation-udd/ConversationalIntelligence.accessChecks.xml — orgHasCallScoring = ECI arm OR River Rush arm; orgHasECICallScoringWithAI adds Einstein GenAI + ECICallScoringAI license perm on top.
- Pref declaration:
core/conversation-udd/java/resources/udd/conversation-udd/ConversationalIntelligence.settings.xml — <orgPreference name="ECICallScoringEnabled" mdApiName="enableECICallScoring" ...>
- Java feature registration (would be the entry point if a
SetupDiscoveryService REST/MCP wrapper existed): core/conversation-impl/java/src/conversation/features/CoachingCompetenciesFeature.java
Competency CRUD workflow
Once Phase 5 confirms Call Coaching is enabled (or Phase 1 detects State 3/4), Claude runs the Next: script directly, in the same turn. Records are managed via Tooling API on EnablementCompetencyDef (setup entity, keyPrefix 1nA, module conversation-udd). Cap: 8 simultaneously active per org (CoachingCompetenciesFeature.MAX_ACTIVE_COMPETENCIES).
All scripts share shared/auth.sh / resolve_org_auth — token propagates across chained invocations, no re-auth. Tooling API writes go through sf api request rest where practical; a subset (custom-CRUD variants, best-practice installer) drops to raw curl for finer request shape.
Scripts fall into two parallel families:
- Generic —
{create,edit,toggle,get}-competency.sh— works on any competency. - Custom-CRUD variants —
*-custom-competency.sh— harden the write path with SpecificCallsOnly filter JSON and richer validation.
Prefer custom variants when the admin's intent is unambiguously custom (S5-created); fall back to generic on OOTB or unknown-provenance records.
Full spec — S3 through S10 script contracts, S5's Q1-Q4 conversational drafting sequence, the admin-intent × org-state execution matrix, and chaining checkpoints — is in `references/competency-crud.md`. Consult it whenever the admin's ask touches competency records (list, install, create/edit, activate, verify, delete).
Standalone Scripts (summary)
| Script | Purpose | ||
|---|---|---|---|
enable-call-scoring.sh <alias> | Detect state, enable Einstein GenAI if off, flip the Call Coaching pref (Phase 0-5). | ||
| `list-competencies.sh <alias> [--verbose\ | --json]` | List all competencies + status. Admin-safe by default; --verbose adds Ids/DeveloperNames; --json for the calling agent only. | |
install-ootb-competencies.sh <alias> [--dry-run] | Install the 6 PRD-canonical OOTB competencies. | ||
install-best-practice-competencies.sh <alias> [--dry-run] [--only "Name1,Name2"] | Install the 7 Momentum best-practice reference prompts. --only filters by MasterLabel. | ||
create-competency.sh <alias> <payload.json> | Create one competency (generic — usable on OOTB or custom). | ||
create-custom-competency.sh <alias> <payload.json> | Create one custom competency (hardened variant — prefer for S5). | ||
edit-competency.sh <alias> <ident> ... | Edit description / instructions (generic). | ||
edit-custom-competency.sh <alias> <ident> ... | Edit description / instructions (custom-CRUD variant). | ||
| `toggle-competency.sh <alias> <ident> <activate\ | deactivate>` | Activate / deactivate (generic). | |
| `toggle-custom-competency.sh <alias> <ident> <activate\ | deactivate>` | Activate / deactivate (custom-CRUD variant). | |
get-competency.sh <alias> <ident> [--field <f>] | Fetch a record or single field (generic). | ||
get-custom-competency.sh <alias> <ident> [--field <f>] | Fetch a record or single field (custom-CRUD variant). | ||
verify-ootb-competencies.sh <alias> ["Name" ...] | Confirm expected competencies exist and are active — outputs the S9 admin-visible markdown table. | ||
| _no delete script (yet)_ | Use sf data delete record --sobject EnablementCompetencyDef --record-id <Id> --use-tooling-api — see §S10. |
Admin Verification
After a successful run, the admin can independently verify:
Via UI — Salesforce Go → Coaching Competencies should now be reachable and show the feature as enabled with the configured competencies.
Via CLI — two Tooling API queries:
# Feature enabled?sf data query --target-org <alias> --use-tooling-api \--query "SELECT IsEciCallScoringEnabled FROM ConversationalIntelligenceSettings"# Competencies configured?sf data query --target-org <alias> --use-tooling-api \--query "SELECT MasterLabel, IsActive, SourceCompetencyTemplate FROM EnablementCompetencyDef ORDER BY MasterLabel"
Assets
assets/ootb-competencies.json— 6 PRD-canonical OOTB prompt bodies
(installed by install-ootb-competencies.sh).
assets/best-practice-competencies.json— 7 Momentum best-practice
prompt bodies (S5 authoring reference; also installable via create-competency.sh).