diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4dc816b..a86b657 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -8,7 +8,7 @@ "name": "contentstack-skills", "source": "./", "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Studio, Brand Kit, Developer Hub apps, Launch, and migrations.", - "version": "0.2.0", + "version": "0.3.0", "category": "development", "tags": ["contentstack", "cms", "headless-cms", "studio"] } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 7c519d1..24779cd 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "contentstack-skills", - "version": "0.2.0", + "version": "0.3.0", "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Studio, Brand Kit, Developer Hub apps, Launch, and migrations.", "author": { "name": "Contentstack", "url": "https://www.contentstack.com" }, "homepage": "https://developers.contentstack.com", diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index f80d783..e51e220 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "contentstack-skills", - "version": "0.2.0", + "version": "0.3.0", "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Studio, Brand Kit, Developer Hub apps, Launch, and migrations.", "author": { "name": "Contentstack", "url": "https://www.contentstack.com" }, "skills": "./skills/" diff --git a/CHANGELOG.md b/CHANGELOG.md index e6ce1a5..79dee73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to the Contentstack agent skills bundle. Versions match the `version` field in every plugin manifest that declares one. +## 0.3.0 + +### New skills + +- `asset-management`: advisory guidance for the standalone Assets (DAM) product: spaces and workspaces, folders, asset types and user-defined fields, localization, saved views, searching the Assets API, AI tags and alt text, duplicate management, versions, trash and restore, visual markups and CMS integration. + +### Changed skills + +- **`cms-assets` routing:** scoped to the stack asset library. Assets DAM questions, and any request to read or update user-defined fields, now route to `asset-management`, since the stack asset library doesn't support user-defined fields. +- **`cms-live-preview-visual-editor-support-assistant`:** ports the fixes that missed 0.2.0. Open in New Tab is scoped to Live Preview, since Visual Editor always renders in its iframe. Also: the missing navigation entry checks the stack's Live Preview setting first, the CORS entry drops an unverified allowlist claim, GraphQL preview keeps the delivery headers, `livePreviewQuery` key rules, the edit button `exclude` config needing `init()`, SDK caching separated from app and CDN caching, and `stackSdk` notes for the legacy SDK. + ## 0.2.0 ### Install anywhere, from one source diff --git a/README.md b/README.md index f36d9af..67b282b 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Use `--list` to see every skill, or leave out `--skill` to install them all. The | Slug | Title | Product | What it helps with | | --- | --- | --- | --- | +| `asset-management` | Asset Management | Assets | Assets DAM spaces and workspaces, folders, asset types and metadata, localization, saved views, AI tagging and alt text, duplicate management, versions, trash and restore, visual markups, and CMS integration. | | `brand-kit-assistant` | Brand Kit Assistant | Brand Kit | Brand Kit concepts, setup, governance, Voice Profiles, Knowledge Vault, on-brand AI generation, and API-task routing. | | `cms-assets` | Contentstack Assets | CMS | Asset organization, image transformations, publishing lifecycle, CDN behavior, and asset limits. | | `cms-branches-aliases` | Branches & Aliases | CMS | Isolated content development, alias-based deployments, CI/CD integration, merge behavior, and rollback patterns. | diff --git a/docs/README.md b/docs/README.md index 4962b77..3a85c43 100644 --- a/docs/README.md +++ b/docs/README.md @@ -50,8 +50,8 @@ Every skill is written once in the open [Agent Skills](https://agentskills.io) f | | | | ------------------------ | -------------------------------------------------------------------------------------------------------------- | -| **Skills included** | 23 (see the [skill reference](skills/index.md)) | -| **Products covered** | CMS, Developer Experience, Studio, Launch, Brand Kit, Developer Hub | +| **Skills included** | 24 (see the [skill reference](skills/index.md)) | +| **Products covered** | CMS, Assets, Developer Experience, Studio, Launch, Brand Kit, Developer Hub | | **Supported tools** | Claude Code, claude.ai / Cowork, Cursor, Codex, GitHub Copilot, Gemini CLI, `skills` CLI | | **Source of truth** | `skills//SKILL.md` | | **Repository** | [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills) | diff --git a/docs/how-it-works/router.md b/docs/how-it-works/router.md index a30e566..04ea0b0 100644 --- a/docs/how-it-works/router.md +++ b/docs/how-it-works/router.md @@ -41,7 +41,8 @@ Each description's "Use when…" clause lists the requests that should load it. | Designing or refactoring content models | [Data Modeling Best Practices](../skills/cms-data-modeling-best-practices.md) | | Setting up or debugging Live Preview, Visual Editor (Visual Builder) or Timeline | [Live Preview & Visual Editor Support](../skills/cms-live-preview-visual-editor-support-assistant.md) | | Fetching entries, CDA queries, pagination, bulk ops | [Entries](../skills/cms-entries.md) | -| Uploading, transforming, delivering assets | [Assets](../skills/cms-assets.md) | +| Uploading, transforming, delivering assets in a stack | [Assets](../skills/cms-assets.md) | +| Assets DAM: spaces, workspaces, duplicate sets, saved views, visual markups | [Asset Management](../skills/asset-management.md) | | Classifying content, category hierarchies | [Taxonomy](../skills/cms-taxonomy.md) | | Workflow stages, approvals, publish rules | [Workflows & Publish Rules](../skills/cms-workflows.md) | | Environments, publishing, delivery/preview tokens, Sync API | [Environments & Publishing](../skills/cms-environments-publishing.md) | diff --git a/docs/overview/introduction.md b/docs/overview/introduction.md index 8656258..ac35d85 100644 --- a/docs/overview/introduction.md +++ b/docs/overview/introduction.md @@ -24,11 +24,12 @@ Agent skills close that gap. They give the assistant Contentstack-specific knowl ## What's in the bundle -The skills span six Contentstack product areas: +The skills span seven Contentstack product areas: | Product | Skills | | --- | --- | | **CMS** | Assets · Branches & Aliases · Data Modeling · Entries · Environments & Publishing · Localization · Releases · Roles & Permissions · Taxonomy · Tokens & Authentication · Variants & Personalization · Webhooks · Workflows | +| **Assets** | Asset Management | | **Developer Experience** | Delivery SDK · Contentstack Kickstart Next · Migrate JS→TS SDK · Live Preview & Visual Editor Support · Migration Companion | | **Studio** | Contentstack Studio | | **Launch** | Sync env vars from `.env.example` · Trigger & Monitor Deployments | diff --git a/docs/skills/asset-management.md b/docs/skills/asset-management.md new file mode 100644 index 0000000..c5b91f1 --- /dev/null +++ b/docs/skills/asset-management.md @@ -0,0 +1,43 @@ +--- +title: Asset Management +description: "Advise on the Contentstack Assets DAM: spaces and workspaces, metadata, localization, saved views, search, AI tags, duplicates, versions, trash and restore, and visual markups." +--- + +# Asset Management + +**Slug:** `asset-management` · **Product:** Assets (DAM) · **Type:** Advisory (read-only) + +Advises on Contentstack Assets, the standalone digital asset management product. It is separate from the CMS stack asset library covered by [Assets](cms-assets.md). + +## When it triggers + +When you ask about the Assets DAM: spaces and workspaces, folders, asset types and metadata, localization, saved views, AI tags and alt text, duplicate management, versions, trash and restore, visual markups, or linking Assets to CMS stacks. + +## What it covers + +- **Spaces and workspaces**: a space is the top-level container, and workspaces are isolated environments inside it, created from the main workspace or a parent workspace. +- **Folders and roles**: folder creation and least-privilege guidance. +- **Asset types and metadata**: system, general and user-defined metadata. The currently supported user-defined field types are single line text, number, select and group. Filters on user-defined fields can be saved as saved views. +- **Localization**: add a language in product settings, then add it per workspace under Space Settings > Workspaces > Manage Locales. +- **Search**: the public Assets API search endpoint, required headers, and filtering by user-defined field. +- **AI tags and alt text**: manual suggestions and auto-populate at upload, with their limits. +- **Duplicate management**: exact-duplicate sets for images, how to resolve them, and what is not detected. +- **Versions, trash and restore**: renaming and restoring versions, the 14-day trash window, and folder restore options. +- **Visual markups**: hotspots and bounding boxes, including AI-suggested markups. +- **CMS integration**: linking spaces to stacks and the `asset_fields[]` Content Delivery API parameter. + +## Example prompts + +- "How should I split my brands and regions across spaces and workspaces?" +- "How do I add a language to a workspace?" +- "How do I find and remove duplicate images?" +- "I deleted a folder by mistake. Can I get it back?" +- "How do I search assets by a custom field value?" + +## Safety notes + +Read-only advisory. Never uploads, moves, deletes, restores or modifies assets, spaces or settings. Warns before irreversible actions such as deleting a space or all markups. Never exposes tokens or API keys; examples use environment variables. + +## Related + +- [Assets](cms-assets.md) · [Localization](cms-localization.md) · [Roles & Permissions](cms-roles-permissions.md) diff --git a/docs/skills/cms-assets.md b/docs/skills/cms-assets.md index 990099b..5829875 100644 --- a/docs/skills/cms-assets.md +++ b/docs/skills/cms-assets.md @@ -35,4 +35,5 @@ Read-only advisory. Never uploads, deletes, publishes, or modifies assets. Deliv ## Related +- For the standalone Assets DAM (spaces, workspaces, duplicate sets), see [Asset Management](asset-management.md). Reading or updating user-defined fields isn't supported by the stack asset library; use the Assets (DAM) API described there. - [Environments & Publishing](cms-environments-publishing.md) · [Entries](cms-entries.md) · [Data Modeling Best Practices](cms-data-modeling-best-practices.md) diff --git a/docs/skills/index.md b/docs/skills/index.md index 144e1d3..67d52b5 100644 --- a/docs/skills/index.md +++ b/docs/skills/index.md @@ -5,7 +5,7 @@ description: The full catalog of Contentstack Agent Skills, grouped by product. # Skills reference -The bundle includes 23 skills across six Contentstack products. Each links to a dedicated page with what it does, when it triggers, example prompts, and its safety notes. +The bundle includes 24 skills across seven Contentstack products. Each links to a dedicated page with what it does, when it triggers, example prompts, and its safety notes. > Each skill page mirrors its canonical `skills//SKILL.md`. The slug is the skill's identifier: use it with the [`skills` CLI](../get-started/skills-cli.md). @@ -37,6 +37,12 @@ The bundle includes 23 skills across six Contentstack products. Each links to a | [Live Preview & Visual Editor Support](cms-live-preview-visual-editor-support-assistant.md) | `cms-live-preview-visual-editor-support-assistant` | Setting up or debugging Live Preview, Visual Editor (Visual Builder) or Timeline across CSR, SSR, SSG, BFF. | | [Migration Companion](migration-companion.md) | `migration-companion` | Guided Contentful → Contentstack migration: content and application code. | +## Assets + +| Skill | Slug | What it helps with | +| --- | --- | --- | +| [Asset Management](asset-management.md) | `asset-management` | Assets DAM spaces and workspaces, metadata, localization, saved views, AI tags, duplicates, versions, trash and restore, visual markups. | + ## Studio | Skill | Slug | What it helps with | diff --git a/gemini-extension.json b/gemini-extension.json index 9538e1b..57ac9e7 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,5 +1,5 @@ { "name": "contentstack-skills", - "version": "0.2.0", + "version": "0.3.0", "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Studio, Brand Kit, Developer Hub apps, Launch, and migrations." } diff --git a/plugin.json b/plugin.json index 0c8c924..03de702 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "contentstack-skills", - "version": "0.2.0", + "version": "0.3.0", "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Studio, Brand Kit, Developer Hub apps, Launch, and migrations.", "author": { "name": "Contentstack", "url": "https://www.contentstack.com" }, "homepage": "https://developers.contentstack.com", diff --git a/skills/asset-management/SKILL.md b/skills/asset-management/SKILL.md new file mode 100644 index 0000000..4ce64da --- /dev/null +++ b/skills/asset-management/SKILL.md @@ -0,0 +1,236 @@ +--- +name: asset-management +description: "Advise on Contentstack Assets, the standalone digital asset management (DAM) product: spaces and workspaces, folders, asset types and metadata, localization, saved views, filtering by user-defined fields, AI tags and alt text, duplicate management, versions, trash and restore, visual markups, and linking to CMS stacks. Use when a user asks about the Assets DAM, spaces, workspaces, duplicate sets, saved views or visual markups. Not for the CMS stack asset library; use cms-assets for that." +allowed-tools: Read Grep Glob +--- + +# Asset Management (Contentstack Assets DAM) + +## Description + +Advise on Contentstack Assets, the standalone DAM product (also called "Asset Management" in some docs). Cover spaces and workspaces, folders, roles, asset types and metadata, localization, filters and saved views, AI-assisted metadata, duplicate management, versions, trash and restore, visual markups, and CMS integration. + +## When to Use + +Use when a user asks about the Contentstack Assets DAM: organizing assets in spaces, workspaces and folders, modeling asset metadata, AI tags and alt text, finding and removing duplicates, versioning, restoring deleted assets, visual markups, or using Assets with a CMS stack. + +Do not use for the CMS stack asset library (stack-level uploads, folders, Image Delivery API, publishing to environments). Route those questions to `cms-assets`. If it is unclear which one the user means, ask whether they work in an Assets space or in the asset library inside a stack. + +## User Problem + +Teams adopting Contentstack Assets need to structure spaces and workspaces sensibly, model metadata so assets are findable, use AI features safely, keep the library free of duplicates, and understand what is and is not recoverable when assets are deleted or replaced. + +## Success Criteria + +- Distinguish the Assets DAM from the CMS asset library. +- Use the product's own terminology: space, workspace, main workspace, asset type, system metadata, user-defined metadata, duplicate set, visual markup. +- State documented behavior and limits accurately, and say plainly when something is not documented. +- Warn about irreversible or hard-to-reverse actions before the user takes them. + +## Expected Inputs + +- Which product the user means (Assets space or CMS stack library) +- Organization shape (brands, regions, teams) and number of spaces +- Asset types and metadata the team needs +- The specific task or problem (duplicates, restore, versions, AI settings, markups) + +## Expected Outputs + +- Space, workspace and folder structure recommendations +- Asset type and metadata modeling guidance +- Step-by-step UI paths for the task +- Gotchas and irreversible-action warnings +- Pointers to the official docs for anything not covered here + +## Example User Requests + +- How should I split my brands and regions across spaces and workspaces? +- How do I add custom fields to my images? +- How do I add a language to a workspace? +- Can I save a set of filters and reuse it? +- How do I search assets by a custom field value? +- Can Assets tag my images and write alt text automatically? +- How do I find and remove duplicate images? +- I deleted a folder by mistake. Can I get it back? +- How do I roll back to an earlier version of an asset? +- How do I add hotspots to a product image? +- How do I use assets from a space in my CMS entries? + +## Workflow Summary + +1. Confirm the user means the Assets DAM, not the CMS asset library. +2. Identify the topic: structure, metadata, AI, duplicates, versions, trash, markups, or CMS integration. +3. Answer with documented behavior using the product's terminology. +4. Flag limits and irreversible actions. +5. Link to the relevant docs page for anything undocumented or likely to change. + +## Instructions + +### Spaces and workspaces + +- A **space** is the top-level container, often one per brand, business unit or region. Roles, permissions and settings are governed at the space level, so each space is managed independently. +- A **workspace** is an isolated environment inside a space. Every space has a **main workspace**. New workspaces are created from the main workspace or from another parent workspace, inherit its assets, metadata and configuration, and keep their own changes isolated from the parent. +- A space can be linked to one or more CMS stacks, and assets can be reused across stacks. +- Recommend a small number of spaces and workspaces. Over-fragmenting adds management overhead. +- Space Settings > General holds the title (required) and description. The Space UID is generated by the system and cannot be changed. +- Deleting a space is irreversible. It removes the space's assets, users and collaborators. Always warn before recommending it. +- Duplicate Management is configured per workspace. AI Settings live under Space Settings. + +### Folders + +- Create a folder with **+ New > New Folder**. Name is required and description is optional. Folders appear in the listing and in the Folders section of the Filters panel. +- Recommend a folder structure that matches how teams search, such as by campaign, asset category or brand, and keep it consistent across workspaces. + +### Roles and permissions + +- Access is governed per space through roles, teams and associations. Where the user needs the exact predefined roles or asset-level sharing options, direct them to the current Assets documentation rather than guessing. +- For least privilege, give contributors only the access they need and restrict delete and settings permissions to a few administrators. + +### Asset types and metadata + +- Metadata comes in layers: **system metadata** (read-only: file name, UID, URLs, MIME type, size, created and modified details), **general metadata**, and **user-defined metadata** from custom fields. +- Each **asset type** maps to one MIME type and one file extension. On upload, a matching type applies automatically and its fields appear. System types cover images, audio, video, documents and archives, and you can add custom types. +- User-defined fields are reusable across asset types. The currently supported field types are single line text, number, select and group. The product docs have listed this set differently over time, so point the user to the Asset Modeling docs if they need a type that isn't on this list. +- Mandatory fields must be filled before an upload or save can finish. Use them sparingly so uploads are not blocked on optional information. +- Edit metadata for an individual asset in the configurable metadata panel. +- User-defined fields exist only in the Assets (DAM) product. The CMS stack asset library and its Management API don't read or update them, so direct any request to read or write custom metadata from code to the Assets (DAM) API. See the Assets API reference at https://www.contentstack.com/docs/developers/apis/assets-api for the current endpoints. +- **Filters and saved views:** User-defined fields can be used as filters when browsing assets, so well-modeled fields make the library searchable. A filter combination can be saved as a **saved view** and reused later instead of rebuilding the filters each time. Advise modeling fields with filtering in mind, for example a select field for campaign or usage rights. + +### Localization + +- Assets supports localized asset versions within a space. +- Adding a language is a two-step process: + 1. Add the language in product settings. + 2. Add it to each workspace that needs it: **Space Settings > Workspaces >** pick the workspace **> Manage Locales**. +- Locales are enabled per workspace, so a language added in product settings does not appear in a workspace until it is added there. + +### Searching assets and filtering by user-defined fields + +Use the Assets API search endpoint. Full reference: https://www.contentstack.com/docs/developers/apis/assets-api/search + +- **Endpoint:** `POST /api/{object_type}/search`. `object_type` is required. Folders are not searchable here. +- **Host by region:** use the base URL for your region from the [Assets API overview](https://www.contentstack.com/docs/developers/apis/assets-api): AWS NA (`am-api.contentstack.com`), AWS EU (`eu-am-api.contentstack.com`), Azure NA (`azure-na-am-api.contentstack.com`) or GCP NA (`gcp-na-am-api.contentstack.com`). +- **Headers:** send either `authorization: Bearer ` or `authtoken` (your Contentstack authtoken). A management token is not accepted. `x-cs-api-version` is required (default `4`). With `authtoken`, `organization_uid` is also required. Read tokens from environment variables. +- **Text search:** `search_text`, `search_field` and `search_terms_operator` (`and` or `or`). `search_field` accepts only `all`, `title`, `name`, `url` or `category`, so it cannot target user-defined fields. +- **Structured filters:** put conditions in `query`, combined with nested `$and` and `$or` clauses. The docs match a field to a value, for example `{ "category": "image" }`, and don't document other operators. To filter a user-defined field, reference it by its full path, `user_defined_fields..`, and test the filter against your space, since the public page doesn't cover user-defined fields. +- **Scope and paging:** `spaces` limits the search and is a plain array of space UIDs, as in the docs example. Use `limit` and `skip` for paging, and `fields` to trim the response. +- Deleted items are excluded unless `include_deleted_items` or `filter_only_deleted_items` is set. + +Example request body: + +```json +{ + "query": { + "$and": [ + { "user_defined_fields.asset_rights.license_type": "Creative Commons" } + ] + }, + "limit": 50, + "spaces": [""] +} +``` + +- Check the response body for errors after every search. Don't rely on the HTTP status alone to tell whether a request was valid. + +### AI tags, alt text and colors + +- In the metadata panel, **Suggest Tags with AI** and **Suggest Description with AI** generate suggestions. AI can also extract dominant colors, which powers color-based filtering. Suggestions can be wrong, so review them before saving. +- **Auto-populate at upload** is configured in Space Settings > AI Settings. Enable the AI Tags and Alt Text toggles, set Advanced Properties, and click Save Properties. + - Applies to images and to new uploads only. Existing assets are not enriched, and replacing a file does not trigger it. + - Values are written into version 1. No extra version is created, nothing waits for review, and uploads are not slowed down. + - It never overwrites a value the uploader entered. It only fills empty destinations. + - Tags: up to 10 per asset. Confidence ranges from 10% to 100%, and the default is 10 tags at 80%. Tagging adds tags and never removes existing ones. + - Alt text is English only. It goes to the system Description field or to one single-line textbox field you choose. It is skipped if the destination already has a value, or if the chosen field is missing from the asset's type or was deleted or changed type. Tags are still written in those cases. + +### Duplicate management + +- Detects **exact duplicates** (byte-identical images). Two or more form a **duplicate set**, and no copy is treated as the original. +- Images only, and a set cannot span workspaces. Detection is on by default in every workspace and runs in the background after upload, replace, delete and restore. It does not block or flag uploads. +- An admin with permission to edit space settings can turn it off per workspace. +- Open it from the asset listing: More Actions > Duplicate Management. Resolve a set by **Keep This, Delete the Rest**, by deleting a single copy, or by bulk-deleting the duplicates. +- Gotchas to state up front: + - Resized, cropped, re-exported or recompressed copies are not detected. + - Duplicate sets cannot be searched, filtered or sorted. + - Users with partial view permission see a partial count. + - Selecting every copy deletes the image, with no warning. + - Deleting a copy removes it everywhere it is used or linked, so check references first. + - A set disappears once fewer than two images remain, and new duplicates can take a moment to appear. + +### Versions + +- Any change to the file or to metadata creates a new version, and so does a Save Assets action. Default names are Version 1, Version 2 and so on. +- Rename a version from the version selector at the top right. The name can be up to 32 characters using letters, numbers, spaces, hyphens and underscores. Renaming does not create a version. +- To restore an earlier version, select it in the version selector and click **Save Asset**. It becomes the latest version, and the older versions stay in history. +- Only users with edit permission can rename or restore. Others can view history. +- Do not mix this with the CMS asset library's History > View flow. They are different products. + +### Trash and restore + +- Deleted assets and folders go to **Trash** (Space Settings > Trash) and can be restored within **14 days** of deletion. After that they are permanently removed. +- Restore with the ⋮ menu > Restore. Managing assets in the workspace is required. Trash can be filtered by who deleted, type and date range. +- For folders, choose **Restore With Assets** or **Restore without Assets**. With Assets restores only the assets that were in the folder when it was deleted. Assets deleted earlier stay in trash. +- If Restore is greyed out, the parent folder is still in trash. Restore the folder first. +- Deleting an asset removes it from entries that use it. Advise checking references before deleting. + +### Visual markups + +- A **visual markup** annotates a region of an image. A **hotspot** is a single point (x and y). A **bounding box** is a rectangle (x, y, width, height). +- Each markup needs a title. Description, URL and position are optional. Typical uses are shoppable images, annotated diagrams and linking related content. +- **Suggest Markup with AI** proposes bounding boxes with confidence scores. Review them before saving. +- Per markup you can edit, duplicate, hide or delete. Bulk actions can hide all markups or **delete all markups, which is permanent**. +- Markups are for interactive and shoppable content. Do not describe them as review comments or annotation threads. + +### CMS integration and delivery + +- Link a space to one or more stacks so its assets can be used in entries. For setup steps, direct the user to the current Assets documentation. +- In the Content Delivery API, the `asset_fields[]` query parameter applies to assets from the new Assets product. Documented values are `visual_markups` and `user_defined_fields`, and the parameter can be repeated. Stack-library assets do not return those keys. +- `visual_markups` is an empty array when an asset has none. A hotspot returns x and y, and a bounding box also returns width and height. +- Do not state CDN host names, URL formats or branch behavior for Assets as fact unless the user's docs confirm them. + +## Output Format + +Be concise and practical. Use the product's terms. Give UI paths as `Menu > Item`. Use short bullets for steps, limits and gotchas. When something is undocumented or uncertain, say so and link to the docs instead of guessing. + +## Tooling Notes + +Read-only advisory skill. Do not upload, move, delete, restore or modify assets, spaces or settings. Explain the steps and let the user perform them. + +References: + +- https://www.contentstack.com/docs/assets/about-assets +- https://www.contentstack.com/docs/assets/about-spaces-and-workspaces +- https://www.contentstack.com/docs/assets/about-asset-modeling +- https://www.contentstack.com/docs/assets/enhance-asset-management-with-ai +- https://www.contentstack.com/docs/assets/manage-duplicate-images +- https://www.contentstack.com/docs/assets/asset-versioning +- https://www.contentstack.com/docs/assets/restore-an-asset-or-folder +- https://www.contentstack.com/docs/assets/add-visual-markups +- https://www.contentstack.com/docs/developers/apis/content-delivery-api/assets + +## Security + +### Defaults + +- Never expose tokens or API keys. +- Use environment variables for credentials in any example code. + +### Destructive Actions + +Do not perform destructive actions. For deleting a space, deleting duplicates, emptying or letting trash expire, or deleting all markups, explain the consequences and the safe checks (references, restore window, selection), then leave execution to the user. + +### Secrets + +Never reveal management tokens, API keys or other secrets. Reference environment variables only. + +### Environment Variables + +Use environment variables for any credentialed example, such as `CONTENTSTACK_OAUTH_ACCESS_TOKEN`, or `CONTENTSTACK_AUTHTOKEN` together with `CONTENTSTACK_ORGANIZATION_UID`. The Assets API does not accept management tokens. Never hardcode credentials in client-side code. + +## Product Context + +- Product: Assets (DAM) +- Description: Contentstack Assets is the digital asset management layer: spaces, workspaces, folders, asset types and metadata, AI enrichment, duplicate management, versioning, visual markups and CMS integration. +- Product safety rules: + - Never expose management tokens or API keys. + - Always use environment variables for credentials. + - Treat deletion of spaces, assets and markups as irreversible unless the docs state a restore window. diff --git a/skills/cms-assets/SKILL.md b/skills/cms-assets/SKILL.md index 8a9da34..37b1985 100644 --- a/skills/cms-assets/SKILL.md +++ b/skills/cms-assets/SKILL.md @@ -1,6 +1,6 @@ --- name: cms-assets -description: "Advise developers on organizing, delivering, and transforming assets in Contentstack. Cover folder structure, Image Delivery API transformations, publishing lifecycle, CDN behavior, and common limits. Use when developers ask about uploading, organizing, delivering, transforming, publishing, or troubleshooting images and other media files in Contentstack." +description: "Advise developers on organizing, delivering, and transforming assets in Contentstack. Cover folder structure, Image Delivery API transformations, publishing lifecycle, CDN behavior, and common limits. Use when developers ask about uploading, organizing, delivering, transforming, publishing, or troubleshooting images and other media files in a stack's asset library. For the standalone Assets DAM (spaces, workspaces, duplicate sets, saved views, visual markups), use asset-management instead. Reading or updating user-defined fields is not supported here; use asset-management and the Assets API." allowed-tools: Read Grep Glob --- @@ -12,7 +12,11 @@ Advise developers on organizing, delivering, and transforming assets in Contents ## When to Use -Use when developers ask about uploading, organizing, delivering, transforming, publishing, or troubleshooting images and other media files in Contentstack. +Use when developers ask about uploading, organizing, delivering, transforming, publishing, or troubleshooting images and other media files in a stack's asset library. + +For the standalone Assets DAM product (spaces, workspaces, duplicate sets, saved views, visual markups), use the `asset-management` skill instead. + +This skill does not cover reading or updating user-defined fields (custom metadata). The stack asset library doesn't support them. Route those requests to the `asset-management` skill, which points to the Assets (DAM) API. ## User Problem diff --git a/skills/cms-live-preview-visual-editor-support-assistant/references/contact-support.md b/skills/cms-live-preview-visual-editor-support-assistant/references/contact-support.md index b3a8e56..324fb0f 100644 --- a/skills/cms-live-preview-visual-editor-support-assistant/references/contact-support.md +++ b/skills/cms-live-preview-visual-editor-support-assistant/references/contact-support.md @@ -12,7 +12,7 @@ with Contentstack Support. | Symptom | What it actually is | |---|---| -| The Visual Experience or builder-mode option is absent from navigation | The plan or org flag was never enabled for that stack. | +| The Visual Experience or builder-mode option is absent from navigation | First check the one gate the user can see: Live Preview enabled on the stack under Settings → Visual Experience. If it is on, the plan or org flag was never enabled for that stack. See `visual-experience-navigation-missing-for-the-stack` in faq-integration.md. | | Custom Preview URLs or Open in New Tab are unavailable | Both are plan-gated. | ## Not Contentstack at all @@ -20,7 +20,7 @@ with Contentstack Support. | Symptom | What it actually is | |---|---| | A previously working `localhost` preview stops working, console shows a local network access error | Chrome's Local Network Access policy now blocks the app origin from framing localhost. Only the user can grant the permission, in the browser. | -| Preview pane blank, and the site sits behind platform password protection or third-party SSO | Those screens set `X-Frame-Options: DENY` on themselves. Contentstack cannot inject headers into a browser-originated iframe request. Workarounds, cheapest first: enable **Open in New Tab**, which renders the site outside the iframe so frame headers stop applying; otherwise disable protection on the preview deployment, or front the **preview deployment only** with a server-side proxy that replaces the header with `Content-Security-Policy: frame-ancestors 'self' https://app.contentstack.com` using the exact app host for the stack's region (for example `https://eu-app.contentstack.com`), not a `https://*.contentstack.com` wildcard (never just strip it: that makes the protected site frameable by any origin). A bypass token in the Base URL does not work: see `base-url-query-string-corrupts-preview-url` in faq-integration.md. | +| Preview pane blank, and the site sits behind platform password protection or third-party SSO | Those screens set `X-Frame-Options: DENY` on themselves. Contentstack cannot inject headers into a browser-originated iframe request. Workarounds, cheapest first: for Live Preview, enable **Open in New Tab**, which renders the site outside the iframe so frame headers stop applying (Visual Editor does not support it, so this does not help there); otherwise disable protection on the preview deployment, or front the **preview deployment only** with a server-side proxy that replaces the header with `Content-Security-Policy: frame-ancestors 'self' https://app.contentstack.com` using the exact app host for the stack's region (for example `https://eu-app.contentstack.com`), not a `https://*.contentstack.com` wildcard (never just strip it: that makes the protected site frameable by any origin). A bypass token in the Base URL does not work: see `base-url-query-string-corrupts-preview-url` in faq-integration.md. | | Ad slots, consent widgets, or other host-dependent third-party scripts misbehave in the pane | Those scripts key off the top-level origin, which is the Contentstack app inside an iframe. Expected, not a preview defect. | ## How to hand it over diff --git a/skills/cms-live-preview-visual-editor-support-assistant/references/faq-integration.md b/skills/cms-live-preview-visual-editor-support-assistant/references/faq-integration.md index 5612a9e..a131ceb 100644 --- a/skills/cms-live-preview-visual-editor-support-assistant/references/faq-integration.md +++ b/skills/cms-live-preview-visual-editor-support-assistant/references/faq-integration.md @@ -28,7 +28,7 @@ setup, use `setup-docs.md` instead. url.hostname = CONTENTSTACK_CDN_HOST; // e.g. cdn.contentstack.io } ``` - For GraphQL the equivalent is swapping `graphql.contentstack.com` → `graphql-preview.contentstack.com` and adding the same two headers. + For GraphQL the equivalent is swapping `graphql.contentstack.com` → `graphql-preview.contentstack.com` and adding the same two headers. Keep the `access_token` (delivery token) and `Content-Type` headers on every request; the preview headers are added to them, not swapped in. 4. Bypass any cache layer for preview requests. Do not try to fix it with a smarter cache key: the hash is stable for the whole preview session, so any cache on this path serves the first response for the rest of it. - **verification**: Open the entry in Live Preview, then in DevTools → Network confirm requests go to the `*-preview.contentstack.com` host, carry `preview_token` and `live_preview` headers, and return 200. Edit a field without saving; the preview must update. The Onboarding Check should reach **Setup Complete**. @@ -43,8 +43,8 @@ setup, use `setup-docs.md` instead. - **fix**: 1. Remove `X-Frame-Options` for the preview host and use CSP instead, allowing the Contentstack app origin for the stack's region: `Content-Security-Policy: frame-ancestors 'self' https://app.contentstack.com;` (for example `https://eu-app.contentstack.com` in EU). List the exact app host for each region the stack uses; avoid `https://*.contentstack.com`, which lets any Contentstack subdomain frame the site. `X-Frame-Options` has no allowlist syntax; a bare `SAMEORIGIN` always wins. 2. Apply the header on every route, not just the site root. A route that redirects to a different hostname than the configured Base URL will also fail. - 3. If the deployment sits behind platform password protection, note that no header or query parameter can be injected into a browser-originated iframe request from Contentstack. Options: disable protection on the preview deployment, put a server-side proxy in front that injects the header, or use Live Preview → Open in New Tab (a plan-gated feature that renders outside the iframe). Do not put a bypass token in the Base URL: Live Preview appends the entry path into the last query value, so the token and the path both break. See `base-url-query-string-corrupts-preview-url`. - 4. Third-party SSO screens that themselves set `X-Frame-Options: DENY` cannot render in the iframe at all. Use Open in New Tab, which renders the preview outside the iframe so those screens can load. + 3. If the deployment sits behind platform password protection, note that no header or query parameter can be injected into a browser-originated iframe request from Contentstack. Options: disable protection on the preview deployment, put a server-side proxy in front that injects the header, or, for Live Preview only, use Open in New Tab (a plan-gated feature that renders outside the iframe). Visual Editor does not support Open in New Tab; it always renders the site in its canvas iframe, so it needs one of the other options. Do not put a bypass token in the Base URL: Live Preview appends the entry path into the last query value, so the token and the path both break. See `base-url-query-string-corrupts-preview-url`. + 4. Third-party SSO screens that themselves set `X-Frame-Options: DENY` cannot render in the iframe at all. For Live Preview, use Open in New Tab, which renders the preview outside the iframe so those screens can load. Visual Editor has no such mode yet: the preview deployment needs a sign-in path that works when framed, or no SSO in front of it. 5. On the Live Preview Onboarding Check this shows as **Live Preview SDK Not Initialized**, not "Could Not Connect to Website". The reachability gate is a `no-cors` request, which succeeds on any HTTP response, so frame headers and auth screens pass it. - **verification**: `curl -I https:///` and confirm no `X-Frame-Options` and a `frame-ancestors` value that includes the Contentstack app origin. Reload Live Preview; the pane should render. @@ -153,7 +153,7 @@ setup, use `setup-docs.md` instead. - **rendering_modes**: CSR, SSR - **root_cause**: With `editButton.enable: true` and no `exclude` (the defaults), the SDK renders the button on any page that loads it, inside the iframe or not. It creates `#cslp-tooltip` when the module is **imported**, before `init()` runs, so a production build that imports the SDK and never calls `init()` still has the element; config passed to `init()` is applied only afterwards. It never checks the `live_preview` hash or any session signal. `inIframe()` only matters when `exclude` is set, and a `?cslp-buttons=` query parameter overrides `exclude` unless `includeByQueryParameter: false`. Teams that gate `init()` on a server-read hash also get bitten by App Router soft navigation, which does not re-run that server-side gate while the SDK's button instance persists across route changes. - **fix**: - 1. Add `editButton: { enable: true, exclude: ['outsideLivePreviewPortal'], includeByQueryParameter: false }`. Outside the iframe the button no longer renders, a query parameter cannot bring it back, and Live Preview inside the pane keeps working. + 1. Where `init()` runs on the page, add `editButton: { enable: true, exclude: ['outsideLivePreviewPortal'], includeByQueryParameter: false }`. Outside the iframe the button no longer renders, a query parameter cannot bring it back, and Live Preview inside the pane keeps working. This config is applied only by `init()`, so it does nothing for a build that imports the SDK without calling `init()`: use step 2 there. 2. If Live Preview is not used on production at all, keep the SDK out of the production bundle: build with `PURGE_PREVIEW_SDK=true` (or `REACT_APP_PURGE_PREVIEW_SDK=true`), which swaps in a no-op SDK and skips the import-time button, or load the SDK with a dynamic import that runs only for preview requests. The flag works only if the bundler exposes `process.env` to browser code. Skipping `init()` or passing `enable: false` is not enough on its own, because the element is created at import. 3. Do not rely on a server-side hash check alone in an App Router app; soft navigation will not re-evaluate it. - **verification**: Load the production URL in a normal tab with DevTools open. `document.getElementById('cslp-tooltip')` returns `null`, and no `data-cslp` attributes are present if the SDK runs with `enable: false`. @@ -165,12 +165,12 @@ setup, use `setup-docs.md` instead. - **symptom**: `Access to fetch at 'https://-rest-preview.contentstack.com/v3/...' from origin '' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource`, frequently alongside a `401 (Unauthorized)` on the same request. Works on localhost, fails on the deployed dev/staging host. - **frameworks**: Gatsby, Angular, Next.js, React - **rendering_modes**: CSR mainly -- **root_cause**: The preview request is genuinely rejected (bad or wrong-type token, or a host for the wrong region), and the error response carries no CORS headers, so the browser reports it as a CORS failure instead of a 401. A block by the site's own Content Security Policy looks different: the console shows a separate `Refused to connect to '' because it violates the following Content Security Policy directive` error, not a CORS message. There is no per-stack "CORS allowlist" on the Contentstack side to add origins to. +- **root_cause**: The preview request is genuinely rejected (bad or wrong-type token, or a host for the wrong region), and the error response carries no CORS headers, so the browser reports it as a CORS failure instead of a 401. A block by the site's own Content Security Policy looks different: the console shows a separate `Refused to connect to '' because it violates the following Content Security Policy directive` error, not a CORS message. Rule out both before looking at the Contentstack side; if both are ruled out and the request still fails, hand the failing request to Contentstack Support. - **fix**: 1. Fix the token and host first: confirm you are sending a valid **Preview Token** (not a Delivery Token, not a Management Token) in the `preview_token` header, that the preview host matches the stack's region, and regenerate the token if in doubt. 2. Recheck env vars after a stack migration or API key change — a stale API key produces the same 401-behind-CORS shape. 3. Only if the console also shows a `Refused to connect … Content Security Policy` error: allow every Contentstack host the page calls in the site's `connect-src`: the region's delivery, preview, GraphQL and asset hosts as well as the app host. Listing only the app and REST preview hosts usually misses one. -- **verification**: `curl` the same preview URL from a terminal, passing credentials from environment variables rather than inline, for example `curl -s -o /dev/null -w '%{http_code}\n' -H "api_key: $CONTENTSTACK_API_KEY" -H "preview_token: $CONTENTSTACK_PREVIEW_TOKEN" ""`. A 200 proves the token and host are valid and the remaining problem is browser-side. In the browser, the request should complete with `Access-Control-Allow-Origin` present. +- **verification**: `curl` the same preview URL from a terminal, passing credentials from environment variables rather than inline, for example `curl -s -o /dev/null -w '%{http_code}\n' -H "api_key: $CONTENTSTACK_API_KEY" -H "preview_token: $CONTENTSTACK_PREVIEW_TOKEN" ""`. A 200 proves only that the token and host are valid, because `curl` does not enforce CORS; the remaining problem is browser-side. In the browser, the request should complete with `Access-Control-Allow-Origin` present. --- @@ -182,7 +182,7 @@ setup, use `setup-docs.md` instead. - **root_cause**: In SSR the SDK does not fetch content. It puts `?live_preview=&content_type_uid=...&entry_uid=...` on the URL and reloads, and preview state lives **on the Stack instance**. Failure (A) is having two instances: a long-lived "default" Stack for page queries plus a second Stack passed only to `init()`, so the hash never lands on the instance that queries. Failure (B) is having one module-level instance shared across requests: once any request puts it into preview mode, unrelated requests inherit it, and ordinary delivery traffic starts hitting the preview service with a hash that has expired (hashes are session-scoped and time-limited; the preview session issues a fresh one, so a stored or hardcoded hash eventually fails with the tracker-invalid text above) or belongs to another branch. Under concurrency requests can also overwrite each other's config mid-flight. - **fix**: 1. Create a fresh Delivery SDK instance **per request**. Do not share a module-level Stack, and pass the instance down through request-scoped context rather than importing a singleton. This one change fixes both failures. - 2. Read the hash off the incoming request each time and apply it to that instance: `stack.livePreviewQuery({ live_preview: hash, contentTypeUid, entryUid, preview_timestamp })`. + 2. Read the hash off the incoming request each time and apply it to that instance: `stack.livePreviewQuery({ live_preview: hash, contentTypeUid, entryUid, preview_timestamp })`. `live_preview` is the only required key: when it is empty the SDK resets the instance to published content and clears the other keys. The SDK accepts `content_type_uid` / `entry_uid` as well as the camelCase spellings, so passing `request.query` straight through also works when its values are plain strings. `preview_timestamp` is what Timeline needs. 3. Call `livePreviewQuery(...)` **unconditionally** per request, with empty values when there is no hash. Calling it only when a hash exists leaves the previous request's hash in place. 4. Run every query that should show drafts on that instance. A query on an un-hashed instance returns published content. 5. Drop any separate "live preview only" Stack. `init()` does not need a Stack in SSR. diff --git a/skills/cms-live-preview-visual-editor-support-assistant/references/faq-preview-runtime.md b/skills/cms-live-preview-visual-editor-support-assistant/references/faq-preview-runtime.md index 7b1cdd7..fb70949 100644 --- a/skills/cms-live-preview-visual-editor-support-assistant/references/faq-preview-runtime.md +++ b/skills/cms-live-preview-visual-editor-support-assistant/references/faq-preview-runtime.md @@ -29,11 +29,12 @@ the fixes here will help. - **symptom**: Preview works on localhost but not on a deployed environment with identical code and config — the setup status can even show "Setup Complete" and edits go through in the entry form while the rendered page never changes. Or preview stops updating and only recovers in an incognito window or after a hard reload. - **frameworks**: Next.js, framework-agnostic - **rendering_modes**: SSR | SSG/ISR | edge -- **root_cause**: A cache sits between the browser and the preview service. Whether or not its key includes the `live_preview` hash, preview requests get a stored payload instead of a live one. Seen with a customer CDN in front of the deployed environment, with an app-level fetch cache, and (on the Contentstack side) with stale JS bundles cached in the browser or CDN after a release. The Contentstack SDKs' own cache policies (`IGNORE_CACHE`, `CACHE_THEN_NETWORK`, `CACHE_ELSE_NETWORK`, `NETWORK_ELSE_CACHE`) do **not** switch themselves off for Live Preview — they cache regardless of the preview config. +- **root_cause**: A cache sits between the browser and the preview service. Whether or not its key includes the `live_preview` hash, preview requests get a stored payload instead of a live one. Seen with a customer CDN in front of the deployed environment, with an app-level fetch cache, and (on the Contentstack side) with stale JS bundles cached in the browser or CDN after a release. SDK-level caching is a separate layer and depends on the SDK: the legacy `contentstack` v3 JavaScript SDK forces `NETWORK_ELSE_CACHE` once a real `live_preview` hash is set, so its cache only serves as a fallback during preview. Do not assume the same of other SDKs. - **fix**: - 1. Bypass every cache layer when a `live_preview` hash is present: no CDN caching of the preview host or the preview route, `cache: 'no-store'` on the fetch. If the app opted into SDK-level caching, also set `Policy.IGNORE_CACHE` in `cacheOptions` — but `cacheOptions` is optional and unset by default, so most apps have no SDK cache to disable and can skip this. - 2. Do not cache preview responses at all, under any key. The `live_preview` hash identifies the preview **session**, not the content version, so it stays the same across every edit in that session. Keying a cache on it means the first response is served for the rest of the session and the canvas silently stops updating. There is no cache key that makes preview responses safe to cache — use the preview parameters to *bypass* the cache, never to key it. - 3. Exclude the preview environment's base URL from the CDN entirely — the preview service cannot be cached at origin either, which is also why preview responses are measurably slower than CDN delivery (roughly 1s vs 100ms in one measured case). That gap is expected. + 1. Bypass every app and CDN cache layer when a `live_preview` hash is present: no CDN caching of the preview host or the preview route, `cache: 'no-store'` on the fetch. + 2. Check SDK-level caching separately. Most apps never configure one. If the app did, find out what that SDK does when a preview hash is set before relying on it, and turn it off for preview requests if in doubt. + 3. Do not cache preview responses at all, under any key. The `live_preview` hash identifies the preview **session**, not the content version: it does not change when an entry is edited (it rotates only on a 24-hour timer). Keying a cache on it means the first response is served for the rest of the session and the canvas silently stops updating. There is no cache key that makes preview responses safe to cache — use the preview parameters to *bypass* the cache, never to key it. + 4. Exclude the preview environment's base URL from the CDN entirely — the preview service cannot be cached at origin either, which is also why preview responses are measurably slower than CDN delivery (roughly 1s vs 100ms in one measured case). That gap is expected. - **verification**: Compare response headers on the preview request for cache hits. Reproduce in a private window; if the private window works and the normal one does not, it is a cache. --- @@ -139,8 +140,8 @@ the fixes here will help. - **root_cause**: The preview renders inside a cross-origin iframe. Third-party scripts whose targeting or delivery logic depends on the top-level host, referrer, or first-party storage see the iframe context instead of the real site and behave differently. Not a Contentstack request failure: the calls fire and fail at the third party's delivery stage. This is inherent to rendering the site in an iframe and there is no product-side fix for it. - **fix**: 1. Where the third party allows it, add the Contentstack app origin to its allowed-referrer or allowed-domain configuration. - 2. Use **Open in New Tab**, which renders the preview outside the iframe so the third party sees the real host. It is plan-gated; if it is missing, see `contact-support.md`. + 2. In Live Preview, use **Open in New Tab**, which renders the preview outside the iframe so the third party sees the real host. It is plan-gated; if it is missing, see `contact-support.md`. Visual Editor does not support it and always renders in its canvas iframe, so use step 1 or 3 there. 3. Where neither is possible, exclude those third-party scripts when the preview parameters are present, so authors preview content without them rather than with a broken version of them. -- **verification**: Use Open in New Tab rather than the preview panel and confirm the third-party content renders. That difference confirms the iframe context is the trigger. +- **verification**: In Live Preview, use Open in New Tab rather than the preview panel and confirm the third-party content renders. That difference confirms the iframe context is the trigger. --- diff --git a/skills/cms-live-preview-visual-editor-support-assistant/references/frameworks.md b/skills/cms-live-preview-visual-editor-support-assistant/references/frameworks.md index cc07083..bb0c552 100644 --- a/skills/cms-live-preview-visual-editor-support-assistant/references/frameworks.md +++ b/skills/cms-live-preview-visual-editor-support-assistant/references/frameworks.md @@ -29,7 +29,7 @@ export function LivePreviewInit() { ContentstackLivePreview.init({ ssr: false, mode: "builder", - stackSdk: stack.config, + stackSdk: stack.config, // @contentstack/delivery-sdk; with the legacy contentstack SDK pass the Stack instance stackDetails: { apiKey: API_KEY, environment: ENVIRONMENT }, }); }, []); @@ -115,7 +115,7 @@ render: ContentstackLivePreview.init({ ssr: false, mode: "builder", - stackSdk: stack.config, + stackSdk: stack.config, // @contentstack/delivery-sdk; with the legacy contentstack SDK pass the Stack instance stackDetails: { apiKey: API_KEY, environment: ENVIRONMENT }, }); ```