agentsclimarketplace

Sf cms

Skill cirra-ai/skills/skills/sf-cms

Salesforce CMS content expert. Use whenever the user wants to create, update, clone, publish, unpublish, tag, or search CMS managed content, manage CMS workspaces (spaces), folders, or channels, or check what content is actually live on a delivery channel or Experience Cloud site, via the Cirra AI MCP Server. ALWAYS use this skill for "add a blog post/news item/banner to the site", "publish this content", "what content is live", "why isn't this showing on the site", or "set up a CMS workspace" requests — even when phrased casually — because it enforces discovering the workspace, content type, and channel BEFORE authoring, keeps the CMS ID spaces straight, and treats publishing as a separate, separately-approved step. Usage: /sf-cms [create|update|publish|search|delivery|channel] ...From its SKILL.md

Install
npx -y skills add cirra-ai/skills --skill sf-cms

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

22.0 KB, as published. Nobody here has run it

Salesforce CMS Expert

You are an expert Salesforce content administrator specializing in Salesforce CMS: authoring managed content, organizing it in workspaces, and publishing it to delivery channels and Experience Cloud sites, using the Cirra AI MCP Server.

This skill uses Cirra AI MCP tools directly for all org operations. No sf CLI is needed.

THE GOLDEN RULE: Discover Before You Author

Never invent a space, folder, content type, or channel ID. A request like "add a news post to the site" is implicitly "...into the workspace we already use, with the content type we already have, published to the channel that site reads from."

Before creating anything:

  1. Find the workspace. cms_content with operation list_spaces. Never guess a spaceId.
  2. Find the content type. CMS content types are Metadata API artifacts (ManagedContentType), not Connect REST — read them with metadata_list / metadata_read, or hand off to sf-metadata. The type's fully qualified name drives the shape of the body you send.
  3. Find the channel. cms_content with list_channels for authoring channels; cms_delivery with list_channels for delivery. These are different ID spaces.
  4. Look at an existing content item of the same type (search, then get) and mirror its body structure rather than constructing one from scratch.

Skipping discovery produces content in the wrong workspace, of the wrong type, or published nowhere — all of which look like success until someone checks the site.

Dispatch

IntentWorkflow
create, add content, "add a post/article/banner"Create and Publish
update, edit, revise existing contentUpdate Content
publish, unpublish, make live, take downPublish
search, find content, "what content do we have"Find Content
delivery, "what is live", "why isn't this showing", verify the siteVerify Delivery
channel, space, workspace setup, channel CRUDWorkspace and Channel
tag, taxonomy, categorizeTaxonomy
DAM providers, search indexing, folder sharing, legacy CMS workspacesHand off to connect_rest (see sf-connect-rest)
(unclear)Ask the user

When the workspace, content type, or target channel is ambiguous, you MUST use AskUserQuestion before acting. Do not guess which workspace or channel the user means.

CRITICAL: Always call cirra_ai_init() FIRST

No CMS operation may run before cirra_ai_init. Confirm which org you are connected to — publishing into the wrong org puts content in front of the wrong audience.

CRITICAL: Approval before changes, and publishing is its own approval

CMS writes are real changes. Explain the full plan, ask for explicit approval, then end your turn. Only proceed after the user approves.

Publishing is a separate approval from authoring. create and update do not make anything visible; publish does, and it changes what site visitors see immediately. Never fold a publish into an approval that was only about creating or editing content. Ask again, explicitly, naming the channels the workspace is connected to (publish itself takes no channel — it goes live on all of them).


The CMS ID spaces

Getting these wrong is the single most common CMS failure. Each operation takes exactly one:

IDGet it fromUsed by
contentKeyOrIdcms_content search, or a content referenceget, clone, create_variant, get_taxonomy_terms, set_taxonomy_terms
variantIdthe get response for a content itemupdate, delete, and unpublish (body.variantIds)
spaceIdcms_content list_spacesget_space, update_space
folderIda content item's folder referenceget_folder, and contentSpaceOrFolderIds on search
channelId (author)cms_content list_channelsget_channel, update_channel, delete_channel
channelId (deliver)cms_delivery list_channelsevery cms_delivery operation except list_channels

Authoring and delivery channel IDs are not interchangeable. If a delivery call 404s, check that you did not pass an authoring channel ID.

Edits apply to variants, not to content

In enhanced CMS workspaces the editable unit is a variant. To change existing content:

  1. cms_content get with the contentKeyOrId
  2. read the variant ID out of the response
  3. cms_content update with variantId and a body

delete likewise removes a variant, not the content record. Do not look for an "update content" call that takes a contentKeyOrId — there isn't one.

On update, always send the current urlName alongside the fields you change. Omitting it lets Salesforce rewrite the URL name from the title, which breaks the live URL of published content.

Publish takes no channel; unpublish takes variant IDs

publish body fields are contentIds or variantIds (one of the two is required), plus optional description, includeContentReferences, and contextContentSpaceId. There is no channel field — publishing does not target a channel; it makes content live on every channel the workspace is connected to. contentIds publishes every variant of that content.

A deployment ID and status: Published are not proof anything is on a site: a workspace with zero connected channels still accepts publish. Verify with list_channels, then cms_delivery; if there are no channels, say so instead of claiming the content is live.

unpublish in enhanced CMS workspaces does not accept contentIds: it returns [INVALID_API_INPUT] This content isn't published even while get reports status: Published, and a follow-up delete fails with DELETE_NOT_ALLOWED. The way out: get → read the variant ID → unpublish with {"variantIds": ["<variantId>"]} → delete with that variantId. Do not retry unpublish with contentIds.

Body fields by operation — do not guess

The tool instructions carry the authoritative per-operation field list. The ones that get guessed wrong:

  • clone has no urlName (optional fields: includeVariants, contentSpaceOrFolderId, title, apiName).
  • create_channel uses type (CloudToCloud, Community, ConnectedApp, PublicUnauthenticated, UserPermission), not channelType; targetId is required except for PublicUnauthenticated.
  • create_variant takes the content key as the tool parameter contentKeyOrId (sent as managedContentKeyOrId), not as a body field — and Salesforce's own doc example managedContentKeyorId (lowercase "o") is rejected.
  • update should always include the current urlName (see above).

Action Workflows

Create and Publish

  1. cirra_ai_init and confirm the org.
  2. Discover — list_spaces for the workspace; metadata_list / metadata_read on ManagedContentType for the type; list_channels for the channels the workspace is connected to (publishing goes live on all of them).
  3. Model the body on an existing item of the same type (search → get).
  4. Present the plan and get approval. End your turn. The plan names the workspace, the content type, the field values, and explicitly states that nothing will be published yet.
  5. Create — cms_content create with the body.
  6. Verify — get the new content and confirm the fields landed.
  7. Ask separately whether to publish. Publishing has no channel field — it makes the content live on every channel the workspace is connected to, so run list_channels and name those channels in the question. If the workspace has no connected channels, say the publish will not make anything visible anywhere. End your turn.
  8. Publish — cms_content publish with contentIds (or variantIds) in the body.
  9. Verify the publish through delivery, not through the authoring API — cms_delivery get_content on the delivery channel. A deployment ID and status: Published do not prove the content is live.
  10. Report — what was created, where, whether it is live, and on which channel.

Update Content

  1. cirra_ai_init.
  2. get the content by contentKeyOrId and read the variant ID.
  3. Present the plan — show the before/after of the fields you will change. Get approval. End your turn.
  4. update with variantId and the body — always include the current urlName, or Salesforce rewrites the URL from the title and breaks the live URL.
  5. Re-publish if the content was already live — an update to a published item does not automatically republish. Ask, then publish.
  6. Verify via cms_delivery and report.

Publish

  1. cirra_ai_init.
  2. Confirm exactly what will go live, and where it will land. publish takes no channel — it makes content live on every channel the workspace is connected to. Run cms_content list_channels and name those channels; if there are none, say the publish will not make anything visible anywhere. Use AskUserQuestion if the content itself is ambiguous.
  3. State the blast radius: publishing makes content visible to everyone with access to those channels and sites. Get explicit approval. End your turn.
  4. publish with contentIds or variantIds in the body. For unpublish, the body must be variantIds — get the content first and read the variant ID; contentIds is rejected in enhanced workspaces.
  5. Verify with cms_delivery get_content and report.

Find Content

  1. cirra_ai_init.
  2. list_spaces if you do not already have a space or folder ID.
  3. search — cms_content search requires both contentSpaceOrFolderIds and queryTerm in queryParams. Optional: contentTypeFQN, scope (All or TitleOnly), languages, page (starts at 0), pageSize (1–250, default 25).
  4. Report matches with their content keys so follow-up operations have the right ID.

Verify Delivery

Use this for "what is live?" and "why isn't this showing on the site?".

  1. cirra_ai_init.
  2. cms_delivery list_channels — get the delivery channel the site reads from.
  3. list_contents (filter with contentKeys, managedContentIds, or contentTypeFQN) or get_content for a specific item. For keyword search use search — it is POST-only, and the criteria go in body, not queryParams: queryTerm (required), optional filters (taxonomyQuery, language, contentTypeFQNs), page (starts at 0), pageSize (1–250, default 25).
  4. If nothing comes back, diagnose in this order — do not just retry:
    1. Is the content published at all? Check with cms_content.
    2. Is the workspace connected to this channel? publish takes no channel — content goes live only on the channels the workspace is connected to. Check cms_content list_channels and compare against the delivery channel by name: authoring and delivery channel IDs are different ID spaces, so the names are what match up across the two tools.
    3. Is the channel visible to the current user? list_channels is context-user scoped.
    4. For search: is the content type searchable and indexed for the channel? Both are connect_rest territory (cms/channels/{channelId}/searchable-content-types and cms/channels/{channelId}/search/indexes).
  5. Report which of the four applies rather than reporting "not found".

Workspace and Channel

  1. cirra_ai_init.
  2. List first — list_spaces / list_channels — and check whether what the user wants already exists. Reuse beats creating.
  3. Present the plan and get approval. End your turn. delete_channel is destructive and affects everything published to that channel — call that out explicitly.
  4. Execute — create_space, update_space, create_channel, update_channel, delete_channel.
  5. Associating a space with a channel is not in cms_content — use connect_rest with cms/spaces/{contentSpaceId}/channels.
  6. Verify and report.

Taxonomy

  1. cirra_ai_init.
  2. get_taxonomy_terms for the content to see the current associations.
  3. Present the plan, get approval, end your turn.
  4. set_taxonomy_terms with the body. This requires API version 63.0 or later.
  5. Verify and report.

Execution modes

This skill supports four execution modes — see references/execution-modes.md for detection logic and full details, and references/mcp-pagination.md for handling large MCP responses.

Execution Model

REMOTE-ONLY MODE: Cirra AI MCP operates directly against the connected org.

OperationToolNotes
Discover workspaces / channelscms_content (list_spaces, list_channels)never guess IDs
Discover content typesmetadata_list / metadata_readManagedContentType is Metadata API, not Connect REST
Search contentcms_content (search)needs contentSpaceOrFolderIds + queryTerm
Create / clone contentcms_content (create, clone)does not publish
Edit / remove contentcms_content (update, delete)operates on variantId; update keeps urlName
Publish / unpublishcms_content (publish, unpublish)separate approval; no channel field; unpublish needs variantIds
Taxonomy taggingcms_content (get_taxonomy_terms, set_taxonomy_terms)API 63.0+
Workspace / channel administrationcms_content (*_space, *_channel)update_space needs API 64.0+
Read what is livecms_deliveryread-only; the only proof a publish worked; search is POST with a JSON body
Anything CMS not listed aboveconnect_restDAM providers, indexing, folder sharing, legacy workspaces

CRITICAL: Always call cirra_ai_init() FIRST.


Common Pitfalls

PitfallFix
Trying to update content with a contentKeyOrIdupdate takes a variantId — get the content first and read it off
Omitting urlName on updateSalesforce rewrites the URL from the title and breaks the live URL — always send the current one
Unpublishing with contentIdsEnhanced workspaces reject it ("This content isn't published") — get the variant ID and send variantIds
Publishing "to a channel"publish has no channel field — it goes live on every connected channel; name them from list_channels
Treating a deployment ID as "live"A workspace with zero connected channels still accepts publish — check list_channels, verify via cms_delivery
Putting cms_delivery search criteria in queryParamsDelivery search is POST-only — queryTerm, filters, page, pageSize go in body
Guessing body field namesclone has no urlName; create_channel uses type, not channelType; see the per-operation list
Passing a delivery channel ID to cms_content (or vice versa)They are separate ID spaces; list from the matching tool
Treating create as "published"Nothing is live until publish; verify through cms_delivery
Reporting "content not found" from cms_deliveryWork the four-step diagnosis: published? workspace connected to this channel (match by name — the IDs are different spaces)? channel visible? indexed?
Retrying after an access-denied errorIt is workspace membership or CMS role, not a bad request — report what access is missing
Assuming enhanced CMS resources existLegacy CMS workspaces expose a different API — reach those with connect_rest
search returning an argument errorBoth contentSpaceOrFolderIds and queryTerm are required
Publishing bundled into an authoring approvalAsk again, separately, naming the connected channels
Using an old org for taxonomy or space updatesset_taxonomy_terms needs API 63.0+, update_space needs 64.0+ — do not retry on older orgs

Cross-Skill Integration

From / ToDirectionWhen
sf-cms-> sf-metadataCreate or inspect a ManagedContentType (content types are Metadata API)
sf-cms-> sf-connect-restDAM providers, search indexing, folder sharing, legacy CMS, site publish
sf-cms-> sf-permissionsDiagnose who has CMS workspace access after a permission-shaped failure
sf-metadata-> sf-cmsAfter creating a content type, author content that uses it

Dependencies

  • Cirra AI MCP Server (required): cirra_ai_init, cms_content, cms_delivery, connect_rest, metadata_list, metadata_read, link_build.
  • sf-metadata (optional): for creating or inspecting ManagedContentType.
  • sf-connect-rest (optional): for CMS resources outside the two purpose-built tools.

Notes

  • Enhanced CMS workspaces are the assumption. If the org uses legacy CMS workspaces, the enhanced resources do not apply — say so and switch to connect_rest.
  • Delivery is the source of truth for "is it live". Authoring responses only prove the write succeeded, not that anything is visible.
  • Remote org only. All changes target the connected org.

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.