
Orchestrating Datacloud
- 2k installs
- 763 repo stars
- Updated July 24, 2026
- forcedotcom/sf-skills
orchestrating-datacloud is an agent skill that Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this skill when the .
About
orchestrating datacloud Salesforce Data Cloud Orchestrator Use this skill when the user needs product level Data Cloud workflow guidance rather than a single isolated command family pipeline setup cross phase troubleshooting data spaces data kits or deciding whether a task belongs in Connect Prepare Harmonize Segment Act or Retrieve This skill intentionally follows sf skills house style while using the external sf data360 command surface as the runtime The plugin is not vendored into this repo Use orchestrating datacloud when the work involves multi phase Data Cloud setup or remediation data spaces sf data360 data space data kits sf data360 data kit health checks sf data360 doctor CRM to unified profile pipeline design deciding how to move from ingestion harmonization segmentation activation cross phase troubleshooting where the root cause is not yet clear Delegate to a phase specific skill when the user is focused on one area
- description: "Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this s
- compatibility: "Requires an external community sf data360 CLI plugin and a Data Cloud-enabled org"
- Use this skill when the user needs **product-level Data Cloud workflow guidance** rather than a single isolated command
- Follow orchestrating-datacloud SKILL.md steps and documented constraints.
- Follow orchestrating-datacloud SKILL.md steps and documented constraints.
Orchestrating Datacloud by the numbers
- 2,004 all-time installs (skills.sh)
- +6 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #585 of 16,659 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
orchestrating-datacloud capabilities & compatibility
- Capabilities
- description: "salesforce data cloud product orch · compatibility: "requires an external community s · use this skill when the user needs **product lev · follow orchestrating datacloud skill.md steps an
- Use cases
- orchestration
What orchestrating-datacloud says it does
description: "Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this skill when the user needs a multi-step Data Cloud pipeline, cross-phase troublesh
compatibility: "Requires an external community sf data360 CLI plugin and a Data Cloud-enabled org"
Use this skill when the user needs **product-level Data Cloud workflow guidance** rather than a single isolated command family: pipeline setup, cross-phase troubleshooting, data spaces, data kits, or
npx skills add https://github.com/forcedotcom/sf-skills --skill orchestrating-datacloudAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2k |
|---|---|
| repo stars | ★ 763 |
| Security audit | 1 / 3 scanners passed |
| Last updated | July 24, 2026 |
| Repository | forcedotcom/sf-skills ↗ |
When should an agent use orchestrating-datacloud and what problem does it solve?
Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this skill when the user needs a multi-step Data Cloud pipeline, cross-phase troubleshooting, or dat
Who is it for?
Developers invoking orchestrating-datacloud as documented in the skill source.
Skip if: Skip when requirements fall outside orchestrating-datacloud documented scope.
When should I use this skill?
Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this skill when the user needs a multi-step Data Cloud pipeline, cross-phase troubleshooting, or dat
What you get
Outputs aligned with the orchestrating-datacloud SKILL.md workflow and stated deliverables.
- Cross-phase pipeline architecture guidance
- Data space and data kit management plan
Files
orchestrating-datacloud: Salesforce Data Cloud Orchestrator
Use this skill when the user needs product-level Data Cloud workflow guidance rather than a single isolated command family: pipeline setup, cross-phase troubleshooting, data spaces, data kits, or deciding whether a task belongs in Connect, Prepare, Harmonize, Segment, Act, or Retrieve.
This skill intentionally follows sf-skills house style while using the external sf data360 command surface as the runtime. The plugin is not vendored into this repo.
---
When This Skill Owns the Task
Use orchestrating-datacloud when the work involves:
- multi-phase Data Cloud setup or remediation
- data spaces (
sf data360 data-space *) - data kits (
sf data360 data-kit *) - health checks (
sf data360 doctor) - CRM-to-unified-profile pipeline design
- deciding how to move from ingestion → harmonization → segmentation → activation
- cross-phase troubleshooting where the root cause is not yet clear
Delegate to a phase-specific skill when the user is focused on one area:
| Phase | Use this skill | Typical scope |
|---|---|---|
| Connect | connecting-datacloud | connections, connectors, source discovery |
| Prepare | preparing-datacloud | data streams, DLOs, transforms, DocAI |
| Harmonize | harmonizing-datacloud | DMOs, mappings, identity resolution, data graphs |
| Segment | segmenting-datacloud | segments, calculated insights |
| Act | activating-datacloud | activations, activation targets, data actions |
| Retrieve | retrieving-datacloud | SQL, search indexes, vector search, async query |
Delegate outside the family when the user is:
- extracting Session Tracing / STDM telemetry → observing-agentforce
- writing CRM SOQL only → querying-soql
- loading CRM source data → handling-sf-data
- creating missing CRM schema → generating-custom-object or generating-custom-field
- implementing downstream Apex or Flow logic → generating-apex, generating-flow
---
Required Context to Gather First
Ask for or infer:
- target org alias
- whether the plugin is already installed and linked
- whether the user wants design guidance, read-only inspection, or live mutation
- data sources involved: CRM objects, external databases, file ingestion, knowledge, etc.
- desired outcome: unified profiles, segments, activations, vector search, analytics, or troubleshooting
- whether the user is working in the default data space or a custom one
- whether the org has already been classified with
scripts/diagnose-org.mjs - which command family is failing today, if any
If plugin availability or org readiness is uncertain, start with:
- references/plugin-setup.md
- references/feature-readiness.md
scripts/verify-plugin.shscripts/diagnose-org.mjsscripts/bootstrap-plugin.sh
---
Core Operating Rules
- Use the external
sf data360plugin runtime; do not reimplement or vendor the command layer. - Prefer the smallest phase-specific skill once the task is localized.
- Run readiness classification before mutation-heavy work. Prefer
scripts/diagnose-org.mjsover guessing from one failing command. - For
sf data360commands, suppress linked-plugin warning noise with2>/dev/nullunless the stderr output is needed for debugging. - Distinguish Data Cloud SQL from CRM SOQL.
- Do not treat
sf data360 doctoras a full-product readiness check; the current upstream command only checks the search-index surface. - Do not treat
query describeas a universal tenant probe; only use it with a known DMO/DLO table after broader readiness is confirmed. - Preserve Data Cloud-specific API-version workarounds when they matter.
- Prefer generic, reusable JSON definition files over org-specific workshop payloads.
---
Recommended Workflow
1. Verify the runtime and auth
Confirm:
sfis installed- the community Data Cloud plugin is linked
- the target org is authenticated
Recommended checks:
sf data360 man
sf org display -o <alias>
bash ./scripts/verify-plugin.sh <alias>Treat sf data360 doctor as a broad health signal, not the sole gate. On partially provisioned orgs it can fail even when read-only command families like connectors, DMOs, or segments still work.
2. Classify readiness before changing anything
Run the shared classifier first:
node ./scripts/diagnose-org.mjs -o <org> --jsonOnly use a query-plane probe after you know the table name is real:
node ./scripts/diagnose-org.mjs -o <org> --phase retrieve --describe-table MyDMO__dlm --jsonUse the classifier to distinguish:
- empty-but-enabled modules
- feature-gated modules
- query-plane issues
- runtime/auth failures
3. Discover existing state with read-only commands
Use targeted inspection after classification:
sf data360 doctor -o <org> 2>/dev/null
sf data360 data-space list -o <org> 2>/dev/null
sf data360 data-stream list -o <org> 2>/dev/null
sf data360 dmo list -o <org> 2>/dev/null
sf data360 identity-resolution list -o <org> 2>/dev/null
sf data360 segment list -o <org> 2>/dev/null
sf data360 activation platforms -o <org> 2>/dev/null4. Localize the phase
Route the task:
- source/connector issue → Connect
- ingestion/DLO/stream issue → Prepare
- mapping/IR/unified profile issue → Harmonize
- audience or insight issue → Segment
- downstream push issue → Act
- SQL/search/index issue → Retrieve
5. Choose deterministic artifacts when possible
Prefer JSON definition files and repeatable scripts over one-off manual steps. Generic templates live in:
assets/definitions/data-stream.template.jsonassets/definitions/dmo.template.jsonassets/definitions/mapping.template.jsonassets/definitions/relationship.template.jsonassets/definitions/identity-resolution.template.jsonassets/definitions/data-graph.template.jsonassets/definitions/calculated-insight.template.jsonassets/definitions/segment.template.jsonassets/definitions/activation-target.template.jsonassets/definitions/activation.template.jsonassets/definitions/data-action-target.template.jsonassets/definitions/data-action.template.jsonassets/definitions/search-index.template.json
6. Verify after each phase
Typical verification:
- stream/DLO exists
- DMO/mapping exists
- identity resolution run completed
- unified records or segment counts look correct
- activation/search index status is healthy
---
High-Signal Gotchas
connection listrequires--connector-type.dmo list --allis useful when you need the full catalog, but first-pagedmo listis often enough for readiness checks and much faster.- Segment creation may need
--api-version 64.0. segment membersreturns opaque IDs; use SQL joins for human-readable details.sf data360 doctorcan fail on partially provisioned orgs even when some read-only commands still work; fall back to targeted smoke checks.query describeerrors such asCouldn't find CDP tenant IDorDataModelEntity ... not foundare query-plane clues, not automatic proof that the whole product is disabled.- Many long-running jobs are asynchronous in practice even when the command returns quickly.
- Some Data Cloud operations still require UI setup outside the CLI runtime.
---
Output Format
When finishing, report in this order: 1. Task classification 2. Runtime status 3. Readiness classification 4. Phase(s) involved 5. Commands or artifacts used 6. Verification result 7. Next recommended step
Suggested shape:
Data Cloud task: <setup / inspect / troubleshoot / migrate>
Runtime: <plugin ready / missing / partially verified>
Readiness: <ready / ready_empty / partial / feature_gated / blocked>
Phases: <connect / prepare / harmonize / segment / act / retrieve>
Artifacts: <json files, commands, scripts>
Verification: <passed / partial / blocked>
Next step: <next phase, setup guidance, or cross-skill handoff>---
Cross-Skill Integration
| Need | Delegate to | Reason |
|---|---|---|
| load or clean CRM source data | handling-sf-data | seed or fix source records before ingestion |
| create missing CRM schema | generating-custom-object, generating-custom-field | Data Cloud expects existing objects/fields |
| deploy permissions or bundles | deploying-metadata | environment preparation |
| write Apex against Data Cloud outputs | generating-apex | code implementation |
| Flow automation after segmentation/activation | generating-flow | declarative orchestration |
| session tracing / STDM / parquet analysis | observing-agentforce | different Data Cloud use case |
---
Reference Map
Start here
- README.md
- references/plugin-setup.md
- references/feature-readiness.md
- UPSTREAM.md
Phase skills
- connecting-datacloud
- preparing-datacloud
- harmonizing-datacloud
- segmenting-datacloud
- activating-datacloud
- retrieving-datacloud
Deterministic helpers
- scripts/bootstrap-plugin.sh
- scripts/verify-plugin.sh
- scripts/diagnose-org.mjs
- assets/definitions/
{
"developerName": "CRM_Target",
"displayName": "CRM Target",
"description": "Example activation target definition for a downstream destination"
}
{
"developerName": "High_Value_Customers_Activation",
"displayName": "High Value Customers Activation",
"description": "Example activation linking a published segment to a destination target",
"segmentName": "High_Value_Customers",
"activationTargetName": "CRM_Target"
}
{
"developerName": "Lifetime_Value",
"displayName": "Lifetime Value",
"description": "Example calculated insight over an order-style DMO",
"definitionType": "CALCULATED_METRIC",
"expression": "SELECT ssot__IndividualId__c, SUM(ssot__TotalAmount__c) AS total_spend FROM ssot__SalesOrder__dlm GROUP BY ssot__IndividualId__c"
}
{
"developerName": "Webhook_Target",
"displayName": "Webhook Target",
"description": "Example data action target for downstream delivery"
}
{
"developerName": "Notify_High_Value_Customer_System",
"displayName": "Notify High Value Customer System",
"description": "Example data action definition that uses a downstream data action target"
}
{
"developerName": "Customer_360_Graph",
"displayName": "Customer 360 Graph",
"description": "Example Data Graph rooted on a unified customer entity",
"sourceObject": {
"name": "UnifiedssotIndividualMain__dlm",
"type": "derived",
"fields": [
{
"name": "ssot__Id__c"
},
{
"name": "ssot__FirstName__c"
},
{
"name": "ssot__LastName__c"
}
],
"relatedObjects": []
}
}
{
"name": "Customer_Stream",
"label": "Customer Stream",
"datasource": "SalesforceDotCom_Home",
"datastreamType": "CONNECTORSFRAMEWORK",
"connectorInfo": {
"connectorType": "SalesforceDotCom",
"connectorDetails": {
"name": "SalesforceDotCom_Home",
"sourceObject": "Custom_Object__c"
}
},
"dataLakeObjectInfo": {
"label": "Customer",
"name": "Customer__dll",
"category": "Profile",
"dataspaceInfo": [
{
"name": "Default"
}
],
"dataLakeFieldInputRepresentations": [
{
"name": "Id",
"label": "Record ID",
"dataType": "Text",
"isPrimaryKey": true
},
{
"name": "External_Id_c",
"label": "External ID",
"dataType": "Text",
"isPrimaryKey": false
}
]
},
"sourceFields": [
{
"name": "Id",
"dataType": "Text"
},
{
"name": "External_Id__c",
"dataType": "Text"
}
],
"mappings": [],
"refreshConfig": {
"isAccelerationEnabled": true,
"refreshMode": "UPSERT",
"frequency": {
"frequencyType": "HOURLY"
}
}
}
{
"developerName": "Customer_Profile__dlm",
"label": "Customer Profile",
"category": "Profile",
"fields": [
{
"name": "External_Id_c__c",
"label": "External ID",
"type": "Text"
},
{
"name": "Preferred_Tier_c__c",
"label": "Preferred Tier",
"type": "Text"
}
]
}
{
"label": "Main",
"description": "Generic identity resolution ruleset using customer identifiers and contact points",
"configurationType": "individual",
"rulesetId": "main",
"doesRunAutomatically": false,
"matchRules": [
{
"label": "Exact Email",
"criteria": [
{
"entityName": "ssot__ContactPointEmail__dlm",
"fieldName": "ssot__EmailAddress__c",
"matchMethodType": "exactnormalized",
"caseSensitiveMatch": false,
"shouldMatchOnBlank": false
}
]
}
],
"reconciliationRules": [
{
"entityName": "ssot__Individual__dlm",
"ruleType": "lastupdated",
"shouldIgnoreEmptyValue": true,
"sources": [],
"fields": []
}
]
}
{
"sourceObjectName": "Customer__dll",
"targetObjectName": "Customer_Profile__dlm",
"fieldMappings": [
{
"sourceFieldName": "External_Id_c",
"targetFieldName": "External_Id_c__c"
},
{
"sourceFieldName": "Preferred_Tier_c",
"targetFieldName": "Preferred_Tier_c__c"
}
]
}
{
"relationships": [
{
"sourceObjectName": "Order_Header__dlm",
"targetObjectName": "ssot__Individual__dlm",
"cardinality": "ManyToOne",
"sourceFieldName": "Customer_ID_c__c",
"targetFieldName": "ssot__PartyId__c",
"relationshipOwner": "DataCloud"
}
]
}
{
"developerName": "Knowledge_Index",
"displayName": "Knowledge Index",
"description": "Example semantic search index for a structured or unstructured Data Cloud source",
"sourceObject": "KnowledgeArticleVersion__dlm",
"embeddingModel": "e5_large_v2",
"chunkingStrategy": "passage_extraction",
"similarityMetric": "COSINE"
}
{
"displayName": "High Value Customers",
"developerName": "High_Value_Customers",
"description": "Example segment built from a unified DMO",
"segmentType": "Dbt",
"includeDbt": {
"models": {
"models": [
{
"name": "UnifiedCustomers",
"sql": "SELECT ui.ssot__Id__c FROM UnifiedssotIndividualMain__dlm ui JOIN ssot__SalesOrder__dlm so ON ui.ssot__Id__c = so.ssot__IndividualId__c GROUP BY ui.ssot__Id__c HAVING SUM(so.ssot__TotalAmount__c) > 1000"
}
]
}
}
}
Credits & Acknowledgments
This skill family distills publicly shared Data Cloud implementation knowledge into sf-skills house style. Attribution is intentionally explicit because contributor credit is a core sf-skills principle.
---
This family intentionally:
- keeps sf-skills naming consistency (
*-datacloud) - keeps the external CLI plugin outside this repo
- favors deterministic helper scripts and reusable JSON templates
- rewrites examples into generic sf-skills-style guidance rather than copying workshop-specific payloads
See UPSTREAM.md for the maintenance contract.
---
orchestrating-datacloud
Salesforce Data Cloud skill family for sf-skills. This is the cross-phase orchestrator for community-driven Data Cloud workflows built around the external sf data360 CLI runtime.
What this skill is for
Use orchestrating-datacloud when the task spans multiple Data Cloud phases:
- connection + ingestion + harmonization setup
- troubleshooting a Data Cloud pipeline end to end
- managing data spaces or data kits
- deciding which specialized Data Cloud skill to use next
What this skill is not
- It does not vendor or fork the external Data Cloud CLI plugin.
- It does not use MCP.
- It does not replace phase-specific skills once the problem is localized.
- It does not cover STDM/session tracing/parquet analysis; use
observing-agentforcefor that.
Data Cloud skill family
| Skill | Purpose |
|---|---|
| orchestrating-datacloud | Orchestrator, data spaces, data kits, cross-phase workflows |
| connecting-datacloud | Connections, connectors, source discovery |
| preparing-datacloud | Data streams, DLOs, transforms, DocAI |
| harmonizing-datacloud | DMOs, mappings, identity resolution, data graphs |
| segmenting-datacloud | Segments, calculated insights |
| activating-datacloud | Activations, activation targets, data actions |
| retrieving-datacloud | SQL, async query, vector search, search indexes |
Runtime model
This family assumes:
- Salesforce CLI (
sf) - a Data Cloud-enabled org
- the external community
sf data360plugin linked intosf
See references/plugin-setup.md.
Deterministic helpers included
| Path | Purpose |
|---|---|
| scripts/bootstrap-plugin.sh | Clone/update the community plugin, compile it, and link it into sf |
| scripts/verify-plugin.sh | Check that the runtime is available before starting Data Cloud work |
| scripts/diagnose-org.mjs | Classify org readiness by phase before mutating Data Cloud assets |
| references/feature-readiness.md | Map high-signal errors and feature gates to concrete next steps |
| assets/definitions/ | Generic JSON templates for repeatable Data Cloud definition files |
| UPSTREAM.md | Upstream mapping for future distillation and maintenance |
Generic templates
The family includes reusable starting points for:
- data streams
- DMOs
- mappings
- identity resolution rulesets
- segments
- search indexes
These are intentionally generic and should be adapted to the target org.
Quick start
1. Verify the runtime
bash ./scripts/verify-plugin.sh
# or with an org alias
bash ./scripts/verify-plugin.sh myorgThe helper treats sf data360 doctor as advisory and falls back to additional read-only smoke checks when an org is only partially provisioned.
2. Diagnose feature readiness before mutating
node ./scripts/diagnose-org.mjs -o myorg --json
# optional retrieve-plane probe, only when you know the table is real
node ./scripts/diagnose-org.mjs -o myorg --phase retrieve --describe-table MyDMO__dlm --jsonUse the diagnose helper to distinguish between:
- feature-gated modules
- empty-but-enabled modules
- query-plane issues
- runtime/auth problems
3. Bootstrap the plugin if needed
python3 ~/.claude/sf-skills-install.py --with-datacloud-runtime
# or run the helper script directly
bash ./scripts/bootstrap-plugin.sh4. Start with read-only inspection
sf data360 man
sf data360 doctor -o myorg 2>/dev/null
sf data360 dmo list -o myorg 2>/dev/null
sf data360 segment list -o myorg 2>/dev/null
sf data360 activation platforms -o myorg 2>/dev/nullCommon examples
"Set up a Customer 360 proof of concept in Data Cloud"
"Troubleshoot why my unified profiles are not increasing"
"I need to figure out whether this issue is in mappings, identity resolution, or segment SQL"
"Show me how to inspect data spaces and data kits for this org"References
- SKILL.md - Orchestrator guidance
- references/plugin-setup.md - Plugin install and verification
- references/feature-readiness.md - Readiness classification and setup guidance
- UPSTREAM.md - Upstream tracking and distillation policy
- CREDITS.md - Contributor and source attribution
Primary contributor
Gnanasekaran Thoppae — primary contributor for the orchestrating-datacloud family.
Data Cloud Feature Readiness
Use this guide when a Data Cloud command fails and you need to decide whether the issue is:
- runtime / plugin setup
- org authentication
- product provisioning
- feature gating
- empty-but-enabled configuration
- a bad table name or wrong probe
The goal is to detect first, classify second, and guide third instead of blindly executing a command and surfacing a raw error.
Core principle
Do not treat one failing command as proof that all of Data Cloud is unavailable.
Different command families hit different backend surfaces. A failure in one area can coexist with successful read-only access in another.
Examples:
sf data360 doctorchecks the search-index endpoint only.sf data360 query describechecks the query plane and requires a real DMO/DLO table name.sf data360 dmo listchecks a catalog/listing endpoint.sf data360 activation platformschecks the activation destination surface.
Recommended first step
Run the shared readiness classifier before mutation-heavy work:
node ../scripts/diagnose-org.mjs -o myorg --jsonFor retrieve/query work, only add a table probe when you already know the table name is real:
node ../scripts/diagnose-org.mjs -o myorg --phase retrieve --describe-table MyDMO__dlm --jsonSignal matrix
| Signal | What it usually means | What to do next | What not to assume |
|---|---|---|---|
sf data360 man fails | Runtime/plugin missing | Install or relink the community runtime | Do not debug org features yet |
sf org display -o <org> fails | Org auth missing | Re-authenticate the org | Do not blame Data Cloud |
No results. | Feature is reachable but currently empty | Continue with create/setup flow | Do not say the feature is disabled |
This feature is not currently enabled for this user type or org: [CdpXxx] | Specific module is gated for the current org/user | Guide the user to setup/provisioning/permission review for that module | Do not say the entire product is disabled |
Couldn't find CDP tenant ID. Please enable CDP first. | The query plane could not resolve a CDP tenant for that request | Re-check broader readiness with data-space list, dmo list, and doctor; then retry with a known table if appropriate | Do not treat this as universal proof that all Data Cloud endpoints are off |
NOT_FOUND: DataModelEntity ... is not found | The table name is not queryable in that org | Pick a real DMO/DLO from dmo list, dlo list, or dmo get | Do not say the whole query feature is unavailable |
Request failed | Generic endpoint failure or inconclusive response | Fall back to neighboring read-only probes | Do not stop after one generic failure |
High-signal feature gates
CdpDataStreams
Typical impact:
sf data360 data-stream list- prepare / ingestion workflows
Suggested guidance:
- review Data Cloud Setup provisioning
- review source connector readiness
- confirm the user has the right Data Cloud permissions
- for Salesforce CRM ingestion, confirm the connector/integration user has object + field read access in the source org
CdpIdentityResolution
Typical impact:
sf data360 identity-resolution list- harmonize / unified profile workflows
Suggested guidance:
- review harmonization and identity-resolution entitlements
- verify Data Cloud permission sets for the acting user
- confirm upstream DLO/DMO work is already healthy before retrying IR
CdpActivationTarget
Typical impact:
sf data360 activation-target list- downstream audience delivery setup
Suggested guidance:
- review Data Cloud activation permissions
- review target/destination setup in Data Cloud Setup
- confirm the org/edition actually exposes activation-target management for that user
CdpActivationExternalPlatform
Typical impact:
sf data360 activation platforms- platform catalog for destinations such as ads or storage targets
Suggested guidance:
- review Activation Targets setup
- review destination-specific authentication/configuration
- check whether the org exposes additional toggles in Data Cloud Setup → Feature Manager
CdpDataSpace
Typical impact:
sf data360 data-space list- core multi-space administration
Suggested guidance:
- review core Data Cloud provisioning and user access
- confirm the user is intended to administer/view data spaces
What is usually not fully programmatic
Do not promise a pure CLI flow for:
- initial Data Cloud tenant provisioning
- license assignment
- every org-wide Data Cloud enablement step
These commonly require Setup UI, provisioning, licensing, or account-level activation.
What is often programmatic after provisioning
Once the org is properly provisioned, many workflows are programmatic through sf data360, including:
- data-space listing / get / create / update
- DMO catalog inspection and some DMO mutations
- segment and calculated insight lifecycle operations
- activation target and data action target operations
- search-index lifecycle operations
- hybrid search and related retrieve-plane workflows on newer runtime versions
Exact coverage still depends on org entitlements and the user's permissions.
Known partial-automation gap
Some external database connectors can be created via API while the corresponding data-stream creation flow still requires UI steps or org-specific browser automation.
Practical guidance:
- treat connection creation and stream creation as separate capability checks
- do not assume a successful external connection create call means
data-stream createwill work for that connector - if the org relies on that path, guide the user toward manual UI creation or a locally validated Playwright/browser automation helper rather than promising a generic CLI-only workflow
User-facing guidance model
When blocked, respond in this order: 1. Classify the failing surface — runtime, auth, provisioning, feature gate, empty state, or bad table 2. Show the evidence — the specific command + high-signal error text 3. Give the next setup step — Data Cloud Setup, permissions, Feature Manager, source-object permissions, destination auth, etc. 4. Avoid false claims — don't say "Data Cloud is off" unless multiple core probes support that conclusion
Setup guidance to point users toward
Depending on the failing feature, guide users to review:
- Setup → Data Cloud Setup for core provisioning / Get Started flow
- Standard Data Cloud permission sets appropriate to the task (for example Architect/Admin vs activation-focused roles)
- Data Cloud Setup → Feature Manager for org-specific toggles or beta features that are actually exposed there
- Source org permissions for CRM ingestion users when streams/connectors depend on object/field access
- Activation target and destination authentication when activation features are partially enabled but not usable yet
Skill author checklist
Before telling the user a feature is unavailable:
- [ ] Did I run a targeted probe for this phase?
- [ ] Did I check at least one neighboring read-only probe?
- [ ] Did I avoid treating
doctoras a full product readiness check? - [ ] Did I avoid treating
query describeas a universal tenant probe? - [ ] Did I tell the user exactly what setup area to review next?
Data Cloud Community Plugin Setup
The orchestrating-datacloud family uses a community `sf data360` CLI runtime. sf-skills does not vendor or fork that plugin.
Why this setup exists
- keeps sf-skills focused on skills, prompts, docs, and templates
- lets the upstream runtime continue to evolve independently
- avoids MCP and keeps execution deterministic
Prerequisites
- Node.js 18+
- yarn
- Salesforce CLI (
sf) - git
- a Data Cloud-enabled org authenticated with
sf org login web -a <alias>
Recommended setup path
If you use the Python installer, it can install this optional runtime for you:
python3 ~/.claude/sf-skills-install.py --with-datacloud-runtimeOr use the helper script directly:
bash ../scripts/bootstrap-plugin.shBy default it clones the plugin into ~/.sf-community-tools/datacloud/sf-cli-plugin-data360, installs dependencies, compiles it, and links it into the local Salesforce CLI.
Manual setup
git clone https://github.com/Jaganpro/sf-cli-plugin-data360.git
cd sf-cli-plugin-data360
yarn install
npx tsc
node ../scripts/generate-manifest.mjs .
sf plugins link .Verification
sf data360 man
bash ../scripts/verify-plugin.sh
bash ../scripts/verify-plugin.sh myorg
node ../scripts/diagnose-org.mjs -o myorg --jsonFor newer command families such as sf data360 query hybrid and recent pagination fixes, update the community runtime to the latest upstream commit by re-running the bootstrap helper.
sf data360 doctor is useful, but it is not the only readiness signal. On partially provisioned orgs it can fail even when other read-only Data Cloud commands still work. The helper script treats doctor as advisory and falls back to additional smoke checks.
Use diagnose-org.mjs when you need phase-specific readiness classification instead of a simple pass/fail check. It helps distinguish:
- empty-but-enabled modules
- feature-gated modules
- query-plane issues
- runtime/auth failures
Output-noise tip
When using linked community plugins, stderr can include warning noise. For normal usage, prefer:
sf data360 dmo list --all -o myorg 2>/dev/null
sf data360 segment list -o myorg 2>/dev/nullTroubleshooting
ESM auto-transpile warning
If you see Warning: @gthoppae/sf-cli-plugin-data360 is a linked ESM module and cannot be auto-transpiled, generate the oclif command manifest:
node ../scripts/generate-manifest.mjs ~/.sf-community-tools/datacloud/sf-cli-plugin-data360This tells oclif to use pre-compiled output directly instead of attempting auto-transpilation. The npx oclif manifest alternative may fail on newer Node.js versions due to @oclif/core version mismatches.
Clone error references gthoppae/sf-cli-plugin-data360
If the clone failure mentions gthoppae/sf-cli-plugin-data360, your local ~/.claude/sf-skills-install.py copy is outdated. Refresh the installer first, then retry the optional runtime install:
python3 ~/.claude/sf-skills-install.py --force-update
python3 ~/.claude/sf-skills-install.py --with-datacloud-runtimeOr rerun the latest installer directly from GitHub:
curl -sSL https://raw.githubusercontent.com/Jaganpro/sf-skills/main/tools/install.py | python3 - --with-datacloud-runtimePlugin not found after install
If sf was installed globally (with sudo), the default data directory may be root-owned. Set SF_DATA_DIR in your shell profile:
export SF_DATA_DIR="${HOME}/.local/share/sf"Then re-run sf plugins link . from the plugin directory, or re-run the bootstrap script.
What to do if the plugin is missing
1. run the bootstrap script 2. re-open your shell if sf plugin discovery is stale 3. verify with sf data360 man 4. only then start live Data Cloud work
Setup guidance reminder
The runtime can help you detect missing capability, but it cannot fully replace Setup for:
- initial Data Cloud provisioning / tenant creation
- license assignment
- every org-wide feature enablement step
When a module is gated, guide users toward the right setup area instead of promising a fully programmatic enablement flow. See feature-readiness.md.
Scope reminder
This setup is for the Data Cloud product family:
orchestrating-datacloudconnecting-datacloudpreparing-datacloudharmonizing-datacloudsegmenting-datacloudactivating-datacloudretrieving-datacloud
For STDM/session tracing/parquet work, use observing-agentforce instead of this plugin-focused family.
#!/usr/bin/env bash
set -euo pipefail
PLUGIN_REPO="${PLUGIN_REPO:-https://github.com/Jaganpro/sf-cli-plugin-data360.git}"
BASE_DIR="${1:-${HOME}/.sf-community-tools/datacloud}"
PLUGIN_DIR="${BASE_DIR}/sf-cli-plugin-data360"
export SF_DATA_DIR="${SF_DATA_DIR:-${HOME}/.local/share/sf}"
need() {
command -v "$1" >/dev/null 2>&1 || {
echo "Missing required command: $1" >&2
exit 1
}
}
need git
need node
need yarn
need sf
need npx
mkdir -p "${BASE_DIR}"
if [[ -d "${PLUGIN_DIR}/.git" ]]; then
echo "Updating existing plugin checkout: ${PLUGIN_DIR}"
git -C "${PLUGIN_DIR}" pull --ff-only
else
echo "Cloning plugin into: ${PLUGIN_DIR}"
git clone "${PLUGIN_REPO}" "${PLUGIN_DIR}"
fi
cd "${PLUGIN_DIR}"
echo "Installing dependencies..."
yarn install
echo "Compiling plugin..."
npx tsc
echo "Generating oclif command manifest..."
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
node "${SCRIPT_DIR}/generate-manifest.mjs" "${PLUGIN_DIR}"
echo "Linking plugin into Salesforce CLI..."
mkdir -p "${SF_DATA_DIR}"
sf plugins link .
echo "Verifying runtime..."
sf data360 man >/dev/null
echo "Done. Community Data Cloud runtime is linked."
echo "Location: ${PLUGIN_DIR}"
echo "Try: sf data360 man"
#!/usr/bin/env node
import { spawnSync } from 'node:child_process';
const HELP = `Data Cloud org readiness classifier
Usage:
node diagnose-org.mjs -o <orgAlias> [--json] [--phase <phase>] [--describe-table <table>] [--timeout <seconds>]
Options:
-o, --target-org Salesforce org alias or username (required)
--json Print machine-readable JSON
--phase Optional phase focus: all | connect | prepare | harmonize | segment | act | retrieve
--describe-table Optional DMO/DLO table name for a retrieve-plane probe
--timeout Per-command timeout in seconds (default: 45)
-h, --help Show this help text
`;
const FEATURE_GUIDANCE = {
CdpDataStreams: 'Data Streams are unavailable for this org/user. Review Data Cloud Setup provisioning, ingestion-related feature availability, and source connector permissions before using preparing-datacloud.',
CdpIdentityResolution: 'Identity Resolution is unavailable for this org/user. Review Data Cloud harmonization/identity-resolution entitlements and the user\'s Data Cloud permissions before using harmonizing-datacloud for IR work.',
CdpActivationTarget: 'Activation Targets are unavailable for this org/user. Review activation permissions, destination setup, and any org-specific activation enablement before using activating-datacloud.',
CdpActivationExternalPlatform: 'Activation destination platforms are unavailable for this org/user. Review Activation Targets setup, destination auth/configuration, and any feature toggles exposed in Data Cloud Setup → Feature Manager.',
CdpDataSpace: 'Data Spaces are unavailable for this org/user. Review core Data Cloud provisioning and user permissions in Data Cloud Setup before assuming downstream phases can work.',
};
const CAVEATS = [
'sf data360 doctor is advisory only: the current upstream command checks the search-index endpoint, not every Data Cloud module.',
'Do not use query describe as a universal tenant probe. Run it only after confirming broader readiness and only against a known DMO or DLO table.',
'Core Data Cloud provisioning, tenant creation, and license assignment are not reliably exposed as a full CLI enablement flow. Use CLI detection plus Setup guidance instead of promising fully programmatic enablement.',
];
function parseArgs(argv) {
const args = { phase: 'all', timeout: 45, json: false, describeTable: null };
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
switch (arg) {
case '-o':
case '--target-org':
args.targetOrg = argv[++i];
break;
case '--phase':
args.phase = argv[++i] ?? 'all';
break;
case '--describe-table':
args.describeTable = argv[++i] ?? null;
break;
case '--timeout':
args.timeout = Number(argv[++i] ?? '45');
break;
case '--json':
args.json = true;
break;
case '-h':
case '--help':
args.help = true;
break;
default:
throw new Error(`Unknown argument: ${arg}`);
}
}
return args;
}
function trimText(text) {
return (text || '').replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, '').trim();
}
function runCommand(command, args, { json = false, timeoutSeconds = 45 } = {}) {
const finalArgs = [...args];
if (json && !finalArgs.includes('--json')) finalArgs.push('--json');
const result = spawnSync(command, finalArgs, {
encoding: 'utf8',
timeout: timeoutSeconds * 1000,
});
const stdout = result.stdout || '';
const stderr = result.stderr || '';
let parsed = null;
if (stdout.trim()) {
try {
parsed = JSON.parse(stdout);
} catch {
parsed = null;
}
}
let errorMessage = null;
if (result.error) {
if (result.error.code === 'ENOENT') {
errorMessage = `${command} is not installed or not on PATH.`;
} else if (result.error.code === 'ETIMEDOUT') {
errorMessage = `Timed out after ${timeoutSeconds}s`;
} else {
errorMessage = result.error.message;
}
}
return {
command: [command, ...finalArgs].join(' '),
exitCode: typeof result.status === 'number' ? result.status : 1,
stdout: trimText(stdout),
stderr: trimText(stderr),
parsed,
errorMessage,
};
}
function extractSuccessSample(parsed) {
const result = parsed?.result ?? {};
if (Array.isArray(result?.data)) {
return result.data[0] ?? null;
}
if (Array.isArray(result?.data?.platforms)) {
return result.data.platforms[0] ?? null;
}
if (Array.isArray(result?.semanticSearchDefinitionDetails)) {
return result.semanticSearchDefinitionDetails[0] ?? null;
}
return null;
}
function extractDetails(parsed) {
const result = parsed?.result ?? {};
if (result && typeof result === 'object' && !Array.isArray(result)) {
const details = { ...result };
delete details.data;
if (details.status || details.indexCount !== undefined || details.apiVersion || details.instanceUrl) {
return details;
}
}
return undefined;
}
function extractCount(parsed) {
const result = parsed?.result ?? {};
if (Array.isArray(result?.data)) return result.data.length;
if (typeof result?.totalSize === 'number') return result.totalSize;
if (Array.isArray(result?.data?.platforms)) return result.data.platforms.length;
if (typeof result?.indexCount === 'number') return result.indexCount;
return null;
}
function classifyError(message) {
const text = message || '';
const gateMatch = text.match(/\[([A-Za-z0-9]+)\]/);
if (text.includes("Couldn't find CDP tenant ID")) {
return {
state: 'query_service_unavailable',
code: 'QUERY_SERVICE_TENANT_LOOKUP_FAILED',
reason: 'The query service could not resolve a CDP tenant for this org context. Confirm broader readiness with data-space, DMO, or doctor probes before declaring Data Cloud fully disabled.',
};
}
if (text.includes('This feature is not currently enabled for this user type or org')) {
const featureCode = gateMatch?.[1] ?? 'UNKNOWN_FEATURE_GATE';
return {
state: 'feature_gated',
code: featureCode,
reason: FEATURE_GUIDANCE[featureCode] ?? 'This capability is gated for the current org or user. Review provisioning, permissions, and any relevant setup toggles before proceeding.',
};
}
if (text.includes('NOT_FOUND: DataModelEntity')) {
return {
state: 'table_not_found',
code: 'DATA_MODEL_ENTITY_NOT_FOUND',
reason: 'The specified DMO or DLO table name is not queryable in this org. Pick a real table from dmo list / dlo list or use dmo get first.',
};
}
if (text.includes('Request failed')) {
return {
state: 'request_failed',
code: 'REQUEST_FAILED',
reason: 'The endpoint returned a generic request failure. Treat this as inconclusive and confirm readiness with adjacent read-only probes.',
};
}
if (text.includes('is not a sf command') || text.includes('not installed or not on PATH')) {
return {
state: 'runtime_missing',
code: 'RUNTIME_MISSING',
reason: 'The sf data360 runtime is not available. Install or relink the community plugin first.',
};
}
if (text.includes('Timed out after')) {
return {
state: 'timeout',
code: 'TIMEOUT',
reason: 'The probe timed out. Retry, reduce the scope, or fall back to a smaller read-only command family.',
};
}
return {
state: 'unknown_error',
code: 'UNKNOWN_ERROR',
reason: 'The probe failed for an unclassified reason. Inspect the raw message and confirm readiness with neighboring probes.',
};
}
function normalizeProbe(name, raw, meta = {}) {
const base = {
name,
command: raw.command,
exitCode: raw.exitCode,
stderr: raw.stderr || undefined,
...meta,
};
if (raw.errorMessage) {
const error = classifyError(raw.errorMessage);
return { ...base, ...error, message: raw.errorMessage };
}
if (raw.parsed && (raw.parsed.status === 0 || raw.exitCode === 0)) {
const count = extractCount(raw.parsed);
const sample = extractSuccessSample(raw.parsed);
const details = extractDetails(raw.parsed);
let state = 'ok';
if (count !== null) {
state = count > 0 ? 'enabled_populated' : 'enabled_empty';
}
if (raw.parsed?.result?.status === 'ok') {
state = 'ok';
}
return {
...base,
state,
count,
sample: sample ?? undefined,
details,
};
}
const message = raw.parsed?.message || raw.stdout || raw.stderr || `Command failed with exit code ${raw.exitCode}`;
const error = classifyError(message);
return { ...base, ...error, message };
}
function summarizePhase(checks) {
const states = Object.values(checks).map((check) => check.state);
if (states.length === 0) return 'skipped';
if (states.every((state) => state === 'skipped')) return 'skipped';
const hasSuccess = states.some((state) => ['ok', 'enabled_empty', 'enabled_populated'].includes(state));
const hasPopulated = states.includes('enabled_populated');
const hasBlocking = states.some((state) => ['feature_gated', 'query_service_unavailable', 'request_failed', 'table_not_found', 'timeout', 'unknown_error'].includes(state));
if (hasSuccess && hasBlocking) return 'partial';
if (hasPopulated) return 'ready';
if (hasSuccess) return 'ready_empty';
if (states.every((state) => state === 'feature_gated')) return 'feature_gated';
if (states.every((state) => state === 'query_service_unavailable')) return 'query_unavailable';
if (states.every((state) => ['request_failed', 'timeout', 'unknown_error'].includes(state))) return 'blocked';
return 'unknown';
}
function guidanceFromProbe(scope, probe) {
if (!probe) return [];
if (['ok', 'enabled_empty', 'enabled_populated', 'skipped'].includes(probe.state)) return [];
if (probe.state === 'runtime_missing') {
return [
'Install or relink the community sf data360 runtime before attempting Data Cloud work.',
'Use python3 ~/.claude/sf-skills-install.py --with-datacloud-runtime or bash ./scripts/bootstrap-plugin.sh.',
];
}
if (probe.state === 'query_service_unavailable') {
return [
`${scope}: query-specific tenant lookup failed. Do not treat this as a global Data Cloud outage by itself. Re-check core probes such as data-space list, dmo list, and doctor, then use a known table name if you retry query describe.`,
];
}
if (probe.state === 'feature_gated') {
return [`${scope}: ${probe.reason}`];
}
if (probe.state === 'table_not_found') {
return [`${scope}: ${probe.reason}`];
}
if (probe.state === 'request_failed') {
return [
`${scope}: ${probe.reason}`,
'If doctor is the failing probe, remember that it only checks search indexes; use adjacent read-only probes before deciding the whole org is blocked.',
];
}
if (probe.state === 'timeout') {
return [`${scope}: ${probe.reason}`];
}
return [`${scope}: ${probe.reason}`];
}
function parseOrgDisplay(raw, targetOrg) {
const base = {
alias: targetOrg,
state: 'ok',
};
if (raw.errorMessage) {
return { ...base, state: 'org_not_authenticated', message: raw.errorMessage };
}
if (raw.parsed && raw.parsed.status === 0) {
const result = raw.parsed.result || {};
return {
...base,
alias: result.alias || targetOrg,
username: result.username,
instanceUrl: result.instanceUrl,
apiVersion: result.apiVersion,
connectedStatus: result.connectedStatus,
};
}
const message = raw.parsed?.message || raw.stdout || raw.stderr || `Failed to resolve org ${targetOrg}`;
return {
...base,
state: 'org_not_authenticated',
message,
};
}
function buildProbeMatrix(orgAlias, describeTable) {
return {
core: {
doctor: ['data360', 'doctor', '-o', orgAlias],
dataSpaces: ['data360', 'data-space', 'list', '-o', orgAlias],
dmos: ['data360', 'dmo', 'list', '-o', orgAlias],
},
phases: {
connect: {
connectorCatalog: ['data360', 'connection', 'connector-list', '-o', orgAlias],
connectionsSalesforceCRM: ['data360', 'connection', 'list', '-o', orgAlias, '--connector-type', 'SalesforceCRM'],
},
prepare: {
dataStreams: ['data360', 'data-stream', 'list', '-o', orgAlias],
dlos: ['data360', 'dlo', 'list', '-o', orgAlias],
},
harmonize: {
dmos: ['data360', 'dmo', 'list', '-o', orgAlias],
identityResolution: ['data360', 'identity-resolution', 'list', '-o', orgAlias],
},
segment: {
segments: ['data360', 'segment', 'list', '-o', orgAlias],
calculatedInsights: ['data360', 'calculated-insight', 'list', '-o', orgAlias],
},
act: {
activationPlatforms: ['data360', 'activation', 'platforms', '-o', orgAlias],
activationTargets: ['data360', 'activation-target', 'list', '-o', orgAlias],
dataActionTargets: ['data360', 'data-action-target', 'list', '-o', orgAlias],
},
retrieve: {
searchIndexes: ['data360', 'search-index', 'list', '-o', orgAlias],
queryDescribe: describeTable
? ['data360', 'query', 'describe', '-o', orgAlias, '--table', describeTable]
: null,
},
},
};
}
function printTextReport(report) {
const lines = [];
lines.push(`Data Cloud readiness for ${report.org.alias}`);
lines.push(`Runtime: ${report.runtime.state}`);
if (report.runtime.message) lines.push(` ${report.runtime.message}`);
lines.push(`Org auth: ${report.org.state}`);
if (report.org.username) lines.push(` User: ${report.org.username}`);
if (report.org.instanceUrl) lines.push(` Instance: ${report.org.instanceUrl}`);
lines.push('');
lines.push('Core probes:');
for (const [name, probe] of Object.entries(report.core)) {
lines.push(` - ${name}: ${probe.state}${probe.count !== null && probe.count !== undefined ? ` (${probe.count})` : ''}`);
if (probe.code) lines.push(` code: ${probe.code}`);
if (probe.message) lines.push(` ${probe.message}`);
}
lines.push('');
lines.push('Phase readiness:');
for (const [phase, entry] of Object.entries(report.phases)) {
lines.push(` ${phase}: ${entry.summary}`);
for (const [name, probe] of Object.entries(entry.checks)) {
lines.push(` - ${name}: ${probe.state}${probe.count !== null && probe.count !== undefined ? ` (${probe.count})` : ''}`);
if (probe.code) lines.push(` code: ${probe.code}`);
if (probe.message) lines.push(` ${probe.message}`);
}
}
lines.push('');
lines.push('Caveats:');
for (const caveat of report.caveats) {
lines.push(` - ${caveat}`);
}
lines.push('');
lines.push('Guidance:');
if (report.guidance.length === 0) {
lines.push(' - No blocking issues detected from the chosen probes. Continue with read-only inspection, then mutate intentionally.');
} else {
for (const item of report.guidance) {
lines.push(` - ${item}`);
}
}
console.log(lines.join('\n'));
}
function main() {
let args;
try {
args = parseArgs(process.argv.slice(2));
} catch (error) {
console.error(error.message);
console.error('');
console.error(HELP);
process.exit(1);
}
if (args.help) {
console.log(HELP);
process.exit(0);
}
if (!args.targetOrg) {
console.error('Missing required --target-org / -o argument.');
console.error('');
console.error(HELP);
process.exit(1);
}
const runtimeCheck = runCommand('sf', ['data360', 'man'], { json: false, timeoutSeconds: args.timeout });
const runtime = runtimeCheck.exitCode === 0
? { state: 'ok', command: runtimeCheck.command }
: { ...classifyError(runtimeCheck.stderr || runtimeCheck.stdout || runtimeCheck.errorMessage || 'sf data360 runtime is unavailable'), command: runtimeCheck.command };
const orgDisplay = parseOrgDisplay(
runCommand('sf', ['org', 'display', '-o', args.targetOrg], { json: true, timeoutSeconds: args.timeout }),
args.targetOrg
);
const matrix = buildProbeMatrix(args.targetOrg, args.describeTable);
const report = {
runtime,
org: orgDisplay,
core: {},
phases: {},
caveats: [...CAVEATS],
guidance: [],
};
if (runtime.state !== 'ok' || orgDisplay.state !== 'ok') {
report.guidance.push(...guidanceFromProbe('runtime', runtime));
if (orgDisplay.state !== 'ok') {
report.guidance.push(`Authenticate the target org first: sf org login web -a ${args.targetOrg}`);
}
if (args.json) {
console.log(JSON.stringify(report, null, 2));
} else {
printTextReport(report);
}
process.exit(runtime.state === 'ok' && orgDisplay.state === 'ok' ? 0 : 1);
}
for (const [name, commandArgs] of Object.entries(matrix.core)) {
report.core[name] = normalizeProbe(name, runCommand('sf', commandArgs, { json: true, timeoutSeconds: args.timeout }));
}
const selectedPhases = args.phase === 'all'
? Object.keys(matrix.phases)
: [args.phase];
for (const phase of selectedPhases) {
const checks = {};
const phaseMatrix = matrix.phases[phase] || {};
for (const [name, commandArgs] of Object.entries(phaseMatrix)) {
if (!commandArgs) {
checks[name] = { name, state: 'skipped', reason: 'No describe table was supplied for the query probe.' };
continue;
}
checks[name] = normalizeProbe(name, runCommand('sf', commandArgs, { json: true, timeoutSeconds: args.timeout }));
}
report.phases[phase] = {
summary: summarizePhase(checks),
checks,
};
}
const uniqueGuidance = new Set();
for (const [name, probe] of Object.entries(report.core)) {
for (const item of guidanceFromProbe(`core.${name}`, probe)) uniqueGuidance.add(item);
}
for (const [phase, entry] of Object.entries(report.phases)) {
for (const [name, probe] of Object.entries(entry.checks)) {
for (const item of guidanceFromProbe(`${phase}.${name}`, probe)) uniqueGuidance.add(item);
}
}
const coreSignals = Object.values(report.core).map((probe) => probe.state);
if (coreSignals.some((state) => ['ok', 'enabled_empty', 'enabled_populated'].includes(state))) {
uniqueGuidance.add('At least one core Data Cloud probe succeeded. Treat individual query or feature-gate failures as scoped issues, not automatic proof that the whole product is disabled.');
}
uniqueGuidance.add('For core provisioning, tenant creation, or license assignment gaps, use Setup → Data Cloud Setup and the current standard Data Cloud permission sets. Feature Manager can expose some org-specific toggles, but it is not the source of truth for every missing capability.');
uniqueGuidance.add('Reference: skills/orchestrating-datacloud/references/feature-readiness.md');
report.guidance = [...uniqueGuidance];
if (args.json) {
console.log(JSON.stringify(report, null, 2));
} else {
printTextReport(report);
}
process.exit(0);
}
main();
#!/usr/bin/env node
/**
* Generate oclif.manifest.json for the sf-cli-plugin-data360 community plugin.
*
* Why this exists:
* `npx oclif manifest` imports every command class, which triggers the
* @oclif/core class hierarchy. When the plugin's pinned @oclif/core is
* older than what the current Node.js version expects, the import fails
* with "Cannot read properties of undefined (reading 'prototype')".
*
* This script avoids importing commands entirely. It walks the compiled
* lib/commands/ directory and extracts static metadata from source text
* via regex, producing a valid manifest that tells oclif to skip
* auto-discovery and auto-transpilation.
*
* Usage:
* node generate-manifest.mjs # uses cwd
* node generate-manifest.mjs /path/to # uses explicit plugin root
*/
import { readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
import { join, relative, sep } from 'node:path';
const pluginRoot = process.argv[2] || process.cwd();
const pkg = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf8'));
const commandsDir = join(pluginRoot, (pkg.oclif?.commands || './lib/commands').replace('./', ''));
function walk(dir) {
const files = [];
for (const entry of readdirSync(dir)) {
const full = join(dir, entry);
if (statSync(full).isDirectory()) files.push(...walk(full));
else if (entry.endsWith('.js') && !entry.endsWith('.test.js')) files.push(full);
}
return files;
}
function parseCommandSource(source, id) {
const cmd = { id, pluginName: pkg.name, pluginType: 'link', aliases: [] };
const summaryMatch = source.match(/static\s+summary\s*=\s*['"`]([^'"`]+)/);
if (summaryMatch) cmd.summary = summaryMatch[1];
const descMatch = source.match(/static\s+description\s*=\s*['"`]([^'"`]+)/);
if (descMatch) cmd.description = descMatch[1];
if (/static\s+hidden\s*=\s*true/.test(source)) cmd.hidden = true;
if (/static\s+strict\s*=\s*false/.test(source)) cmd.strict = false;
if (/static\s+enableJsonFlag\s*=\s*true/.test(source)) cmd.enableJsonFlag = true;
return cmd;
}
const commands = {};
for (const file of walk(commandsDir)) {
const rel = relative(commandsDir, file).replace(/\.js$/, '');
const id = rel.split(sep).join(':');
try {
commands[id] = parseCommandSource(readFileSync(file, 'utf8'), id);
} catch {
commands[id] = { id, pluginName: pkg.name, pluginType: 'link', aliases: [] };
}
}
const manifest = { version: pkg.version, commands };
const outPath = join(pluginRoot, 'oclif.manifest.json');
writeFileSync(outPath, JSON.stringify(manifest, null, 2));
console.log(`Generated oclif.manifest.json: ${Object.keys(commands).length} commands (v${pkg.version})`);
#!/usr/bin/env bash
set -euo pipefail
ORG="${1:-}"
if ! command -v sf >/dev/null 2>&1; then
echo "Salesforce CLI (sf) is not installed or not on PATH." >&2
exit 1
fi
if ! sf data360 man >/dev/null 2>&1; then
echo "The community 'sf data360' runtime is not available." >&2
echo "Run bash ./scripts/bootstrap-plugin.sh first." >&2
exit 1
fi
echo "✓ sf data360 runtime detected"
if [[ -n "${ORG}" ]]; then
if sf org display -o "${ORG}" >/dev/null 2>&1; then
echo "✓ org alias '${ORG}' is authenticated"
else
echo "Org alias '${ORG}' is not authenticated." >&2
exit 1
fi
if sf data360 doctor -o "${ORG}" >/dev/null 2>&1; then
echo "✓ sf data360 doctor completed for '${ORG}'"
else
echo "! sf data360 doctor did not complete cleanly for '${ORG}'. Falling back to read-only smoke checks." >&2
smoke_passed=0
while IFS='|' read -r label command; do
[[ -z "${label}" ]] && continue
if bash -lc "${command}" >/dev/null 2>&1; then
echo "✓ ${label} smoke check passed for '${ORG}'"
smoke_passed=1
fi
done <<EOF
connectors|sf data360 connection connector-list -o "${ORG}"
dmos|sf data360 dmo list --all -o "${ORG}"
segments|sf data360 segment list -o "${ORG}"
data-action-targets|sf data360 data-action-target list -o "${ORG}"
EOF
if [[ "${smoke_passed}" -ne 1 ]]; then
echo "No fallback Data Cloud smoke checks succeeded for '${ORG}'. Check org access and Data Cloud provisioning." >&2
exit 1
fi
echo "! Doctor remains advisory for partially provisioned orgs; at least one read-only Data Cloud command succeeded." >&2
fi
fi
echo "Verification complete."
if [[ -n "${ORG}" ]]; then
echo "Next: node ./scripts/diagnose-org.mjs -o '${ORG}' --json"
fi
Upstream Distillation Map for orchestrating-datacloud
This file exists to make downstream maintenance easy without sacrificing sf-skills consistency.
Maintenance contract
When upstream changes, do not copy blindly.
Instead: 1. review new upstream commits 2. identify changed command behaviors, install patterns, or gotchas 3. update sf-skills prompts and templates in a distilled form 4. keep naming, attribution, and cross-skill boundaries consistent with sf-skills 5. update this file with the new reviewed commit SHAs
High-priority upstream areas to re-check
- installation / linking workflow for the community plugin
- command counts and topic coverage
- API-version guidance
- known issues and bug-fix notes
- live-tested command set
- any new commands affecting Connect / Prepare / Harmonize / Segment / Act / Retrieve boundaries
- connector-specific payload examples worth distilling into generic repo-safe examples
- search-index / hybrid-search guidance and any command-surface changes around hybrid scoring or prefilter behavior
- Ingestion API schema-upload flow, send-data examples, and problem-record guidance
- unstructured-source setup differences between connection-level reruns, stream refreshes, and initial UI seeding
- UI-only gaps where upstream introduces browser automation; validate before importing
Cross-skill boundary reminders
Keep Data Cloud product work in *-datacloud, but do not blur into:
observing-agentforcefor STDM/session tracing/parquet workflowsquerying-soqlfor CRM SOQL-only taskshandling-sf-datafor CRM record seeding/cleanupgenerating-*skills for CRM schema creation (custom objects, fields, validation rules, etc.)
Local helper files in this family
references/plugin-setup.mdscripts/bootstrap-plugin.shscripts/verify-plugin.shassets/definitions/
These are sf-skills-owned conveniences and should evolve independently from upstream when that improves user experience.
Related skills
Forks & variants (1)
Orchestrating Datacloud has 1 known copy in the catalog totaling 519 installs. They canonicalize to this original listing.
- forcedotcom - 519 installs
How it compares
Use orchestrating-datacloud for cross-phase Data Cloud pipeline design; switch to phase-specific sf-skills when work stays within a single Connect, Prepare, or Segment step.
FAQ
What is orchestrating-datacloud?
Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this skill when the user needs a multi-step Data Cloud pipeline, cross-phase tro
When should I use orchestrating-datacloud?
Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this skill when the user needs a multi-step Data Cloud pipeline, cross-phase tro
Is orchestrating-datacloud safe to install?
Review the Security Audits panel on this page before production use.