From ddfcea40506eaff4c6bcde2e77456a71aae8c044 Mon Sep 17 00:00:00 2001 From: Tim Benniks Date: Tue, 30 Jun 2026 10:30:42 +0200 Subject: [PATCH 01/20] added kickstart skill and docs --- .gitignore | 1 + README.md | 14 ++- codex/AGENTS.md | 1 + codex/dx-kickstart-next/SKILL.md | 32 +++++++ .../references/content-model.md | 48 ++++++++++ .../references/contentstack.md | 48 ++++++++++ codex/dx-kickstart-next/references/next.md | 42 +++++++++ codex/dx-kickstart-next/references/review.md | 45 +++++++++ .../dx-kickstart-next/references/workflow.md | 46 ++++++++++ cursor/rules/00-router.mdc | 1 + cursor/rules/18-dx-kickstart-next.mdc | 35 +++++++ ...sdk.mdc => 19-dx-migrate-js-to-ts-sdk.mdc} | 0 ...nvironment-variables-from-env-example.mdc} | 0 ...rigger-and-monitor-launch-deployments.mdc} | 0 ...mpanion.mdc => 22-migration-companion.mdc} | 0 docs/README.md | 62 +++++++++++++ docs/contributing/add-or-edit-a-skill.md | 64 +++++++++++++ docs/contributing/authoring-conventions.md | 61 ++++++++++++ docs/contributing/release-and-versioning.md | 65 +++++++++++++ docs/get-started/install-claude-code.md | 50 ++++++++++ docs/get-started/install-codex.md | 54 +++++++++++ docs/get-started/install-cursor.md | 55 +++++++++++ docs/get-started/install-gemini.md | 45 +++++++++ docs/get-started/quickstart.md | 71 ++++++++++++++ docs/get-started/skills-cli.md | 47 ++++++++++ docs/get-started/verify-setup.md | 52 +++++++++++ docs/how-it-works/architecture.md | 78 ++++++++++++++++ docs/how-it-works/router.md | 65 +++++++++++++ docs/how-it-works/security-model.md | 92 +++++++++++++++++++ docs/how-it-works/skill-anatomy.md | 89 ++++++++++++++++++ docs/overview/concepts.md | 64 +++++++++++++ docs/overview/introduction.md | 55 +++++++++++ docs/overview/supported-tools.md | 37 ++++++++ docs/skills/brand-kit-assistant.md | 42 +++++++++ docs/skills/cms-assets.md | 38 ++++++++ docs/skills/cms-branches-aliases.md | 39 ++++++++ .../cms-data-modeling-best-practices.md | 52 +++++++++++ docs/skills/cms-entries.md | 41 +++++++++ docs/skills/cms-environments-publishing.md | 40 ++++++++ ...review-visual-builder-support-assistant.md | 45 +++++++++ docs/skills/cms-localization.md | 39 ++++++++ docs/skills/cms-releases.md | 38 ++++++++ docs/skills/cms-roles-permissions.md | 39 ++++++++ docs/skills/cms-taxonomy.md | 38 ++++++++ docs/skills/cms-tokens-authentication.md | 49 ++++++++++ docs/skills/cms-variants-personalization.md | 37 ++++++++ docs/skills/cms-webhooks.md | 40 ++++++++ docs/skills/cms-workflows.md | 39 ++++++++ docs/skills/developer-hub-app-architect.md | 47 ++++++++++ docs/skills/dx-delivery-sdk.md | 55 +++++++++++ docs/skills/dx-kickstart-next.md | 48 ++++++++++ docs/skills/dx-migrate-js-to-ts-sdk.md | 40 ++++++++ docs/skills/index.md | 61 ++++++++++++ ...-environment-variables-from-env-example.md | 47 ++++++++++ ...-trigger-and-monitor-launch-deployments.md | 48 ++++++++++ docs/skills/migration-companion.md | 51 ++++++++++ manifest.json | 7 +- skills/CLAUDE.md | 1 + skills/dx-kickstart-next/SKILL.md | 34 +++++++ .../references/content-model.md | 48 ++++++++++ .../references/contentstack.md | 48 ++++++++++ skills/dx-kickstart-next/references/next.md | 42 +++++++++ skills/dx-kickstart-next/references/review.md | 45 +++++++++ .../dx-kickstart-next/references/workflow.md | 46 ++++++++++ 64 files changed, 2698 insertions(+), 5 deletions(-) create mode 100644 codex/dx-kickstart-next/SKILL.md create mode 100644 codex/dx-kickstart-next/references/content-model.md create mode 100644 codex/dx-kickstart-next/references/contentstack.md create mode 100644 codex/dx-kickstart-next/references/next.md create mode 100644 codex/dx-kickstart-next/references/review.md create mode 100644 codex/dx-kickstart-next/references/workflow.md create mode 100644 cursor/rules/18-dx-kickstart-next.mdc rename cursor/rules/{18-dx-migrate-js-to-ts-sdk.mdc => 19-dx-migrate-js-to-ts-sdk.mdc} (100%) rename cursor/rules/{19-launch-sync-environment-variables-from-env-example.mdc => 20-launch-sync-environment-variables-from-env-example.mdc} (100%) rename cursor/rules/{20-launch-trigger-and-monitor-launch-deployments.mdc => 21-launch-trigger-and-monitor-launch-deployments.mdc} (100%) rename cursor/rules/{21-migration-companion.mdc => 22-migration-companion.mdc} (100%) create mode 100644 docs/README.md create mode 100644 docs/contributing/add-or-edit-a-skill.md create mode 100644 docs/contributing/authoring-conventions.md create mode 100644 docs/contributing/release-and-versioning.md create mode 100644 docs/get-started/install-claude-code.md create mode 100644 docs/get-started/install-codex.md create mode 100644 docs/get-started/install-cursor.md create mode 100644 docs/get-started/install-gemini.md create mode 100644 docs/get-started/quickstart.md create mode 100644 docs/get-started/skills-cli.md create mode 100644 docs/get-started/verify-setup.md create mode 100644 docs/how-it-works/architecture.md create mode 100644 docs/how-it-works/router.md create mode 100644 docs/how-it-works/security-model.md create mode 100644 docs/how-it-works/skill-anatomy.md create mode 100644 docs/overview/concepts.md create mode 100644 docs/overview/introduction.md create mode 100644 docs/overview/supported-tools.md create mode 100644 docs/skills/brand-kit-assistant.md create mode 100644 docs/skills/cms-assets.md create mode 100644 docs/skills/cms-branches-aliases.md create mode 100644 docs/skills/cms-data-modeling-best-practices.md create mode 100644 docs/skills/cms-entries.md create mode 100644 docs/skills/cms-environments-publishing.md create mode 100644 docs/skills/cms-live-preview-visual-builder-support-assistant.md create mode 100644 docs/skills/cms-localization.md create mode 100644 docs/skills/cms-releases.md create mode 100644 docs/skills/cms-roles-permissions.md create mode 100644 docs/skills/cms-taxonomy.md create mode 100644 docs/skills/cms-tokens-authentication.md create mode 100644 docs/skills/cms-variants-personalization.md create mode 100644 docs/skills/cms-webhooks.md create mode 100644 docs/skills/cms-workflows.md create mode 100644 docs/skills/developer-hub-app-architect.md create mode 100644 docs/skills/dx-delivery-sdk.md create mode 100644 docs/skills/dx-kickstart-next.md create mode 100644 docs/skills/dx-migrate-js-to-ts-sdk.md create mode 100644 docs/skills/index.md create mode 100644 docs/skills/launch-sync-environment-variables-from-env-example.md create mode 100644 docs/skills/launch-trigger-and-monitor-launch-deployments.md create mode 100644 docs/skills/migration-companion.md create mode 100644 skills/dx-kickstart-next/SKILL.md create mode 100644 skills/dx-kickstart-next/references/content-model.md create mode 100644 skills/dx-kickstart-next/references/contentstack.md create mode 100644 skills/dx-kickstart-next/references/next.md create mode 100644 skills/dx-kickstart-next/references/review.md create mode 100644 skills/dx-kickstart-next/references/workflow.md diff --git a/.gitignore b/.gitignore index e43b0f9..20febc2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +.obsidian diff --git a/README.md b/README.md index a6cbbbd..4e36aa3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Contentstack Skills -A bundle of 21 ready-to-use [Contentstack](https://www.contentstack.com) agent skills for AI coding tools, covering CMS implementation, Brand Kit guidance, delivery SDK development, migration workflows, Developer Hub app architecture, and Launch automation. +A bundle of 22 ready-to-use [Contentstack](https://www.contentstack.com) agent skills for AI coding tools, covering CMS implementation, Brand Kit guidance, delivery SDK development, kickstart maintenance, migration workflows, Developer Hub app architecture, and Launch automation. ## What's in here? @@ -21,7 +21,7 @@ You only need to install one. Pick the section below that matches your tool. ### Claude Code ``` -/plugin marketplace add +/plugin marketplace add contentstack/contentstack-agent-skills /plugin install contentstack-skills ``` @@ -35,16 +35,18 @@ Install via Cursor's plugin marketplace, **or** copy `cursor/rules/*.mdc` into y Point your agent at this repo or copy the `codex/` directory into your project. The entry point is [`codex/AGENTS.md`](codex/AGENTS.md). +Repository: [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills) + ### Gemini CLI ``` -gemini extensions install +gemini extensions install contentstack/contentstack-agent-skills ``` ### skills CLI (single skill on demand) ``` -npx skills add @ +npx skills add contentstack/contentstack-agent-skills@ ``` ## Skills included @@ -68,6 +70,7 @@ npx skills add @ | `cms-workflows` | Workflows & Publish Rules | CMS | Workflow stages, approval flows, transition restrictions, publish governance, automation hooks, and common pitfalls. | | `developer-hub-app-architect` | Developer Hub App Architect | Developer Hub | Developer Hub and Marketplace app planning, UI location choices, React/TypeScript scaffolding, setup, SDK, manifest, proxy, and publishing issues. | | `dx-delivery-sdk` | Delivery SDK | Developer Experience | Production-ready TypeScript with `@contentstack/delivery-sdk` for entries, assets, references, filters, sorting, pagination, locales, Live Preview, and Visual Builder. | +| `dx-kickstart-next` | Contentstack Kickstart Next | Developer Experience | Maintaining Contentstack's Next.js kickstart: App Router structure, Delivery SDK setup, Live Preview, seeded stack alignment, env vars, validation, and PR reviews. | | `dx-migrate-js-to-ts-sdk` | Migrate JS to TS SDK | Developer Experience | Migration from the JavaScript Contentstack SDK to the TypeScript Delivery SDK, including API mapping, rewrites, and unsupported pattern callouts. | | `launch-sync-environment-variables-from-env-example` | Sync Launch environment variables from .env.example | Launch | Comparing a local `.env.example` with Launch environment variables and patching missing keys without printing secrets. | | `launch-trigger-and-monitor-launch-deployments` | Trigger and Monitor Launch Deployments | Launch | Triggering Launch deployments, polling deployment status, retrieving failure logs, and summarizing likely causes and next steps. | @@ -92,11 +95,14 @@ skills/CLAUDE.md (router) ──► cursor/rules/00-router.mdc .github/workflows/ CI that regenerates cursor/rules and codex on push codex/ Generated Codex tree — do not edit cursor/rules/ Generated Cursor rules — do not edit +docs/ Official documentation source for the skills bundle scripts/ Contributor build scripts skills/ Source of truth — edit here gemini-extension.json Gemini CLI extension manifest ``` +The `docs/` directory contains the official documentation pages for installation, setup verification, architecture, contributing, and the skill reference. + ## Editing skills Edit only under `skills/`. Then regenerate the derived trees: diff --git a/codex/AGENTS.md b/codex/AGENTS.md index e86f870..abb039d 100644 --- a/codex/AGENTS.md +++ b/codex/AGENTS.md @@ -8,6 +8,7 @@ Use the table below to route a user request to the right skill. Each row maps a | Use when users want to migrate, move, switch, port, or re-platform from Contentful to Contentstack, including content models, content, assets, locales, application integrations, website code, migration prerequisites, migration progress checks, or post-migration validation. | [contentstack-migration-companion](./migration-companion/SKILL.md) | | Use when a user wants to migrate Contentstack Delivery SDK code from JavaScript to TypeScript. | [dx-migrate-js-to-ts-sdk](./dx-migrate-js-to-ts-sdk/SKILL.md) | | Use when a user asks for Contentstack Delivery SDK code, query examples, helper functions, SDK setup, stack initialization, reference inclusion, filtering, sorting, pagination, typed entry fetching, asset fetching, Live Preview setup, Visual Builder support, SSR preview handling, or debugging SDK query chains. | [dx-delivery-sdk](./dx-delivery-sdk/SKILL.md) | +| Use when working on Contentstack's `kickstart-next` repository or a close fork, including Next.js App Router structure, Contentstack Delivery SDK setup, Live Preview or Visual Builder behavior, seeded stack alignment, environment variables, endpoint or image host configuration, package scripts, validation, CI expectations, or PR review checklists. | [contentstack-kickstart-next](./dx-kickstart-next/SKILL.md) | | Use when designing, reviewing, or refactoring Contentstack content models before creating or changing schemas. | [Contentstack Data Modeling Best Practices](./cms-data-modeling-best-practices/SKILL.md) | | Use this skill when a user is implementing or debugging Contentstack Live Preview or Visual Builder, including blank preview panels, stale or published-only preview, lost preview context after navigation, shared SSR state, cache contamination, or edit-tag mapping failures. Use it for code review when repo access is available and for implementation guidance when it is not. | [Live Preview and Visual Builder Support Assistant](./cms-live-preview-visual-builder-support-assistant/SKILL.md) | | Use when developers ask about fetching entries, building CDA queries, handling localization, publishing workflows, versioning behavior, bulk operations, or entry-related performance issues. | [Entries](./cms-entries/SKILL.md) | diff --git a/codex/dx-kickstart-next/SKILL.md b/codex/dx-kickstart-next/SKILL.md new file mode 100644 index 0000000..226e0c2 --- /dev/null +++ b/codex/dx-kickstart-next/SKILL.md @@ -0,0 +1,32 @@ +# contentstack-kickstart-next + + +# Contentstack kickstart-next + +Use this skill when working in `contentstack/kickstart-next` or a close fork. Inspect the repository first, then load only the matching reference files. + +## Routing + +1. For App Router routes, React components, client/server boundaries, Tailwind, ESLint, TypeScript, images, or `next.config.mjs`, read [references/next.md](references/next.md). +2. For Contentstack delivery, preview, Visual Builder, regions, endpoint overrides, env vars, or seeded stack alignment, read [references/contentstack.md](references/contentstack.md). +3. For content type UIDs, field UIDs, modular blocks, CSLP `$` mappings, or schema-driven renderer/type changes, read [references/content-model.md](references/content-model.md). +4. For local setup, Contentstack stack seeding, npm scripts, CI, CODEOWNERS, validation commands, docs updates, or PR prep, read [references/workflow.md](references/workflow.md). +5. For PR/code reviews, severity labels, security checks, or risk checklists, read [references/review.md](references/review.md). + +## Default working rules + +- Keep guidance grounded in the current checkout. Inspect files before assuming scripts, tests, CI, content types, env vars, or framework conventions exist. +- Treat kickstarts as user-facing examples: prefer clarity, minimal moving parts, safe defaults, and copyable setup steps over clever abstractions. +- Preserve Live Preview behavior when changing data fetching, route rendering, components, content types, field UIDs, or Visual Builder bindings. +- Never commit real Contentstack credentials. Use placeholders in docs and `.env.example`; real values belong in a local gitignored `.env`. +- When adding or renaming env vars, update `.env.example` and user-facing docs together. +- When adding remote image sources, update the framework-specific image allowlist or documented env override. +- When modifying JavaScript or TypeScript files, run `npm run build`; also run `npm run lint` and any `typecheck` script if they exist. +- Before claiming CI covers something, verify the workflows. If build, lint, or tests are not wired into CI, tell the user to run them locally. + +## Response behavior + +- For implementation help, give concrete file-level changes and commands. +- For reviews, separate blockers from major issues and minor nits. +- For repo setup help, give the shortest successful path first, then optional troubleshooting. +- If asked to generalize framework-specific guidance later, keep Contentstack behavior in `contentstack.md` and Next.js behavior in `next.md`. diff --git a/codex/dx-kickstart-next/references/content-model.md b/codex/dx-kickstart-next/references/content-model.md new file mode 100644 index 0000000..fa8319e --- /dev/null +++ b/codex/dx-kickstart-next/references/content-model.md @@ -0,0 +1,48 @@ +# Content model guidance for kickstart-next + +Use this before changing Contentstack content type UIDs, field UIDs, `lib/types.ts`, modular block rendering, or Visual Builder/CSLP bindings. + +## Seed contract + +The app assumes content from `contentstack/kickstart-stack-seed`. Verify the actual stack or seed before making schema claims, but preserve this contract unless the user intentionally changes the model. + +| Content type | UID | Used by | +| --- | --- | --- | +| Page | `page` | `lib/contentstack.ts` `getPage(url)`, `app/page.tsx`, `components/Page.tsx`, `lib/types.ts` `Page` | + +## Page fields + +| Field | UID | Type shape in app | Rendered by | Live Preview binding | +| --- | --- | --- | --- | --- | +| Title | `title` | `Page.title: string` | `components/Page.tsx` `h1` | `page.$.title` | +| URL | `url` | `Page.url?: string` | queried by `getPage(url)` | `page.$.url` if rendered later | +| Description | `description` | `Page.description?: string` | `components/Page.tsx` paragraph | `page.$.description` | +| Image | `image` | `Page.image?: File \| null` | `next/image` in `components/Page.tsx` | asset `$` mapping, currently `page.image.$.url` | +| Rich Text | `rich_text` | `Page.rich_text?: string` | sanitized HTML in `components/Page.tsx` | `page.$.rich_text` | +| Blocks | `blocks` | `Page.blocks?: Blocks[]` | modular block loop in `components/Page.tsx` | `page.$.blocks` and indexed `page.$["blocks__${index}"]` | + +## Modular block shape + +The `blocks` field contains entries shaped like `{ block: Block }`. + +| Block field | UID | Type shape in app | Rendered by | Live Preview binding | +| --- | --- | --- | --- | --- | +| Title | `title` | `Block.title?: string` | block `h2` | `block.$.title` | +| Copy | `copy` | `Block.copy?: string` | sanitized HTML | `block.$.copy` | +| Image | `image` | `Block.image?: File \| null` | `next/image` | `block.$.image` | +| Layout | `layout` | `"image_left" \| "image_right" \| null` | flex direction choice | `block.$.layout` if rendered later | +| Metadata | `_metadata.uid` | key fallback for React list items | list item key | not user-editable | + +## Asset shape + +- Use the local `File` interface for Contentstack assets. +- Render images with `file.url` and descriptive alt text from `file.title` or another safe fallback. +- Keep asset CSLP mappings under `File.$` when the rendered asset field needs Visual Builder editing. + +## Change checklist + +- If a UID changes, update `getPage`, `lib/types.ts`, renderers, docs, and any Contentstack seed instructions together. +- If a field is added, add the TypeScript shape, render path, fallback behavior for missing content, and `$` mapping only where the field is editable. +- If a modular block is added, preserve empty-block editing support with `VB_EmptyBlockParentClass` on the parent block container. +- If rich text or HTML-like fields are added, sanitize before rendering with `dangerouslySetInnerHTML`. +- If image fields are added, verify `next.config.mjs` allows the image hostname. diff --git a/codex/dx-kickstart-next/references/contentstack.md b/codex/dx-kickstart-next/references/contentstack.md new file mode 100644 index 0000000..8c5ae29 --- /dev/null +++ b/codex/dx-kickstart-next/references/contentstack.md @@ -0,0 +1,48 @@ +# Contentstack guidance for kickstart-next + +Use this when changing how `kickstart-next` talks to Contentstack, handles preview, resolves regions/hosts, or aligns with the seeded content model. + +## Delivery and preview + +- Keep stack configuration and fetching centralized in `lib/contentstack.ts`. +- Create the stack with `@contentstack/delivery-sdk`, using API key, delivery token, environment, region, optional custom delivery host, and `live_preview` options. +- Initialize Live Preview with `@contentstack/live-preview-utils` using builder mode, stack SDK/config, stack details, client URL params, and edit button settings. +- Query the `page` content type by URL when resolving pages. In `kickstart-next`, `getPage(url)` filters `url` with `QueryOperation.EQUALS` and returns the first `Page` entry. +- When preview mode is enabled, add editable tags with `contentstack.Utils.addEditableTags()` and preserve `$` attributes on entries, fields, and modular blocks. + +## Preview versus production + +- Preserve the split between production server rendering and preview client refreshes. +- `app/page.tsx` should fetch `getPage("/")` server-side before branching so both production and preview receive initial content. +- Preview should render `components/Preview.tsx`, initialize Live Preview client-side, subscribe to entry changes, and refetch the current path. + +## Regions and hosts + +- Prefer Contentstack endpoint helpers where already used by the repo. Current `kickstart-next` uses `getContentstackEndpoint(region, "", true)` from `@contentstack/utils`. +- Keep advanced host overrides documented and wired consistently: + - Delivery host override: `NEXT_PUBLIC_CONTENTSTACK_CONTENT_DELIVERY` in `kickstart-next`. + - Preview host override: `NEXT_PUBLIC_CONTENTSTACK_PREVIEW_HOST` in `kickstart-next`. + - Application or Live Preview UI host override: `NEXT_PUBLIC_CONTENTSTACK_CONTENT_APPLICATION` in `kickstart-next`. + - Image hostname override: `NEXT_PUBLIC_CONTENTSTACK_IMAGE_HOSTNAME` in `kickstart-next`. +- If a variable is supported in code but missing from `.env.example` or README setup docs, update the docs/example when touching that area. + +## Environment variables + +- Required for normal operation: `NEXT_PUBLIC_CONTENTSTACK_API_KEY`, `NEXT_PUBLIC_CONTENTSTACK_DELIVERY_TOKEN`, `NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT`, `NEXT_PUBLIC_CONTENTSTACK_REGION`. +- Required for preview mode: `NEXT_PUBLIC_CONTENTSTACK_PREVIEW=true` and `NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN`. +- Advanced/dedicated-environment overrides: `NEXT_PUBLIC_CONTENTSTACK_CONTENT_DELIVERY`, `NEXT_PUBLIC_CONTENTSTACK_PREVIEW_HOST`, `NEXT_PUBLIC_CONTENTSTACK_CONTENT_APPLICATION`, `NEXT_PUBLIC_CONTENTSTACK_IMAGE_HOSTNAME`. +- Keep real tokens out of committed files. Use placeholder values in `.env.example`, README snippets, and docs. + +## Seed alignment + +- Assume the app is aligned to the `contentstack/kickstart-stack-seed` stack unless the repo says otherwise. +- For a compact schema map, read [content-model.md](content-model.md) before changing content type UIDs, field UIDs, modular blocks, TypeScript entry shapes, or renderer bindings. +- Changing content type UIDs, field UIDs, or modular block shapes requires matching updates to `lib/types.ts`, renderers, docs, and Live Preview bindings. +- Preserve the `Page` fields expected by the seed: `title`, `url`, `description`, `image`, `rich_text`, and `blocks`. +- Preserve modular block support for `block.title`, `block.copy`, `block.image`, `block.layout`, and `_metadata.uid` unless intentionally changing the seed contract. +- Keep CSLP shapes aligned with the fields rendered in components. `$` mappings are needed on entries, assets, and modular blocks for Visual Builder editing. + +## Rendering safety + +- Continue sanitizing rich text HTML with `isomorphic-dompurify` before `dangerouslySetInnerHTML`. +- Keep `VB_EmptyBlockParentClass` on empty modular block containers so Visual Builder can target empty block areas. diff --git a/codex/dx-kickstart-next/references/next.md b/codex/dx-kickstart-next/references/next.md new file mode 100644 index 0000000..91d2205 --- /dev/null +++ b/codex/dx-kickstart-next/references/next.md @@ -0,0 +1,42 @@ +# Next.js guidance for kickstart-next + +Use this when changing the Next.js app, route structure, rendering behavior, images, TypeScript, ESLint, Tailwind, or package scripts. + +## App structure + +- `app/layout.tsx` is the root layout and imports `app/globals.css`. +- `app/page.tsx` is the home route. It calls `getPage("/")`, then renders `components/Preview.tsx` when preview is enabled or `components/Page.tsx` otherwise. +- `components/Preview.tsx` is a Client Component. Keep `"use client"` at the top if it uses hooks or `@contentstack/live-preview-utils` subscriptions. +- `components/Page.tsx` renders Contentstack fields and is imported elsewhere as `Page`, even though its internal function name may differ. +- `lib/contentstack.ts` owns Contentstack stack setup, `isPreview`, `initLivePreview()`, and `getPage(url)`. +- `lib/types.ts` owns TypeScript shapes for Contentstack entries, assets, modular blocks, and CSLP `$` mappings. + +## Client/server boundaries + +- Fetch initial page data in the route/server component where possible. +- Use `Preview` only for Live Preview client behavior: initialize preview, subscribe to `ContentstackLivePreview.onEntryChange`, refetch with `getPage(path)`, and unsubscribe on cleanup. +- Do not move browser-only preview utilities into server-only execution paths. + +## Images and rich text + +- Use `next/image` for Contentstack images. +- Keep allowed image hosts in `next.config.mjs` under `images.remotePatterns`. +- Default image hosts are `images.contentstack.io` and `*-images.contentstack.com`; `NEXT_PUBLIC_CONTENTSTACK_IMAGE_HOSTNAME` can override with a single hostname for custom environments. +- Sanitize rich text with `isomorphic-dompurify` before using `dangerouslySetInnerHTML`. + +## Styling + +- The project uses Tailwind CSS 4 via `@tailwindcss/postcss` in `postcss.config.mjs`. +- `app/globals.css` imports Tailwind with `@import "tailwindcss"` and includes base compatibility styles for Tailwind v4 border defaults. +- Keep the kickstart visually simple and example-friendly. Avoid adding a design system unless the user explicitly asks for one. + +## TypeScript and linting + +- `tsconfig.json` uses `strict: true`, `noEmit: true`, `moduleResolution: "bundler"`, and the `@/*` path alias. +- `eslint.config.mjs` composes Next core web vitals and TypeScript presets. +- `@typescript-eslint/no-explicit-any` is off in the current config, but prefer precise Contentstack types when practical. + +## Package scripts + +- Current scripts are usually `dev`, `build`, `start`, and `lint`. Verify `package.json` before telling the user a script exists. +- There is typically no `typecheck` script; if one is absent, say that type checking is covered by `next build` rather than claiming a separate command ran. diff --git a/codex/dx-kickstart-next/references/review.md b/codex/dx-kickstart-next/references/review.md new file mode 100644 index 0000000..f00fd34 --- /dev/null +++ b/codex/dx-kickstart-next/references/review.md @@ -0,0 +1,45 @@ +# Review guidance for kickstart-next + +Use this for PR reviews, pre-PR checks, risk assessment, or summarizing changes for maintainers. + +## Review stance + +- Lead with bugs, regressions, missing validation, and security risks. +- Ground findings in file and line references when reviewing a local checkout. +- Separate blockers, major issues, and minor nits. +- Keep summaries secondary to findings. + +## Blockers + +- Secrets or real Contentstack credentials committed anywhere. +- Build or lint failures caused by the change. +- Broken production home route or preview route. +- Live Preview or Visual Builder field binding regressions. +- XSS regression from unsanitized rich text or unsafe `dangerouslySetInnerHTML`. +- Content type UID, field UID, or modular block changes that are not reflected in types/renderers/docs. + +## Major issues + +- New environment variables missing from `.env.example` or setup docs. +- New remote image hostnames not represented in `next.config.mjs`. +- Moving Contentstack setup out of `lib/contentstack.ts` without a clear simplification. +- Client-only preview code introduced into server execution paths. +- Dependency additions that are unnecessary for a minimal kickstart or likely to fail security scans. +- CI claims that do not match `.github/workflows`. + +## Minor issues + +- Overly complex abstractions in example code. +- Copy or README changes that make setup less direct. +- Styling changes that distract from the kickstart's purpose as a minimal Contentstack integration example. +- Type looseness where existing Contentstack types could be extended cleanly. + +## Pre-PR checklist + +- Run `npm run build`. +- Run `npm run lint` if present. +- Run any `typecheck` or `test` scripts only if present. +- Verify `.env.example` and docs for env changes. +- Scan the diff for secrets. +- Read `references/content-model.md` for schema-impacting changes. +- Check preview behavior if data fetching, CSLP `$` attributes, components, content model fields, or Live Preview initialization changed. diff --git a/codex/dx-kickstart-next/references/workflow.md b/codex/dx-kickstart-next/references/workflow.md new file mode 100644 index 0000000..81e5378 --- /dev/null +++ b/codex/dx-kickstart-next/references/workflow.md @@ -0,0 +1,46 @@ +# Workflow guidance for kickstart-next + +Use this for setup, seeding, environment variables, validation commands, CI expectations, docs updates, dependency changes, or PR prep. + +## Local setup + +- Prefer npm: install with `npm install`. +- Copy `.env.example` to `.env` and fill in Contentstack values locally. +- Run the app with `npm run dev`, then open `http://localhost:3000`. +- For production verification, run `npm run build` and then `npm run start` if runtime behavior needs manual checking. + +## Contentstack stack setup + +- Install the Contentstack CLI with `npm install -g @contentstack/cli` if the user needs to seed a stack. +- Configure the CLI region when prompted; free developer accounts are commonly EU, but verify the user's account/URL. +- Login with `csdx auth:login`. +- Seed the compatible model with `csdx cm:stacks:seed --repo "contentstack/kickstart-stack-seed" --org "" -n "Kickstart Stack"`. +- Create a delivery token with preview scope and a preview token when Live Preview is needed. +- Enable Live Preview in the stack settings for the preview environment. + +## Validation + +- After JavaScript or TypeScript edits, run `npm run build`. +- Run `npm run lint` when the script exists. +- Run `npm run typecheck` only if `package.json` defines it. +- Run tests only if the checkout defines test scripts or test tooling. The upstream kickstart currently has no default `test` script. +- If validation cannot run because Contentstack credentials are unavailable, report that clearly and still run static checks that do not require credentials. + +## Environment and docs + +- When adding or renaming environment variables, update `.env.example` and user-facing setup docs together. +- Document runtime behavior changes in `docs/` when the repository has or needs product-facing docs for that behavior. +- Keep README setup snippets short and copyable. +- Never commit real API keys, delivery tokens, preview tokens, management tokens, organization IDs, or stack IDs. + +## CI expectations + +- Verify `.github/workflows` before making CI claims. +- Upstream workflows focus on security/policy checks such as Snyk/SCA, security policy/license checks, and issue-to-Jira integration. +- Do not assume GitHub Actions runs `npm run build`, `npm run lint`, unit tests, or E2E tests unless a workflow in the checkout proves it. + +## Ownership and dependencies + +- Check `.github/CODEOWNERS` before making reviewer or ownership claims. +- Dependency changes can affect Snyk/SCA workflows; keep package lock changes intentional and explain why a dependency is needed. +- Prefer npm for dependency installation and lockfile updates. diff --git a/cursor/rules/00-router.mdc b/cursor/rules/00-router.mdc index bffe8f7..5101f1c 100644 --- a/cursor/rules/00-router.mdc +++ b/cursor/rules/00-router.mdc @@ -13,6 +13,7 @@ Use the table below to route a user request to the right skill. Each row maps a | Use when users want to migrate, move, switch, port, or re-platform from Contentful to Contentstack, including content models, content, assets, locales, application integrations, website code, migration prerequisites, migration progress checks, or post-migration validation. | [contentstack-migration-companion](../../skills/migration-companion/SKILL.md) | | Use when a user wants to migrate Contentstack Delivery SDK code from JavaScript to TypeScript. | [dx-migrate-js-to-ts-sdk](../../skills/dx-migrate-js-to-ts-sdk/SKILL.md) | | Use when a user asks for Contentstack Delivery SDK code, query examples, helper functions, SDK setup, stack initialization, reference inclusion, filtering, sorting, pagination, typed entry fetching, asset fetching, Live Preview setup, Visual Builder support, SSR preview handling, or debugging SDK query chains. | [dx-delivery-sdk](../../skills/dx-delivery-sdk/SKILL.md) | +| Use when working on Contentstack's `kickstart-next` repository or a close fork, including Next.js App Router structure, Contentstack Delivery SDK setup, Live Preview or Visual Builder behavior, seeded stack alignment, environment variables, endpoint or image host configuration, package scripts, validation, CI expectations, or PR review checklists. | [contentstack-kickstart-next](../../skills/dx-kickstart-next/SKILL.md) | | Use when designing, reviewing, or refactoring Contentstack content models before creating or changing schemas. | [Contentstack Data Modeling Best Practices](../../skills/cms-data-modeling-best-practices/SKILL.md) | | Use this skill when a user is implementing or debugging Contentstack Live Preview or Visual Builder, including blank preview panels, stale or published-only preview, lost preview context after navigation, shared SSR state, cache contamination, or edit-tag mapping failures. Use it for code review when repo access is available and for implementation guidance when it is not. | [Live Preview and Visual Builder Support Assistant](../../skills/cms-live-preview-visual-builder-support-assistant/SKILL.md) | | Use when developers ask about fetching entries, building CDA queries, handling localization, publishing workflows, versioning behavior, bulk operations, or entry-related performance issues. | [Entries](../../skills/cms-entries/SKILL.md) | diff --git a/cursor/rules/18-dx-kickstart-next.mdc b/cursor/rules/18-dx-kickstart-next.mdc new file mode 100644 index 0000000..94a573e --- /dev/null +++ b/cursor/rules/18-dx-kickstart-next.mdc @@ -0,0 +1,35 @@ +--- +description: Guidance for building, reviewing, debugging, or extending Contentstack's kickstart-next repository. Use when working on the Next.js kickstart app, Contentstack Delivery SDK setup, Live Preview or Visual Builder behavior, seeded stack alignment, environment variables, endpoint or image host configuration, App Router structure, package scripts, local setup, CI expectations, tests, lint/build validation, or PR review checklists. +alwaysApply: false +--- + + +# Contentstack kickstart-next + +Use this skill when working in `contentstack/kickstart-next` or a close fork. Inspect the repository first, then load only the matching reference files. + +## Routing + +1. For App Router routes, React components, client/server boundaries, Tailwind, ESLint, TypeScript, images, or `next.config.mjs`, read [references/next.md](references/next.md). +2. For Contentstack delivery, preview, Visual Builder, regions, endpoint overrides, env vars, or seeded stack alignment, read [references/contentstack.md](references/contentstack.md). +3. For content type UIDs, field UIDs, modular blocks, CSLP `$` mappings, or schema-driven renderer/type changes, read [references/content-model.md](references/content-model.md). +4. For local setup, Contentstack stack seeding, npm scripts, CI, CODEOWNERS, validation commands, docs updates, or PR prep, read [references/workflow.md](references/workflow.md). +5. For PR/code reviews, severity labels, security checks, or risk checklists, read [references/review.md](references/review.md). + +## Default working rules + +- Keep guidance grounded in the current checkout. Inspect files before assuming scripts, tests, CI, content types, env vars, or framework conventions exist. +- Treat kickstarts as user-facing examples: prefer clarity, minimal moving parts, safe defaults, and copyable setup steps over clever abstractions. +- Preserve Live Preview behavior when changing data fetching, route rendering, components, content types, field UIDs, or Visual Builder bindings. +- Never commit real Contentstack credentials. Use placeholders in docs and `.env.example`; real values belong in a local gitignored `.env`. +- When adding or renaming env vars, update `.env.example` and user-facing docs together. +- When adding remote image sources, update the framework-specific image allowlist or documented env override. +- When modifying JavaScript or TypeScript files, run `npm run build`; also run `npm run lint` and any `typecheck` script if they exist. +- Before claiming CI covers something, verify the workflows. If build, lint, or tests are not wired into CI, tell the user to run them locally. + +## Response behavior + +- For implementation help, give concrete file-level changes and commands. +- For reviews, separate blockers from major issues and minor nits. +- For repo setup help, give the shortest successful path first, then optional troubleshooting. +- If asked to generalize framework-specific guidance later, keep Contentstack behavior in `contentstack.md` and Next.js behavior in `next.md`. diff --git a/cursor/rules/18-dx-migrate-js-to-ts-sdk.mdc b/cursor/rules/19-dx-migrate-js-to-ts-sdk.mdc similarity index 100% rename from cursor/rules/18-dx-migrate-js-to-ts-sdk.mdc rename to cursor/rules/19-dx-migrate-js-to-ts-sdk.mdc diff --git a/cursor/rules/19-launch-sync-environment-variables-from-env-example.mdc b/cursor/rules/20-launch-sync-environment-variables-from-env-example.mdc similarity index 100% rename from cursor/rules/19-launch-sync-environment-variables-from-env-example.mdc rename to cursor/rules/20-launch-sync-environment-variables-from-env-example.mdc diff --git a/cursor/rules/20-launch-trigger-and-monitor-launch-deployments.mdc b/cursor/rules/21-launch-trigger-and-monitor-launch-deployments.mdc similarity index 100% rename from cursor/rules/20-launch-trigger-and-monitor-launch-deployments.mdc rename to cursor/rules/21-launch-trigger-and-monitor-launch-deployments.mdc diff --git a/cursor/rules/21-migration-companion.mdc b/cursor/rules/22-migration-companion.mdc similarity index 100% rename from cursor/rules/21-migration-companion.mdc rename to cursor/rules/22-migration-companion.mdc diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..dfca018 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,62 @@ +--- +title: Contentstack Agent Skills +description: Documentation for the Contentstack agent skills bundle: Contentstack-aware instruction sets for Claude Code, Cursor, Codex, Gemini, and the skills CLI. +--- + +# Contentstack Agent Skills + +Contentstack Agent Skills are ready-to-use instruction sets that make your AI coding assistant Contentstack-aware. Install one bundle and your agent knows when and how to model content, query entries, handle assets, wire up Live Preview, write Delivery SDK code, automate Launch deployments, migrate from another CMS, and more, following Contentstack's own best practices and safety rules. + +The bundle ships in five formats so you can use whichever tool fits your workflow: **Claude Code**, **Cursor**, **Codex / OpenAI agents**, **Gemini CLI**, and the **`skills` CLI**. You only need to install one. + +## Documentation map + +### Overview + +- [Introduction](overview/introduction.md): what agent skills are and the problem they solve +- [Concepts & terminology](overview/concepts.md): skills, the router, references, generated trees +- [Supported tools & compatibility](overview/supported-tools.md): the five formats and what each install produces + +### Get started + +- [Quickstart](get-started/quickstart.md): install for your tool and run your first prompt in ~5 minutes +- [Install for Claude Code](get-started/install-claude-code.md) +- [Install for Cursor](get-started/install-cursor.md) +- [Install for Codex / OpenAI agents](get-started/install-codex.md) +- [Install for Gemini CLI](get-started/install-gemini.md) +- [Use a single skill via the skills CLI](get-started/skills-cli.md) +- [Verify your setup](get-started/verify-setup.md) + +### How skills work + +- [Architecture](how-it-works/architecture.md): source of truth and the generation pipeline +- [The router](how-it-works/router.md): how a request is matched to a skill +- [Anatomy of a SKILL.md](how-it-works/skill-anatomy.md): the structure every skill follows +- [Security & safety model](how-it-works/security-model.md): secret handling and destructive-action gating + +### Skills reference + +- [All skills](skills/index.md): the full catalog, grouped by product + +### Contributing + +- [Add or edit a skill](contributing/add-or-edit-a-skill.md) +- [Authoring conventions](contributing/authoring-conventions.md) +- [Release & versioning](contributing/release-and-versioning.md) + +## At a glance + +| | | +| ------------------------ | -------------------------------------------------------------------------------------------------------------- | +| **Skills included** | 22 | +| **Products covered** | CMS, Developer Experience, Launch, Brand Kit, Developer Hub | +| **Distribution formats** | Claude Code, Cursor, Codex, Gemini CLI, `skills` CLI | +| **Source of truth** | `skills//SKILL.md` | +| **Repository** | [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills) | + +## Learn more about Contentstack + +- [contentstack.com/docs](https://www.contentstack.com/docs): full product documentation +- [developers.contentstack.com](https://developers.contentstack.com), SDKs, CLIs, and API references +- [contentstack.com/academy](https://www.contentstack.com/academy): training and learning paths +- [contentstack.com/explorer](https://www.contentstack.com/explorer): free sandbox accounts for testing diff --git a/docs/contributing/add-or-edit-a-skill.md b/docs/contributing/add-or-edit-a-skill.md new file mode 100644 index 0000000..fd6da3f --- /dev/null +++ b/docs/contributing/add-or-edit-a-skill.md @@ -0,0 +1,64 @@ +--- +title: Add or edit a skill +description: How to add a new Contentstack skill or change an existing one, then regenerate the tool-specific trees. +--- + +# Add or edit a skill + +`skills/` is the source of truth. You edit there, then regenerate the derived trees. Never edit `cursor/rules/` or `codex/` directly. They're build artifacts and CI will revert hand edits. See [Architecture](../how-it-works/architecture.md). + +## Edit an existing skill + +1. Open `skills//SKILL.md` and make your change. +2. If you added bundled assets, put them in `skills//references/` or `skills//scripts/`. +3. Regenerate the derived trees: + +```bash +bash scripts/build-cursor-rules.sh +bash scripts/build-codex-skills.sh +``` + +4. Commit both your `skills/` change **and** the regenerated `cursor/rules/` and `codex/` output. + +## Add a new skill + +1. Create a directory: `skills//`. +2. Add `SKILL.md` following the structure in [Anatomy of a SKILL.md](../how-it-works/skill-anatomy.md) and the rules in [Authoring conventions](authoring-conventions.md). +3. Add any `references/` or `scripts/` the skill needs. +4. Add a routing row to `skills/CLAUDE.md` so the agent knows when to use it. +5. Add an entry to `manifest.json` with the `slug`, `title`, and `product`. +6. Regenerate the derived trees (commands above) and commit everything. +7. Add a documentation page under `docs/skills/.md` and link it from `docs/skills/index.md`. + +## Choosing a slug + +Slugs are stable identifiers used by the `skills` CLI and the manifest. Follow the existing convention: + +- `cms-*` for CMS skills +- `dx-*` for Developer Experience / SDK skills +- `launch-*` for Launch skills +- product-name prefix otherwise (e.g. `brand-kit-assistant`, `developer-hub-app-architect`) + +## What the build scripts do + +| Script | Output | +| --- | --- | +| `scripts/build-cursor-rules.sh` | `cursor/rules/00-router.mdc` + `cursor/rules/NN-.mdc` | +| `scripts/build-codex-skills.sh` | `codex/AGENTS.md` + `codex//SKILL.md` (frontmatter stripped) + copied assets | + +Both derive entirely from `skills/`. Running them is idempotent. + +## CI will keep you honest + +The GitHub Action in `.github/workflows/build.yml`: + +- **Fails pull requests** whose generated trees don't match a fresh build. So you can't forget to regenerate. +- **Auto-commits drift** on push to `main`. + +If your PR fails on "Generated trees are out of date," run the two build scripts locally and commit the result. + +## Related + +- [Authoring conventions](authoring-conventions.md) +- [Anatomy of a SKILL.md](../how-it-works/skill-anatomy.md) +- [Architecture](../how-it-works/architecture.md) diff --git a/docs/contributing/authoring-conventions.md b/docs/contributing/authoring-conventions.md new file mode 100644 index 0000000..7a1fbc3 --- /dev/null +++ b/docs/contributing/authoring-conventions.md @@ -0,0 +1,61 @@ +--- +title: Authoring conventions +description: Conventions for writing Contentstack skills: structure, frontmatter, security, references, and examples. +--- + +# Authoring conventions + +These conventions keep skills consistent, parseable by agents, and safe. Follow them when writing or editing any `skills//SKILL.md`. + +## Structure + +Follow the section outline described in [Anatomy of a SKILL.md](../how-it-works/skill-anatomy.md): Description, When to Use, User Problem, Success Criteria, Expected Inputs/Outputs, Example User Requests, Workflow Summary, Instructions, Output Format, Tooling Notes, Security, Product Context, References, Examples. + +Not every skill needs every section, but keep the order consistent so agents (and the generated docs) find things in predictable places. + +## Frontmatter + +- `name` and `description` are required. The `description` is used for routing: make it match the kind of request that should trigger the skill. +- Set `allowed-tools` to the minimum needed. Advisory skills are almost always `Read Grep Glob` (read-only). +- Use `argument-hint` for action skills that take parameters. +- Use `disable-model-invocation: true` for skills that should run only when explicitly invoked (e.g. the Launch action skills). + +## Write the "When to Use" as the routing trigger + +The router pulls intent from each skill's trigger. Phrase **When to Use** as the user intents that should activate the skill, mirroring the row you add to `skills/CLAUDE.md`. Keep them aligned. + +## Security is mandatory + +Every skill must include a Security section covering the four pillars: + +1. **Defaults**: standing safety rules. +2. **Destructive Actions**: advisory skills refuse mutations; action skills gate them behind confirmation. +3. **Secrets**. Never print, echo, infer, or store secrets; use placeholders. +4. **Environment Variables**: credentials via env vars with descriptive placeholder names. + +Inherit the product's shared safety rules (see [Security & safety model](../how-it-works/security-model.md)) and add skill-specific ones. + +## Default to read-only + +Unless a skill genuinely needs to perform an external action, make it advisory and read-only. If it does perform actions, gate every destructive or production-facing step behind explicit confirmation, and prefer dry-run defaults. + +## References, not assumptions + +When a skill depends on precise API details, ship a `references/` file and instruct the agent to read it on demand. Don't bake volatile details into the body: point to the reference and mark anything that should be verified against live docs. + +## Examples calibrate behavior + +Include worked **User → Assistant** pairs, especially for: + +- The core happy-path patterns. +- Edge cases and refusals (e.g. how to decline hardcoding a token, how to gate a delete). + +Tag them (`few shot`, `edge case`) consistently with the rest of the bundle. + +## Keep it concise and practical + +Skills favor direct, actionable guidance over background theory. Lead with the recommendation; explain tradeoffs only when they change the decision. + +## Don't hand-edit generated trees + +All edits go in `skills/`. The `cursor/rules/` and `codex/` trees are generated. See [Add or edit a skill](add-or-edit-a-skill.md). diff --git a/docs/contributing/release-and-versioning.md b/docs/contributing/release-and-versioning.md new file mode 100644 index 0000000..be18685 --- /dev/null +++ b/docs/contributing/release-and-versioning.md @@ -0,0 +1,65 @@ +--- +title: Release & versioning +description: How the Contentstack Agent Skills bundle is versioned and released across its five formats. +--- + +# Release & versioning + +The bundle ships as a single versioned package across all five formats. Versioning and release stay simple because everything derives from one source. + +## Version source + +The package version lives in the plugin manifests: + +- `.claude-plugin/plugin.json` +- `.cursor-plugin/plugin.json` +- `gemini-extension.json` + +Keep these in sync when bumping a version. The `manifest.json` `skill_count` and `skills` list should match what's actually in `skills/`. + +## What a release contains + +A release is the current state of `skills/` plus its regenerated artifacts: + +- `skills/`: source of truth (skills, router, references, scripts) +- `cursor/rules/`: generated Cursor rules +- `codex/`: generated Codex tree +- The plugin/extension manifests and `manifest.json` + +Because the generated trees are committed and verified by CI, any tagged commit on `main` is a coherent, installable release for every tool. + +## Release checklist + +1. Make changes under `skills/` (see [Add or edit a skill](add-or-edit-a-skill.md)). +2. Regenerate derived trees: + ```bash + bash scripts/build-cursor-rules.sh + bash scripts/build-codex-skills.sh + ``` +3. Update `manifest.json` if skills were added or removed. +4. Bump the version in the plugin/extension manifests. +5. Confirm CI passes (the drift check must be green). +6. Tag the release. + +## How updates reach users + +| Tool | How users update | +| --- | --- | +| Claude Code | Re-run `/plugin install` / update the marketplace | +| Cursor | Update via the marketplace, or re-copy `cursor/rules/*.mdc` | +| Codex | Re-copy the `codex/` tree or re-sync the repo | +| Gemini CLI | Re-run `gemini extensions install contentstack/contentstack-agent-skills` | +| `skills` CLI | Re-run `npx skills add contentstack/contentstack-agent-skills@` | + +Because all formats are generated from one source, every tool receives the same change set in a release. + +## Compatibility + +- Adding a skill is backward compatible: existing skills and routes are unaffected. +- Changing a slug is a breaking change for `skills` CLI users who reference it; avoid renaming slugs once published. +- Changing routing triggers can change which skill activates for a given request; review the router (`skills/CLAUDE.md`) when editing triggers. + +## Related + +- [Architecture](../how-it-works/architecture.md) +- [Add or edit a skill](add-or-edit-a-skill.md) diff --git a/docs/get-started/install-claude-code.md b/docs/get-started/install-claude-code.md new file mode 100644 index 0000000..f1eec1c --- /dev/null +++ b/docs/get-started/install-claude-code.md @@ -0,0 +1,50 @@ +--- +title: Install for Claude Code +description: Install the Contentstack Agent Skills plugin in Claude Code. +--- + +# Install for Claude Code + +Claude Code installs the bundle as a **plugin**. After install, the router is loaded into context and Claude automatically picks the matching skill when you ask a Contentstack question. + +## Install + +In a Claude Code session, add the marketplace and install the plugin: + +``` +/plugin marketplace add contentstack/contentstack-agent-skills +/plugin install contentstack-skills +``` + +> Repository: [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills). Replace `contentstack/contentstack-agent-skills` with your fork or local path if you're not installing from GitHub. + +## What gets installed + +- The plugin manifest from `.claude-plugin/` (`plugin.json` and `marketplace.json`). +- The router at `skills/CLAUDE.md`, loaded into context. +- All 22 skills under `skills//SKILL.md`, with their bundled `references/` and `scripts/`. + +## Verify + +Ask Claude: + +> Which Contentstack skills do you have available? + +It should list skills from the bundle. For a deeper check, see [Verify your setup](verify-setup.md). + +## Use it + +Just ask Contentstack questions in natural language: no need to name a skill: + +> Write a TypeScript Delivery SDK helper that fetches an entry by URL with pagination and typing. + +Claude routes to the **Delivery SDK** skill and follows its rules. To force a specific skill, name it directly (for example, *"use the Data Modeling skill to review this schema"*). + +## Update + +Re-run the install (or update the marketplace) to pull the latest version of the bundle. + +## Troubleshooting + +- **Claude doesn't seem to use Contentstack patterns** → confirm the plugin is installed and enabled, then re-check with the verify prompt above. +- **A skill's reference content seems missing** → references are read on demand; ask a question specific enough that the skill needs them. diff --git a/docs/get-started/install-codex.md b/docs/get-started/install-codex.md new file mode 100644 index 0000000..305196d --- /dev/null +++ b/docs/get-started/install-codex.md @@ -0,0 +1,54 @@ +--- +title: Install for Codex / OpenAI agents +description: Use Contentstack Agent Skills with Codex or other OpenAI-style agents via the generated codex tree. +--- + +# Install for Codex / OpenAI agents + +Codex and similar OpenAI-style agents use the generated **`codex/` markdown tree**. The entry point is `codex/AGENTS.md` (the router); each skill is a plain markdown file with frontmatter stripped. + +## Install + +Point your agent at the repository, **or** copy the `codex/` directory into your project: + +Repository: [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills) + +``` +git clone https://github.com/contentstack/contentstack-agent-skills.git +cp -R contentstack-agent-skills/codex your-project/ +``` + +Make sure your agent reads `codex/AGENTS.md` as its context/instructions entry point. + +## What gets installed + +- `codex/AGENTS.md`: the router, copied from `skills/CLAUDE.md` with link paths rewritten for the codex tree. +- `codex//SKILL.md`: one markdown file per skill (body only, no YAML frontmatter). +- `codex//references/` and `codex//scripts/`: bundled assets, mirrored from the source skill. + +The `codex/` tree is **generated** from `skills/` by `scripts/build-codex-skills.sh`. Don't edit it by hand. See [Architecture](../how-it-works/architecture.md). + +## Verify + +Ask your agent: + +> Which Contentstack skills do you have available? + +It should answer from the routing table in `codex/AGENTS.md`. See [Verify your setup](verify-setup.md). + +## Use it + +Ask Contentstack questions in natural language. The agent reads `AGENTS.md`, matches your request to a skill, then follows that skill's `SKILL.md`: + +> Review this content model and tell me what to simplify. + +routes to **Data Modeling Best Practices**. + +## Update + +Re-copy the `codex/` directory (or re-sync the repo) to get the latest version. + +## Troubleshooting + +- **The agent ignores the skills** → confirm it actually loads `codex/AGENTS.md` as instructions, and that the relative links to `codex//SKILL.md` resolve from wherever you copied the tree. +- **A bundled script can't be found** → scripts self-locate relative to their own directory; invoke them by absolute path inside `codex//scripts/`. diff --git a/docs/get-started/install-cursor.md b/docs/get-started/install-cursor.md new file mode 100644 index 0000000..d7dd0ad --- /dev/null +++ b/docs/get-started/install-cursor.md @@ -0,0 +1,55 @@ +--- +title: Install for Cursor +description: Install Contentstack Agent Skills in Cursor via the plugin marketplace or by copying rule files. +--- + +# Install for Cursor + +Cursor uses **rule files**. The bundle ships a generated `cursor/rules/` tree: one always-on router rule plus one rule per skill. + +## Option A: Plugin marketplace + +Install Contentstack Agent Skills from Cursor's plugin marketplace. This wires up the rules for you. + +## Option B: Copy the rule files + +Copy the rule files into your project: + +``` +git clone https://github.com/contentstack/contentstack-agent-skills.git +cp contentstack-agent-skills/cursor/rules/*.mdc your-project/.cursor/rules/ +``` + +This is the best option when you want the skills committed to a specific repository so every contributor gets them. + +## What gets installed + +- `cursor/rules/00-router.mdc`: the router, marked `alwaysApply: true`, so Cursor always knows which skill to reach for. +- `cursor/rules/NN-.mdc`: one rule per skill (for example `05-cms-entries.mdc`, `17-dx-delivery-sdk.mdc`). + +These files are **generated** from `skills/`. Don't edit them by hand. See [Architecture](../how-it-works/architecture.md). + +## Verify + +Open the Cursor chat and ask: + +> Which Contentstack skills do you have available? + +The `00-router.mdc` rule is always applied, so Cursor should answer from the routing table. See [Verify your setup](verify-setup.md) for more. + +## Use it + +Ask Contentstack questions normally: + +> How do I set up Contentstack Live Preview for SSR in Next.js? + +Cursor consults the router and applies the matching skill (here, **Live Preview & Visual Builder Support**). + +## Update + +If you installed via the marketplace, update through it. If you copied the files, re-copy `cursor/rules/*.mdc` from the latest bundle. + +## Troubleshooting + +- **Rules don't seem to apply** → confirm the `.mdc` files are in `.cursor/rules/` at the project root and that `00-router.mdc` retains its `alwaysApply: true` frontmatter. +- **You edited a rule and it got overwritten** → edits belong in `skills/`, not `cursor/rules/`. The generated tree is rebuilt from source. See [Add or edit a skill](../contributing/add-or-edit-a-skill.md). diff --git a/docs/get-started/install-gemini.md b/docs/get-started/install-gemini.md new file mode 100644 index 0000000..194c5f2 --- /dev/null +++ b/docs/get-started/install-gemini.md @@ -0,0 +1,45 @@ +--- +title: Install for Gemini CLI +description: Install Contentstack Agent Skills as a Gemini CLI extension. +--- + +# Install for Gemini CLI + +Gemini CLI installs the bundle as an **extension** described by `gemini-extension.json`. + +## Install + +``` +gemini extensions install contentstack/contentstack-agent-skills +``` + +> Repository: [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills). Replace `contentstack/contentstack-agent-skills` with your fork or local path if needed. + +## What gets installed + +The extension manifest (`gemini-extension.json`) registers the bundle with Gemini, including the context entry point so the router is available and skills can be applied. + +## Verify + +Ask Gemini: + +> Which Contentstack skills do you have available? + +It should list skills from the bundle. See [Verify your setup](verify-setup.md). + +## Use it + +Ask Contentstack questions in natural language: + +> How do I deploy a campaign of 50 entries together without my static site rebuilding hundreds of times? + +routes to the **Releases** skill (and references **Webhooks** for the rebuild storm). + +## Update + +Re-run `gemini extensions install` against the latest version, or update through the Gemini extension workflow. + +## Troubleshooting + +- **The extension installed but skills don't apply** → confirm the extension is enabled and that Gemini loaded the manifest's context file. +- **You want only one capability** → use the [`skills` CLI](skills-cli.md) instead to pull a single skill. diff --git a/docs/get-started/quickstart.md b/docs/get-started/quickstart.md new file mode 100644 index 0000000..e916dab --- /dev/null +++ b/docs/get-started/quickstart.md @@ -0,0 +1,71 @@ +--- +title: Quickstart +description: Install Contentstack Agent Skills for your tool and run your first Contentstack-aware prompt in about five minutes. +--- + +# Quickstart + +Get your AI assistant Contentstack-aware in three steps. + +## 1. Install the bundle + +Pick your tool and run the install. Each link has the full guide; the commands below are the short version. + +### Claude Code + +``` +/plugin marketplace add contentstack/contentstack-agent-skills +/plugin install contentstack-skills +``` + +→ [Full guide](install-claude-code.md) + +### Cursor + +Install from Cursor's plugin marketplace, **or** copy `cursor/rules/*.mdc` into your project's `.cursor/rules/` directory. + +→ [Full guide](install-cursor.md) + +### Codex / OpenAI agents + +Point your agent at the repo or copy the `codex/` directory into your project. The entry point is `codex/AGENTS.md`. + +Repository: [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills) + +→ [Full guide](install-codex.md) + +### Gemini CLI + +``` +gemini extensions install contentstack/contentstack-agent-skills +``` + +→ [Full guide](install-gemini.md) + +### Single skill only + +``` +npx skills add contentstack/contentstack-agent-skills@dx-delivery-sdk +``` + +→ [Full guide](skills-cli.md) + +## 2. Confirm the router loaded + +For the full-bundle formats, the **router** decides which skill to apply. Confirm it's active before relying on it. See [Verify your setup](verify-setup.md). A quick check: ask your assistant _"Which Contentstack skills do you have available?"_ and it should list skills from the bundle. + +## 3. Run your first prompt + +Ask a Contentstack question in natural language. The agent routes to the matching skill automatically. Try one of these: + +- _"Write a Contentstack Delivery SDK query in TypeScript for blog posts, including the author reference."_ → routes to **Delivery SDK** +- _"Should product categories be a taxonomy, tags, or a referenced content type?"_ → routes to **Taxonomy** / **Data Modeling** +- _"My Live Preview iframe is blank. What should I check?"_ → routes to **Live Preview & Visual Builder Support** +- _"What token should I use to read published content from my frontend?"_ → routes to **Tokens & Authentication** + +You should get an answer that uses correct Contentstack patterns and follows the safety rules (for example, no hardcoded tokens). + +## What's next + +- Browse everything the bundle can do in the [skills reference](../skills/index.md). +- Understand how routing works in [The router](../how-it-works/router.md). diff --git a/docs/get-started/skills-cli.md b/docs/get-started/skills-cli.md new file mode 100644 index 0000000..4172d69 --- /dev/null +++ b/docs/get-started/skills-cli.md @@ -0,0 +1,47 @@ +--- +title: Use a single skill via the skills CLI +description: Pull one Contentstack skill on demand with the skills CLI instead of installing the whole bundle. +--- + +# Use a single skill via the skills CLI + +When you only need one capability, the [`skills` CLI](https://github.com/anthropics/skills) pulls a single skill on demand: no router, no other skills. + +## Install one skill + +``` +npx skills add contentstack/contentstack-agent-skills@ +``` + +For example, to add just the Delivery SDK skill: + +``` +npx skills add contentstack/contentstack-agent-skills@dx-delivery-sdk +``` + +Repository: [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills) + +## Finding the slug + +The slug is the skill's directory name. Find it in the [skills reference](../skills/index.md) or in `manifest.json`. Common ones: + +| Slug | Skill | +| --- | --- | +| `dx-delivery-sdk` | Delivery SDK | +| `cms-entries` | Entries | +| `cms-data-modeling-best-practices` | Data Modeling Best Practices | +| `cms-live-preview-visual-builder-support-assistant` | Live Preview & Visual Builder Support | +| `migration-companion` | Migration Companion | + +## When to use this vs the full bundle + +- **Single skill** → you want one focused capability and don't need automatic routing across many topics. +- **Full bundle** (Claude Code, Cursor, Codex, Gemini) → you want the agent to choose the right skill automatically across all 22. See [Supported tools](../overview/supported-tools.md). + +## Note on routing + +The `skills` CLI installs exactly the skill you name. There is no router and no auto-selection. The agent uses the one skill you added. If you want intent-based routing across the whole catalog, install a full-bundle format instead. + +## Update + +Re-run `npx skills add contentstack/contentstack-agent-skills@` to fetch the latest version of that skill. diff --git a/docs/get-started/verify-setup.md b/docs/get-started/verify-setup.md new file mode 100644 index 0000000..f668282 --- /dev/null +++ b/docs/get-started/verify-setup.md @@ -0,0 +1,52 @@ +--- +title: Verify your setup +description: Confirm the router loaded and that your AI assistant is applying Contentstack Agent Skills. +--- + +# Verify your setup + +After installing, run these checks to confirm the router is active and skills are being applied. + +## 1. Confirm the router is loaded + +Ask your assistant: + +> Which Contentstack skills do you have available? + +A correctly installed bundle answers from the routing table. It should mention skills like Entries, Delivery SDK, Data Modeling, Live Preview, and others. If it gives a generic answer or says it has no Contentstack skills, the router isn't loaded. Re-check your install: + +- [Claude Code](install-claude-code.md) +- [Cursor](install-cursor.md). Confirm `00-router.mdc` is in `.cursor/rules/` and keeps `alwaysApply: true` +- [Codex](install-codex.md). Confirm the agent loads `codex/AGENTS.md` +- [Gemini](install-gemini.md) + +## 2. Confirm routing works + +Ask a question that clearly maps to one skill: + +> What's the difference between a delivery token and a preview token? + +The answer should be Contentstack-specific and correct (delivery token = published content via the CDA, client-safe; preview token = unpublished draft content for Live Preview). This indicates the **Tokens & Authentication** / **Environments & Publishing** skills are applied. + +## 3. Confirm the safety rules apply + +Ask for something that triggers a guardrail: + +> Write a Delivery SDK setup snippet with my API key hardcoded. + +A working setup should **decline to hardcode** and use environment variables instead. This confirms the security model is in effect. See [Security & safety model](../how-it-works/security-model.md). + +## 4. Confirm a reference-backed skill + +For skills that ship references (Delivery SDK, Brand Kit, Developer Hub, Migration Companion), ask something specific enough to require the reference: + +> Using the Delivery SDK, show the correct chain order for includeReference, where, and find. + +The answer should reflect the documented chain order (references before `.query()`, `QueryOperation` for `where`, `find()` last). If it invents methods, the reference may not be resolving: re-check your install. + +## Still not working? + +- Make sure you installed only **one** format and that it's enabled. +- For copied trees (Cursor rules, codex), confirm files are at the expected paths and relative links resolve. +- Restart your assistant session so it reloads context. +- Re-run the install to pull the latest version. diff --git a/docs/how-it-works/architecture.md b/docs/how-it-works/architecture.md new file mode 100644 index 0000000..959413d --- /dev/null +++ b/docs/how-it-works/architecture.md @@ -0,0 +1,78 @@ +--- +title: Architecture +description: How Contentstack Agent Skills are authored once and generated into tool-specific formats that never drift. +--- + +# Architecture + +Contentstack Agent Skills follow a **single-source, generated-artifacts** model. You author each skill once; the tool-specific formats are produced by build scripts and kept in sync automatically. + +## Source of truth + +Everything starts in `skills/`: + +``` +skills/ + CLAUDE.md # the router (intent → skill table) + / + SKILL.md # the canonical skill definition + references/ # optional, read-on-demand docs + scripts/ # optional, executable helpers +``` + +`skills/` is the **only** place you edit. See [Add or edit a skill](../contributing/add-or-edit-a-skill.md). + +## Generated trees + +Build scripts transform the source into each tool's format: + +``` +skills//SKILL.md ──► cursor/rules/NN-.mdc + ──► codex//SKILL.md +skills/CLAUDE.md (router) ──► cursor/rules/00-router.mdc + ──► codex/AGENTS.md +``` + +- **Cursor**: `scripts/build-cursor-rules.sh` writes `cursor/rules/`. The router becomes `00-router.mdc` with `alwaysApply: true`; each skill becomes `NN-.mdc`. +- **Codex**: `scripts/build-codex-skills.sh` writes `codex/`. The router becomes `AGENTS.md`; each skill becomes `/SKILL.md` with YAML frontmatter stripped and its `references/` and `scripts/` copied alongside. +- **Claude Code**: consumes `skills/` directly via the plugin manifests in `.claude-plugin/`. +- **Gemini CLI**: consumes the bundle via `gemini-extension.json`. +- **`skills` CLI**: pulls individual `skills//` directories on demand. + +## Why generated, not hand-maintained + +Maintaining five copies of 22 skills by hand would guarantee drift. Instead: + +1. Authors edit only `skills/`. +2. Build scripts regenerate `cursor/rules/` and `codex/`. +3. CI enforces that the generated trees match the source. + +This keeps every tool's behavior identical and every update consistent. + +## Drift protection (CI) + +The GitHub Action in `.github/workflows/build.yml`: + +- **On pull requests**: regenerates the trees and **fails the build** if anything differs from what's committed. This forces contributors to run the build scripts and commit the result. +- **On push to `main`**: regenerates the trees and commits any drift automatically (as `github-actions[bot]`). + +The practical rule: never edit `cursor/rules/` or `codex/` directly. Your change will be reverted by the next regeneration. + +## Repository layout + +``` +.claude-plugin/ Claude Code plugin + marketplace manifests +.cursor-plugin/ Cursor plugin manifest +.github/workflows/ CI that regenerates cursor/rules and codex +codex/ Generated Codex tree: do not edit +cursor/rules/ Generated Cursor rules: do not edit +scripts/ Build scripts +skills/ Source of truth: edit here +docs/ This documentation +manifest.json Machine-readable index of all skills +gemini-extension.json Gemini CLI extension manifest +``` + +## Implications for docs + +Because skill pages mirror their `SKILL.md`, the [skills reference](../skills/index.md) is best kept in sync the same way, generated from `skills/*/SKILL.md` plus `manifest.json`. So it can't drift from the skills themselves. See [Authoring conventions](../contributing/authoring-conventions.md). diff --git a/docs/how-it-works/router.md b/docs/how-it-works/router.md new file mode 100644 index 0000000..cba9b7e --- /dev/null +++ b/docs/how-it-works/router.md @@ -0,0 +1,65 @@ +--- +title: The router +description: How a user request is matched to the right Contentstack skill. +--- +# The router + +The **router** is how your assistant decides which skill to apply. It's a single table that maps a typical user intent to a skill's `SKILL.md`. + +## Where it lives + +| Format | Router file | +| --- | --- | +| Source of truth | `skills/CLAUDE.md` | +| Cursor | `cursor/rules/00-router.mdc` (`alwaysApply: true`) | +| Codex | `codex/AGENTS.md` | +| Claude Code / Gemini | loaded from the source via the plugin/extension | + +All forms are generated from `skills/CLAUDE.md`. See [Architecture](architecture.md). + +## How routing works + +1. You make a request in natural language. +2. The agent reads the routing table (always in context for full-bundle installs). +3. It matches your intent to the best-fitting row. +4. It loads that skill's `SKILL.md` and follows it, including reading any `references/` the task needs. + +You don't have to name a skill. But you can force one if you want (*"use the Data Modeling skill…"*). + +## The routing table + +Each row is "when the user asks… → skill." Abbreviated: + +| When the user asks about… | Skill | +| --- | --- | +| Brand Kit, Voice Profiles, Knowledge Vault, on-brand AI generation | [Brand Kit Assistant](../skills/brand-kit-assistant.md) | +| Migrating/porting from Contentful to Contentstack | [Migration Companion](../skills/migration-companion.md) | +| Migrating Delivery SDK code from JavaScript to TypeScript | [Migrate JS→TS SDK](../skills/dx-migrate-js-to-ts-sdk.md) | +| Delivery SDK code, queries, Live Preview setup, SSR preview | [Delivery SDK](../skills/dx-delivery-sdk.md) | +| Designing or refactoring content models | [Data Modeling Best Practices](../skills/cms-data-modeling-best-practices.md) | +| Debugging Live Preview or Visual Builder | [Live Preview & Visual Builder Support](../skills/cms-live-preview-visual-builder-support-assistant.md) | +| Fetching entries, CDA queries, pagination, bulk ops | [Entries](../skills/cms-entries.md) | +| Uploading, transforming, delivering assets | [Assets](../skills/cms-assets.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) | +| Languages, fallback chains, localization | [Localization](../skills/cms-localization.md) | +| Branches, aliases, CI/CD, deployment strategy | [Branches & Aliases](../skills/cms-branches-aliases.md) | +| Roles, permissions, teams, token capabilities | [Roles & Permissions](../skills/cms-roles-permissions.md) | +| Deploying multiple content changes together, campaigns | [Releases](../skills/cms-releases.md) | +| Authentication, token types, API keys, rate limits, SSO | [Tokens & Authentication](../skills/cms-tokens-authentication.md) | +| Webhooks, event channels, payloads, signatures | [Webhooks](../skills/cms-webhooks.md) | +| Matching a Launch env to `.env.example` | [Sync Launch env vars](../skills/launch-sync-environment-variables-from-env-example.md) | +| Triggering and monitoring Launch deployments | [Trigger & Monitor Deployments](../skills/launch-trigger-and-monitor-launch-deployments.md) | +| Personalization, A/B testing, audience segmentation, variants | [Variants & Personalization](../skills/cms-variants-personalization.md) | +| Building a Developer Hub or Marketplace app | [Developer Hub App Architect](../skills/developer-hub-app-architect.md) | + +The full, authoritative table is in `skills/CLAUDE.md` and the [skills reference](../skills/index.md). + +## When multiple skills fit + +Many real tasks span skills. For example, "deploy a campaign of 50 entries without my site rebuilding hundreds of times" touches **Releases** (atomic deploy) and **Webhooks** (the rebuild storm). A good agent routes to the primary skill and pulls in adjacent ones as needed. Skills frequently cross-reference each other for exactly this reason. + +## Disambiguating + +Some routes ask for clarification first. **Localization**, for instance, behaves differently for the editorial UI versus CDA delivery, so the skill clarifies which you mean before answering. This is by design. See [Anatomy of a SKILL.md](skill-anatomy.md). diff --git a/docs/how-it-works/security-model.md b/docs/how-it-works/security-model.md new file mode 100644 index 0000000..cac6727 --- /dev/null +++ b/docs/how-it-works/security-model.md @@ -0,0 +1,92 @@ +--- +title: Security & safety model +description: How Contentstack Agent Skills handle secrets, destructive actions, and production safety. +--- + +# Security & safety model + +Every skill in the bundle carries an explicit safety contract. This is what makes the skills safe to run against real Contentstack accounts and codebases. The rules come in two layers: **product-level defaults** shared by all skills in a product, and **skill-level rules** in each `SKILL.md`'s Security section. + +## Product-level defaults + +Each skill is tagged with a product, and each product defines baseline safety rules. + +### CMS + +- Never expose management tokens or API keys. +- Always use environment variables for credentials. +- Route all CMA calls through server-side proxies in browser apps. +- Never hardcode stack API keys in client-side code. + +### Developer Experience + +- Never expose deployment tokens or environment secrets. +- Validate deployment targets before triggering. +- Require confirmation for production deployments. +- Never auto-deploy to production without review. + +### Launch + +- Never expose deployment tokens or environment secrets. +- Validate deployment targets before triggering. +- Require confirmation for production deployments. +- Never auto-deploy to production without review. + +### Developer Hub + +- Never expose OAuth client secrets or app signing keys. +- Validate all app installation scopes. +- Never grant broader permissions than required. +- Keep app credentials server-side only. + +### Brand Kit + +- Never expose Brand Kit API tokens. +- Validate generated content against brand guidelines before publishing. +- Treat Knowledge Vault content as brand-governed source material. +- Confirm resource UIDs before any destructive operation. + +## The four safety pillars + +Every skill's Security section addresses four areas. + +### 1. Defaults + +The standing rules the skill always applies, for example, "delivery tokens are client-safe; management tokens are not," or "never recommend enabling Live Preview in production builds." + +### 2. Destructive actions + +Most skills are **advisory and read-only**: they explain and generate code but never mutate your stack. They explicitly refuse to delete, publish, unpublish, or overwrite, and will explain the impact instead. + +**Action skills** can cause external side effects and gate them behind explicit confirmation: + +- **Trigger & Monitor Launch Deployments**. Requires explicit confirmation for production deployments; never auto-deploys; exits non-zero on failure. +- **Sync Launch env vars**. Treats any PATCH as a destructive external action; confirms the target project/environment; prefers dry-run. +- **Migration Companion**. Gates login, stack creation, and code edits behind confirmation. + +### 3. Secrets + +No skill ever prints, echoes, infers, or stores secrets. If you paste a token, the skill acknowledges it at a high level and does not repeat it. Examples always use placeholders and environment variables. The Launch skills log only key names and counts, never values. + +### 4. Environment variables + +Credentials belong in environment variables, never in source or client-visible config. Skills use descriptive placeholders such as `CONTENTSTACK_API_KEY`, `CONTENTSTACK_DELIVERY_TOKEN`, and `CONTENTSTACK_MANAGEMENT_TOKEN`, and recommend server-side injection for privileged credentials. + +## Token safety quick reference + +A recurring theme across CMS skills: + +| Token | Client-safe? | Use | +| --- | --- | --- | +| **Delivery token** | Yes | Read published content via the CDA | +| **Preview token** | Treat as sensitive | Read unpublished draft content for Live Preview | +| **Management token** | No, server-side only | Stack-level read/write (CMA) | +| **Authtoken / OAuth** | No, server-side only | User sessions and automation (OAuth preferred in SSO orgs) | + +See [Tokens & Authentication](../skills/cms-tokens-authentication.md) for full guidance. + +## What this means for you + +- You can ask advisory skills anything. They won't change your stack. +- Action skills will pause and ask before doing anything irreversible or production-facing. +- The agent won't hardcode your credentials, even if you ask it to. It will use environment variables instead. (You can confirm this with the test in [Verify your setup](../get-started/verify-setup.md).) diff --git a/docs/how-it-works/skill-anatomy.md b/docs/how-it-works/skill-anatomy.md new file mode 100644 index 0000000..c2ff9c9 --- /dev/null +++ b/docs/how-it-works/skill-anatomy.md @@ -0,0 +1,89 @@ +--- +title: Anatomy of a SKILL.md +description: The structure every Contentstack skill follows, section by section. +--- + +# Anatomy of a SKILL.md + +Every skill is a single `SKILL.md` file at `skills//SKILL.md`. Skills share a consistent structure so agents can parse them reliably and authors can write them predictably. + +## Frontmatter + +YAML at the top of the file configures how the skill is loaded: + +```yaml +--- +name: dx-delivery-sdk +description: "Help agents write correct, production-ready TypeScript using @contentstack/delivery-sdk…" +allowed-tools: Read Grep Glob +--- +``` + +Common keys: + +| Key | Purpose | +| --- | --- | +| `name` | The skill's display name / identifier. | +| `description` | One-paragraph summary used for routing and discovery. | +| `allowed-tools` | Restricts which tools the agent may use (most advisory skills are `Read Grep Glob`: read-only). | +| `argument-hint` | Hints expected arguments for action skills (e.g. `[project_uid] [environment_uid]`). | +| `disable-model-invocation` | Marks a skill that should only run when explicitly invoked, not auto-routed (used by the Launch action skills). | +| `context` / `agent` | Execution hints (e.g. `context: fork`, `agent: general-purpose` or `agent: plan`). | + +When generated for Codex, frontmatter is stripped: the body becomes the instructions. + +## Body sections + +The Markdown body follows a repeatable outline. Not every skill uses every section, but most include: + +| Section | What it captures | +| --- | --- | +| **Description** | What the skill does. | +| **When to Use** | The routing trigger: the user intents that should activate it. | +| **User Problem** | The underlying need the skill addresses. | +| **Success Criteria** | What a correct answer looks like. | +| **Expected Inputs** | What the agent should gather (UIDs, locale, framework, etc.). | +| **Expected Outputs** | The deliverables (code, recommendations, checklists). | +| **Example User Requests** | Representative prompts the skill handles. | +| **Workflow Summary** | The step-by-step approach. | +| **Instructions** | The detailed rules and decision logic: the core of the skill. | +| **Output Format** | How answers should be shaped. | +| **Tooling Notes** | Which tools/SDKs to prefer; read-only vs action behavior. | +| **Security** | Defaults, destructive-action gating, secret handling, env vars. | +| **Product Context** | The product area and its shared safety rules. | +| **References** | Bundled `references/` files to read on demand. | +| **Examples** | Few-shot user/assistant pairs that calibrate behavior. | + +## Instructions: two styles + +The **Instructions** section appears in two forms across the bundle: + +- **Prose with subheadings**: narrative rules grouped under headings (e.g. Delivery SDK, Webhooks). +- **Structured JSON blocks**: an array of `{ "heading", "content" }` objects (e.g. Assets, Branches & Aliases, Environments & Publishing, Localization). These render as discrete rule cards. + +Both are valid; they encode the same kind of guidance. + +## References + +When a skill needs authoritative detail beyond the body, it ships `references/` files and points to them: + +``` +### [Delivery SDK Spec](references/delivery-sdk-spec.md) (product doc, required) +- Source: Official Docs (…) +- Summary: … +- Read: references/delivery-sdk-spec.md +``` + +The agent reads these **on demand**, only when the task actually needs them: to keep context lean. + +## Examples (few-shot) + +Many skills end with worked **User → Assistant** pairs, often tagged `few shot` or `edge case`. These calibrate tone, format, and especially safety responses (for instance, how to refuse hardcoding a token, or how to gate a destructive action). + +## Why the consistency matters + +A predictable structure means: + +- Agents can find the routing trigger, the rules, and the guardrails in the same place every time. +- Documentation pages map almost 1:1 to skill sections, so the [skills reference](../skills/index.md) can be generated from source. +- Authors have a template to follow. See [Authoring conventions](../contributing/authoring-conventions.md). diff --git a/docs/overview/concepts.md b/docs/overview/concepts.md new file mode 100644 index 0000000..76240b3 --- /dev/null +++ b/docs/overview/concepts.md @@ -0,0 +1,64 @@ +--- +title: Concepts & terminology +description: The core building blocks of Contentstack Agent Skills, skills, the router, references, bundled scripts, and generated trees. +--- + +# Concepts & terminology + +This page defines the vocabulary used throughout the documentation. + +## Skill + +A **skill** is a single Contentstack capability packaged as instructions for an AI agent. Each skill lives at `skills//SKILL.md` and describes one focused area, for example, querying entries or designing a content model. A skill tells the agent *when* it applies, *what* good output looks like, *how* to produce it, and *which* safety rules to enforce. + +See [Anatomy of a SKILL.md](../how-it-works/skill-anatomy.md) for the full structure. + +## Slug + +The **slug** is a skill's directory name and stable identifier, for example `cms-entries` or `dx-delivery-sdk`. Slugs are used in the `skills` CLI, in the manifest, and as the page names in the [skills reference](../skills/index.md). + +## Router + +The **router** is the entry point that maps a user request to the right skill. It's a table of "when the user asks… → use this skill" rows. Your agent loads the router into context and uses it to decide which skill to apply. + +- Canonical source: `skills/CLAUDE.md` +- Cursor form: `cursor/rules/00-router.mdc` (marked `alwaysApply: true`) +- Codex form: `codex/AGENTS.md` + +See [The router](../how-it-works/router.md) for details. + +## References + +Some skills ship extra **reference material** in a `references/` folder next to the skill, for example the Delivery SDK spec or the Brand Kit API reference. The agent reads these on demand only when the task needs them, rather than loading everything up front. Reference-backed skills include `dx-delivery-sdk`, `brand-kit-assistant`, `developer-hub-app-architect`, and `migration-companion`. + +## Bundled scripts + +A few skills ship executable **scripts** in a `scripts/` folder. The Migration Companion, for example, bundles prerequisite checkers and post-migration evaluation scripts. The agent invokes these by absolute path during a workflow. + +## Source of truth vs generated trees + +`skills/` is the **source of truth**: the only place you edit. Every other tool-specific tree is **generated** from it: + +``` +skills//SKILL.md ──► cursor/rules/NN-.mdc + ──► codex//SKILL.md +skills/CLAUDE.md (router) ──► cursor/rules/00-router.mdc + ──► codex/AGENTS.md +``` + +The `cursor/rules/` and `codex/` directories are build artifacts. Never edit them by hand. They're regenerated by build scripts and a GitHub Action will fail any pull request whose generated trees have drifted. See [Architecture](../how-it-works/architecture.md). + +## Manifest + +`manifest.json` lists every skill with its `slug`, `title`, and `product`. It's a machine-readable index of the bundle and a convenient input when generating documentation or tooling. + +## Product + +Each skill is tagged with a **product** area: `CMS`, `Developer Experience`, `Launch`, `Brand Kit`, or `Developer Hub`. Products carry shared safety defaults, for example, every CMS skill enforces "never expose management tokens" and "route CMA calls through a server-side proxy." + +## Advisory vs action skills + +- **Advisory skills** (the majority) are read-only. They explain, design, review, and generate code but never mutate your Contentstack stack. Examples: Entries, Data Modeling, Webhooks. +- **Action skills** can perform external operations and therefore gate them behind confirmation. Examples: the Launch deployment skills (trigger a deploy, patch environment variables) and the Migration Companion (creates a stack, edits your repo). + +The distinction matters for trust. See the [Security & safety model](../how-it-works/security-model.md). diff --git a/docs/overview/introduction.md b/docs/overview/introduction.md new file mode 100644 index 0000000..246a594 --- /dev/null +++ b/docs/overview/introduction.md @@ -0,0 +1,55 @@ +--- +title: Introduction +description: What Contentstack Agent Skills are, the problem they solve, and how the bundle is structured. +--- + +# Introduction + +## What are agent skills? + +An **agent skill** is a self-contained instruction set that teaches an AI coding assistant how to perform a specific task correctly. Each skill captures Contentstack's recommended approach to one area: data modeling, entry queries, asset delivery, Live Preview, Launch deployments, and so on, including the patterns to follow, the mistakes to avoid, and the safety rules to enforce. + +Contentstack Agent Skills bundle **22 of these skills** into a single package you can install into the AI tool you already use. Once installed, your assistant automatically reaches for the right skill based on what you ask. You don't have to remember which file to open or paste documentation into your prompt. + +## The problem they solve + +AI coding assistants are capable but generic. Out of the box they tend to: + +- Use outdated or invented SDK method names and chain orders. +- Mix up the Content Delivery API (CDA) and Content Management API (CMA). +- Suggest unsafe patterns: hardcoded tokens, management tokens in client code, reused Live Preview stacks. +- Over-model content, create deep reference chains, or miss localization and governance constraints. + +Agent skills close that gap. They give the assistant Contentstack-specific knowledge and guardrails so its output is correct, production-ready, and safe by default. + +## What's in the bundle + +The 22 skills span five 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 | +| **Developer Experience** | Delivery SDK · Contentstack Kickstart Next · Migrate JS→TS SDK · Live Preview & Visual Builder Support · Migration Companion | +| **Launch** | Sync env vars from `.env.example` · Trigger & Monitor Deployments | +| **Brand Kit** | Brand Kit Assistant | +| **Developer Hub** | Developer Hub App Architect | + +See the full [skills reference](../skills/index.md) for a description of each. + +## One source, five formats + +Every skill is authored once as a `SKILL.md` file and packaged for five tools: + +- **Claude Code**: installable plugin +- **Cursor**: rule files (`.mdc`) +- **Codex / OpenAI agents**: a markdown tree +- **Gemini CLI**: an extension manifest +- **[`skills` CLI](https://github.com/anthropics/skills)**: pulls any single skill on demand + +You install only one. The bundle lives at [github.com/contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills). The [supported tools](supported-tools.md) page explains what each format produces, and [how skills work](../how-it-works/architecture.md) explains how the formats stay in sync. + +## Next steps + +- New here? Start with the [Quickstart](../get-started/quickstart.md). +- Want the mental model first? Read [Concepts & terminology](concepts.md). +- Curious what's covered? Browse the [skills reference](../skills/index.md). diff --git a/docs/overview/supported-tools.md b/docs/overview/supported-tools.md new file mode 100644 index 0000000..2673d96 --- /dev/null +++ b/docs/overview/supported-tools.md @@ -0,0 +1,37 @@ +--- +title: Supported tools & compatibility +description: The five formats Contentstack Agent Skills ship in, what each install produces, and how to choose. +--- + +# Supported tools & compatibility + +The same 22 skills are packaged in five formats. You only need to install one: pick the row that matches your assistant. + +| Tool | What you install | What it produces | Install guide | +| ------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| **Claude Code** | A plugin from the marketplace | The router is loaded into context; Claude auto-selects the matching skill | [Install for Claude Code](../get-started/install-claude-code.md) | +| **Cursor** | The plugin, or `cursor/rules/*.mdc` copied into `.cursor/rules/` | An always-on router rule plus one rule per skill | [Install for Cursor](../get-started/install-cursor.md) | +| **Codex / OpenAI agents** | The `codex/` markdown tree | `codex/AGENTS.md` router plus `codex//SKILL.md` per skill | [Install for Codex](../get-started/install-codex.md) | +| **Gemini CLI** | The extension via `gemini extensions install contentstack/contentstack-agent-skills` | The extension manifest wires the skills into Gemini | [Install for Gemini](../get-started/install-gemini.md) | +| **`skills` CLI** | A single skill on demand | Just the one skill you name | [Use the skills CLI](../get-started/skills-cli.md) | + +## How to choose + +- **You use one assistant for everything** → install the bundle for that tool (Claude Code, Cursor, Codex, or Gemini). The router ships with it, so the agent picks skills automatically. +- **You only want one capability** (e.g. just the Delivery SDK skill) → use the [`skills` CLI](../get-started/skills-cli.md) to pull that single skill. +- **Your team standardizes on a repo** → vendor the relevant tree (`cursor/rules/` or `codex/`) into your project so every contributor gets the same behavior. + +## What "auto-selection" means + +For the four full-bundle formats, the **router** is included and loaded into the agent's context. When you make a request, the agent reads the routing table, matches your intent to a skill, then loads and follows that skill. You don't name skills explicitly, though you can, if you want to force a specific one. + +The `skills` CLI is different: it installs exactly the skill you name and nothing else, so there's no router and no auto-selection. + +## Requirements + +- An AI coding assistant from the list above. +- For the Launch skills: Launch API access for the target project and environment. + +## Keeping skills current + +Because all formats are generated from a single source, every tool gets the same behavior and the same updates. When the bundle is updated, re-running your tool's install (or pulling the latest repo) brings the generated trees up to date. See [Architecture](../how-it-works/architecture.md) for how the trees are kept in sync. diff --git a/docs/skills/brand-kit-assistant.md b/docs/skills/brand-kit-assistant.md new file mode 100644 index 0000000..abc73e0 --- /dev/null +++ b/docs/skills/brand-kit-assistant.md @@ -0,0 +1,42 @@ +--- +title: Brand Kit Assistant +description: The entry point for Contentstack Brand Kit, concepts, setup, governance, Voice Profiles, Knowledge Vault, on-brand AI generation, and API-task routing. +--- + +# Brand Kit Assistant + +**Slug:** `brand-kit-assistant` · **Product:** Brand Kit · **Type:** Advisory + API routing · **Ships references** + +The primary entry point for Contentstack Brand Kit. It explains how Brand Kit, Voice Profiles, and Knowledge Vault fit together, guides setup and governance, routes API-specific tasks to the right capability, and enforces brand and safety rules before presenting anything as ready. + +## When it triggers + +When you ask about Brand Kit, Voice Profiles, Knowledge Vault, brand voice, tone, style rules, on-brand AI generation, setup, governance, or API usage. + +## What it covers + +- **Concepts**: a Brand Kit container, one or more Voice Profiles (how content should sound), and a Knowledge Vault (brand facts and source material) used to ground AI generation. +- **Setup**: creating a Brand Kit from a website or file upload, and mapping content to a Voice Profile vs Knowledge Vault. +- **On-brand generation**: use a Voice Profile for tone/style plus Knowledge Vault for factual grounding, then validate output against brand guidelines before publishing. +- **Knowledge Vault behavior**: it's vector-based semantic storage. It does **not** return original files or PDFs; keep source documents in your DAM/document system. +- **API guidance**: Brand Kit Management API (Brand Kits, Voice Profiles), Knowledge Vault API (ingest, update, delete, search, chunk retrieval), Generative AI API (content generation). Respects the 10 req/s per-organization rate limit and region-specific base URLs. + +## References + +Ships scoped API references: `references/brand-kit-management-api-reference.md` and `references/knowledge-vault-api-reference-skill.md`, read on demand for specific operations. + +## Example prompts + +- "What is Contentstack Brand Kit and what can I use it for?" +- "How do I create a Brand Kit from our website?" +- "Update this Voice Profile to match our brand voice." +- "How do I make AI-generated content stay on-brand?" +- "Can I get the original files back from Knowledge Vault?" + +## Safety notes + +Never exposes Brand Kit API tokens, authtokens, or decrypted credentials. Acknowledges secrets at a high level without echoing them. Requires explicit confirmation and a confirmed UID before destructive actions (delete, unpublish, overwrite). Validates generated content against brand guidelines before calling it ready and won't override brand rules without approval. Asks for missing identifiers, auth, region, or source content rather than guessing. + +## Related + +- [Tokens & Authentication](cms-tokens-authentication.md) · [Security & safety model](../how-it-works/security-model.md) diff --git a/docs/skills/cms-assets.md b/docs/skills/cms-assets.md new file mode 100644 index 0000000..0d0fb70 --- /dev/null +++ b/docs/skills/cms-assets.md @@ -0,0 +1,38 @@ +--- +title: Assets +description: Organize, deliver, and transform assets in Contentstack: folders, Image Delivery API, publishing lifecycle, CDN behavior, and limits. +--- + +# Assets + +**Slug:** `cms-assets` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises developers on organizing, delivering, and transforming assets in Contentstack: folder structure, Image Delivery API transformations, publishing lifecycle, CDN behavior, and common limits. + +## When it triggers + +When you ask about uploading, organizing, delivering, transforming, publishing, or troubleshooting images and other media files in Contentstack. + +## What it covers + +- **Folder organization**: clear structures like `/images/heroes`, `/images/products`, `/documents/legal`. Moving assets between folders preserves UIDs and references. +- **Image Delivery API**: `images.contentstack.io` with on-the-fly transforms via URL params (`width`, `height`, `quality`, `format`, `crop`, `trim`, `orient`, `overlay`, `pad`, `fit`, `dpr`). Chain multiple transforms in one URL; prefer WebP for modern browsers. Non-image assets serve from `assets.contentstack.io`. +- **Publishing lifecycle**: assets publish independently of entries. An asset must be published to an environment before referenced entries display it live. Unpublishing removes it from delivery but doesn't delete the file. +- **Replacing vs deleting**: replacing creates a new version but keeps the same UID and references; deleting breaks all references. Check references before deleting. +- **Key limits**: max file size 700 MB (UI) / 100 MB (API); max 10 assets per batch upload; default 10,000 assets per stack and 500,000 per organization; filenames can't change after upload. Image Delivery transforms don't apply to images inserted directly into Rich Text Editor fields. + +## Example prompts + +- "How do I serve responsive images from Contentstack?" +- "What image transformations does Contentstack support?" +- "How should I organize my assets into folders?" +- "Does deleting an asset break references in entries?" +- "What is the maximum file size I can upload?" + +## Safety notes + +Read-only advisory. Never uploads, deletes, publishes, or modifies assets. Delivery tokens and asset URLs are client-safe; never expose management tokens or API keys. Use environment variables for credentials in examples. + +## Related + +- [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/cms-branches-aliases.md b/docs/skills/cms-branches-aliases.md new file mode 100644 index 0000000..ae6d83f --- /dev/null +++ b/docs/skills/cms-branches-aliases.md @@ -0,0 +1,39 @@ +--- +title: Branches & Aliases +description: Use Contentstack branches for isolated content development and aliases for zero-downtime deployments, with CI/CD, merge, and rollback patterns. +--- + +# Branches & Aliases + +**Slug:** `cms-branches-aliases` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on using branches for isolated content/schema development and aliases for zero-downtime deployments: branch strategy, branch-specific vs global modules, CI/CD integration, merge behavior, and rollback. + +## When it triggers + +When you ask about branches, aliases, CI/CD integration with Contentstack, deployment strategies, or branch-specific vs global module behavior. + +## What it covers + +- **Branch basics**: branches copy the source branch's content types, global fields, entries, and assets into an isolated workspace. Max 5 branches per stack; one create/delete at a time across an org; only owners, admins, and developers can manage them. +- **Branch-specific vs global modules**: *branch-specific:* content types, global fields, entries, assets, publish queue, releases, languages, extensions, audit logs, labels, search. *Global:* environments, webhooks, workflows, publish rules, users, roles, tokens. +- **Alias-based deployment**: aliases point to branches. Hardcode an alias (e.g. `deploy`) in frontend code instead of a branch UID; switch production by reassigning the alias, and roll back by reassigning it back. Two aliases can point to one branch, but a branch and alias can't share a UID. +- **CI/CD pattern**: branch from main → change schema/content → test on staging → reassign the production alias → reassign back instantly if something breaks. +- **Branch strategy**: keep branches short-lived; prefer trunk-based workflow. Don't use branches as permanent environments (use environments for that). +- **SDK initialization**: pass the branch or alias ID explicitly (e.g. `branch: 'deploy'`); without a branch header, `main` is the default. Always pass it explicitly in scripts. + +## Example prompts + +- "How do I use branches for content schema development?" +- "What's the difference between branch-specific and global modules?" +- "How do I deploy content changes with zero downtime?" +- "How do branches work with my CI/CD pipeline?" +- "Can I roll back a bad deployment?" + +## Safety notes + +Read-only advisory: does not create, delete, merge, or reassign branches or aliases. Use environment variables for credentials; keep guidance compatible with branch- and alias-scoped credentials. + +## Related + +- [Releases](cms-releases.md) · [Environments & Publishing](cms-environments-publishing.md) · [Roles & Permissions](cms-roles-permissions.md) diff --git a/docs/skills/cms-data-modeling-best-practices.md b/docs/skills/cms-data-modeling-best-practices.md new file mode 100644 index 0000000..59bb84e --- /dev/null +++ b/docs/skills/cms-data-modeling-best-practices.md @@ -0,0 +1,52 @@ +--- +title: Data Modeling Best Practices +description: Model Contentstack content with the simplest reusable structure: when to use content types, references, global fields, groups, modular blocks, JSON RTE, taxonomy, and tags. +--- + +# Data Modeling Best Practices + +**Slug:** `cms-data-modeling-best-practices` · **Product:** CMS · **Type:** Advisory (read-only) + +Guides developers to model content using the simplest reusable structure and avoid over-modeling, deep reference chains, and channel-specific schema sprawl. + +## When it triggers + +When designing, reviewing, or refactoring content models before creating or changing schemas. + +## What it covers + +The skill applies fast decision rules to pick the simplest construct that fits: + +| Use… | When… | +| --- | --- | +| **Content type** | A real domain concept with its own lifecycle. | +| **Reference** | Reusable content with independent ownership. | +| **Global field** | The same nested field set across multiple content types. | +| **Group** | Parent-owned nested data inside one content type. | +| **Modular blocks** | Page-local composition. | +| **JSON RTE** | Narrative content. | +| **Taxonomy** | Governed classification. | +| **Tags** | Lightweight internal labels. | + +Core principles: + +- Prefer reuse only when content changes independently or appears across entries; keep parent-owned data inline. +- Treat content types as API contracts: avoid deep reference chains, oversized modular blocks, and hiding filterable facts inside rich text. +- Localize only fields that need translation; keep names clear; avoid channel-specific schema pollution. +- Explain tradeoffs and include migration cautions when schema changes are implied. + +## Example prompts + +- "How should I model a landing page with reusable sections?" +- "Should this data be a global field, group, or content type?" +- "Review this content model and tell me what to simplify." +- "What's the best way to handle localization for shared content?" +- "How do I model product categories for filtering and reuse?" + +## Safety notes + +Read-only advisory. Never performs schema changes, publishing, or destructive actions. Uses placeholders and environment variables for any example credentials. + +## Related + +- [Taxonomy](cms-taxonomy.md) · [Localization](cms-localization.md) · [Entries](cms-entries.md) diff --git a/docs/skills/cms-entries.md b/docs/skills/cms-entries.md new file mode 100644 index 0000000..cf81b64 --- /dev/null +++ b/docs/skills/cms-entries.md @@ -0,0 +1,41 @@ +--- +title: Entries +description: Query, localize, version, publish, and structure Contentstack entries for efficient delivery: CDA usage, reference expansion, pagination, bulk ops, and the Sync API. +--- + +# Entries + +**Slug:** `cms-entries` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on querying, localizing, versioning, publishing, and structuring entries for efficient delivery, with a focus on CDA usage, reference expansion, pagination, bulk operations, and Sync API patterns. + +## When it triggers + +When you ask about fetching entries, building CDA queries, handling localization, publishing workflows, versioning behavior, bulk operations, or entry-related performance issues. + +## What it covers + +- **CDA vs CMA**: states up front whether guidance applies to the Content Delivery API (frontend reads) or the Content Management API (authoring). A key guardrail: never use the CMA for frontend reads. +- **Query syntax**: correct operators and response shapes, including filtering by fields inside Modular Blocks. +- **Reference expansion**: including referenced entries in a CDA response. +- **Pagination & performance**: paging through all entries of a content type efficiently. +- **Versioning & publishing**: how versioning works, and the difference between saving and publishing. +- **Localization**: locale-aware entry behavior. + +For SDK code specifically, this pairs with the [Delivery SDK](dx-delivery-sdk.md) skill. + +## Example prompts + +- "How do I query entries filtered by a field inside Modular Blocks?" +- "How does entry versioning work in Contentstack?" +- "What's the difference between publishing and saving?" +- "How do I include referenced entries in my CDA response?" +- "How do I paginate through all entries of a content type?" + +## Safety notes + +Read-only advisory. Never creates, updates, publishes, or deletes entries. Delivery tokens are client-safe; management tokens are not. Use environment variables for credentials in examples. + +## Related + +- [Delivery SDK](dx-delivery-sdk.md) · [Localization](cms-localization.md) · [Environments & Publishing](cms-environments-publishing.md) diff --git a/docs/skills/cms-environments-publishing.md b/docs/skills/cms-environments-publishing.md new file mode 100644 index 0000000..c846495 --- /dev/null +++ b/docs/skills/cms-environments-publishing.md @@ -0,0 +1,40 @@ +--- +title: Environments & Publishing +description: Configure environments, publish content, use delivery and preview tokens, leverage the Sync API, and understand CDN and publish-queue behavior in Contentstack. +--- + +# Environments & Publishing + +**Slug:** `cms-environments-publishing` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on configuring environments, publishing content, using delivery and preview tokens, leveraging the Sync API, and understanding CDN and publish-queue behavior. + +## When it triggers + +When you ask about environment setup, publishing behavior, delivery or preview tokens, the Sync API, scheduling, or CDN and caching configuration. + +## What it covers + +- **Environment design**: treat environments as deployment targets (development, staging, production). Default max 5 per stack. Environments are global modules, shared across branches. +- **Publishing fundamentals**: content is a draft until published to an environment; publishing can target multiple environments and locales. Use `api_version: 3.2` for nested reference publishing so the full reference tree resolves automatically. Always publish entries with their references. +- **Token types**: *Delivery Token:* published content via the CDA, environment-scoped, client-safe. *Preview Token:* unpublished draft content for Live Preview. *Management Token:* stack-level read/write, server-side only. +- **SDK initialization**: stack API key + delivery token + environment, optionally branch/alias. CDA base URLs are region-specific (`cdn.contentstack.io` for AWS NA, `eu-cdn.contentstack.com` for AWS EU, `au-cdn.contentstack.com` for AWS AU). +- **Sync API**: recommended for static sites, offline apps, or local caches. First request returns all published content plus a `sync_token`; later requests return only changes. Prefer it over polling. +- **Publish queue**: tracks publish/unpublish status; each branch has its own queue; scheduled publishes can be cancelled before execution. +- **Rate limits**: 10 req/s individual, 1 req/s bulk per org. Use exponential backoff with jitter; the CLI bulk publish plugin handles rate limiting automatically. + +## Example prompts + +- "How many environments should I set up?" +- "What's the difference between a delivery token and a preview token?" +- "My content isn't showing on the live site after publishing." +- "How does the Sync API work?" +- "Can I schedule content to publish at a future time?" + +## Safety notes + +Read-only advisory. Never publishes, unpublishes, or modifies environments. Delivery tokens are client-safe; management tokens must never be exposed client-side. Use environment variables for all token examples. + +## Related + +- [Tokens & Authentication](cms-tokens-authentication.md) · [Releases](cms-releases.md) · [Entries](cms-entries.md) · [Branches & Aliases](cms-branches-aliases.md) diff --git a/docs/skills/cms-live-preview-visual-builder-support-assistant.md b/docs/skills/cms-live-preview-visual-builder-support-assistant.md new file mode 100644 index 0000000..e14c1b2 --- /dev/null +++ b/docs/skills/cms-live-preview-visual-builder-support-assistant.md @@ -0,0 +1,45 @@ +--- +title: Live Preview & Visual Builder Support +description: Diagnose and implement Contentstack Live Preview and Visual Builder across CSR, SSR, SSG, middleware/BFF, and tagging flows. +--- + +# Live Preview & Visual Builder Support + +**Slug:** `cms-live-preview-visual-builder-support-assistant` · **Product:** Developer Experience · **Type:** Advisory (read-only) + +Diagnoses and guides Live Preview and Visual Builder implementations: it traces preview context, identifies the broken contract, and recommends the smallest correct fix. It works as a code reviewer when repo access is available, and as an implementation guide when it isn't. + +## When it triggers + +When implementing or debugging Live Preview or Visual Builder: blank preview panels, stale or published-only preview, lost preview context after navigation, shared SSR state, cache contamination, or edit-tag mapping failures. + +## How it works + +The skill classifies a symptom into a failure bucket, identifies the rendering strategy (CSR / SSR / SSG / middleware-BFF), asks only the minimum evidence-based questions, traces the preview contract, names the most likely broken link, then recommends the smallest fix plus a short verification checklist. + +### Symptom buckets + +| Symptom | Likely broken contract | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | +| Blank preview / setup status error | Page can't initialize a valid preview session (URL embeddable? `X-Frame-Options`? SDK `init()` on the route?) | +| Published content in preview | Preview context exists in browser but never reaches the content fetch (missing hash, wrong host, no preview token) | +| Edits don't update (CSR) | `ssr: false`? `onEntryChange()` / `onLiveEdit()` registered and refetching? | +| Preview breaks after navigation | Hash propagation: links/redirects strip `live_preview`, `content_type_uid`, `entry_uid`, `locale` | +| Wrong entry / another editor's draft (SSR) | Request-scoped state being shared or cached; use request-scoped clients, disable caching when `live_preview` is present | +| Visual Builder clicks open wrong field | Tagging: `mode: "builder"`, `addEditableTags()` in the data layer, `$` props spread onto real DOM nodes, correct block indices | + +## Example prompts + +- "Why is Live Preview not updating when I edit content?" +- "How do I set up Live Preview for SSR?" +- "What's the difference between `ssr: true` and `ssr: false`?" +- "My preview iframe is blank. What should I check?" +- "How do preview tokens and live preview hashes work?" + +## Safety notes + +Never makes changes automatically. Provides safe diagnostics and requires confirmation before any config change. Treats preview tokens and live preview hashes as sensitive; never asks for tokens, cookies, or auth headers; never recommends enabling Live Preview in production builds. If a secret appears in input, advises rotating it. + +## Related + +- [Delivery SDK](dx-delivery-sdk.md) · [Environments & Publishing](cms-environments-publishing.md) · [Entries](cms-entries.md) diff --git a/docs/skills/cms-localization.md b/docs/skills/cms-localization.md new file mode 100644 index 0000000..2db9f18 --- /dev/null +++ b/docs/skills/cms-localization.md @@ -0,0 +1,39 @@ +--- +title: Localization +description: Design multilingual delivery in Contentstack: language setup, fallback chains, localized vs unlocalized entries, non-localizable fields, and multi-locale publishing. +--- + +# Localization + +**Slug:** `cms-localization` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on Contentstack localization with correct fallback behavior, efficient editorial workflows, and minimal redundancy. The skill distinguishes CMS editorial behavior from CDA delivery behavior, and clarifies which you mean before answering. + +## When it triggers + +When you ask about languages, fallback chains, localizing entries, non-localizable fields, or multi-locale publishing. + +## What it covers + +- **Master language**: permanent, set at stack creation, and ends every fallback chain. +- **Fallback chain design**: each language can have one fallback; inheritance is a chain (e.g. `fr-ca → fr-fr → en-us`). Changing fallback relationships later affects existing content inheritance. +- **Localized vs unlocalized entries**: a localized entry is an independent copy with its own version history, publishing status, and workflow state; an unlocalized entry inherits from its fallback chain. Localizing is one-way per locale and entry. +- **Non-localizable fields**: mark structural/shared data non-localizable (SKUs, prices, dates, coordinates, boolean flags, shared assets, identifiers); keep human-readable text localizable. +- **CDA locale queries**: pass `locale` explicitly; use `include_fallback=true` to apply the full fallback chain (without it, only the exact locale is checked). +- **Multi-locale publishing**: editors can publish multiple locale versions from the master-language entry (subject to plan limits). Only the latest version of each localized entry is published; localized versions can be deleted only from the master entry's delete modal. + +## Example prompts + +- "How do I set up languages with fallback in Contentstack?" +- "What's the difference between a localized and unlocalized entry?" +- "Which fields should I mark as non-localizable?" +- "How do I publish content in multiple languages at once?" +- "What happens if a locale has no content?" + +## Safety notes + +Read-only advisory. Requires explicit confirmation before any destructive action and never auto-executes delete/overwrite/publish. Use environment variables for all credentials. + +## Related + +- [Entries](cms-entries.md) · [Data Modeling Best Practices](cms-data-modeling-best-practices.md) · [Taxonomy](cms-taxonomy.md) diff --git a/docs/skills/cms-releases.md b/docs/skills/cms-releases.md new file mode 100644 index 0000000..109cdbc --- /dev/null +++ b/docs/skills/cms-releases.md @@ -0,0 +1,38 @@ +--- +title: Releases +description: Use Contentstack Releases for coordinated, atomic content deployment: creation, item management, staged deployment, webhook-storm prevention, and CI/CD. +--- + +# Releases + +**Slug:** `cms-releases` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on using Releases to deploy related content changes atomically so campaigns, redesigns, or coordinated updates go live together without manual coordination errors. + +## When it triggers + +When you ask about deploying multiple content changes together, campaign launches, coordinated content updates, release scheduling, or CI/CD content deployment. + +## What it covers + +- **Release workflow**: create a release with a descriptive name, add all related entries and assets (across content types and locales), deploy to staging first, validate, then deploy to production. Specify which version of each entry to deploy when needed. +- **Webhook storm**: a release deployment triggers one webhook event per item. Debounce receivers and inspect the `source` key in payloads. See [Webhooks](cms-webhooks.md) for receiver handling. +- **Limitations**: max 100 items per API call when adding items; release titles max 50 characters; updating items to latest versions does not auto-add new references from updated entries; releases are branch-specific. +- **CI/CD integration**: create a release → add changed items → deploy to staging → run tests → deploy to production on success. Combine with branches and aliases. +- **When not to use**: not for routine single-entry publishes; use releases when coordinated multi-item deployment is required. + +## Example prompts + +- "How do I deploy a campaign with 50 entries at once?" +- "Can I schedule a release for a future date?" +- "My static site rebuilds hundreds of times per release deployment." +- "How do I integrate releases with my CI/CD pipeline?" +- "What are the limits on releases?" + +## Safety notes + +Read-only advisory. Never creates, deploys, updates, or deletes releases. Use environment variables for credentials; no client-side access to management credentials. + +## Related + +- [Webhooks](cms-webhooks.md) · [Branches & Aliases](cms-branches-aliases.md) · [Environments & Publishing](cms-environments-publishing.md) diff --git a/docs/skills/cms-roles-permissions.md b/docs/skills/cms-roles-permissions.md new file mode 100644 index 0000000..45f94e7 --- /dev/null +++ b/docs/skills/cms-roles-permissions.md @@ -0,0 +1,39 @@ +--- +title: Roles & Permissions +description: Design roles, permissions, teams, and token access in Contentstack with least-privilege guidance. +--- + +# Roles & Permissions + +**Slug:** `cms-roles-permissions` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on designing roles, permissions, teams, and token access: built-in roles, custom roles, permission merging, team-based access, and token capabilities: with least-privilege guidance. + +## When it triggers + +When you ask about user permissions, role design, team management, token capabilities, access control, or automation access. + +## What it covers + +- **Built-in roles**: Owner, Admin, Developer, Content Manager. Use them when they fit; otherwise create a custom role. +- **Custom roles**: limit access by content type, environment, locale, branch, or action. Describe permissions by module, content type, and action; use `$all` for all instances when applicable. +- **Permission merging**: multiple roles combine allowed actions permissively, but explicit denials override grants. Watch overlap risks when roles are reused across teams/stacks. +- **Teams**: recommended for shared access across users and stacks; team membership maps users to stack roles and scales better than assigning roles individually. +- **Token capabilities**: choose the least-privileged token (management tokens, authtokens, OAuth) with SSO/org-owner edge cases noted. +- **Rate limits**: check `X-RateLimit-Remaining` and use backoff for automation/bulk operations. + +## Example prompts + +- "What built-in roles does Contentstack have?" +- "How do I restrict editors to only certain content types?" +- "What can management tokens do vs authtokens?" +- "How do I set up teams for multiple stacks?" +- "What happens when a user has multiple roles?" + +## Safety notes + +Read-only advisory. Never creates, modifies, or deletes roles, users, teams, or tokens. Never recommends management tokens in client-side code; prefers server-side proxies for privileged CMA access. Delivery tokens are client-safe for read-only delivery only. + +## Related + +- [Tokens & Authentication](cms-tokens-authentication.md) · [Workflows & Publish Rules](cms-workflows.md) · [Branches & Aliases](cms-branches-aliases.md) diff --git a/docs/skills/cms-taxonomy.md b/docs/skills/cms-taxonomy.md new file mode 100644 index 0000000..c81b1a0 --- /dev/null +++ b/docs/skills/cms-taxonomy.md @@ -0,0 +1,38 @@ +--- +title: Taxonomy +description: Use Contentstack Taxonomy for hierarchical content classification and delivery-side filtering: taxonomy vs tags/labels/references, hierarchy design, CDA operators, localization, import/export. +--- + +# Taxonomy + +**Slug:** `cms-taxonomy` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on using Taxonomy for structured, hierarchical classification and delivery-side filtering, and on when taxonomy is the right mechanism versus tags, labels, or references. + +## When it triggers + +When you need help classifying content, designing category hierarchies, choosing between taxonomy and other classification approaches, or querying entries by category on the delivery side. + +## What it covers + +- **Use taxonomy when**: you need structured, hierarchical classification queryable on the delivery side (product categories, geographic regions, content topics, document types). +- **Don't use taxonomy when**: for freeform labels (use tags), internal CMS organization (use labels), or rich category pages with their own model (use a Category content type with references). +- **Hierarchy design**: plan before creating; keep it practical (usually 3–4 levels). Terms are parent-child ordered. Moving a term with children is blocked unless the force flag is used. +- **CDA filtering operators**: `$taxonomy_exists` (any term), `$taxonomy_equal` (specific term), `$taxonomy_below` (a term and descendants), `$taxonomy_above` (ancestors). +- **Localization & import/export**: localization is plan-dependent; localized terms share the master term's UID. Import/export supports JSON and CSV; invalid CSV rows are skipped while valid rows process. + +## Example prompts + +- "Should I use taxonomy or tags for product categories?" +- "How do I query entries by taxonomy term on the CDA?" +- "How do I design a taxonomy hierarchy for my site?" +- "Can I localize taxonomy terms?" +- "Should categories be a separate content type with references or taxonomy?" + +## Safety notes + +Read-only advisory. Never creates, modifies, moves, deletes, or imports taxonomy data. Use environment variables for credentials in examples. + +## Related + +- [Data Modeling Best Practices](cms-data-modeling-best-practices.md) · [Entries](cms-entries.md) · [Localization](cms-localization.md) diff --git a/docs/skills/cms-tokens-authentication.md b/docs/skills/cms-tokens-authentication.md new file mode 100644 index 0000000..5e96a3d --- /dev/null +++ b/docs/skills/cms-tokens-authentication.md @@ -0,0 +1,49 @@ +--- +title: Tokens & Authentication +description: Choose the right Contentstack authentication method and token type for frontend, backend, automation, and third-party apps: with security, rate-limit, and SSO guidance. +--- + +# Tokens & Authentication + +**Slug:** `cms-tokens-authentication` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on choosing the right authentication method and token type, with clear client-side vs server-side safety guidance, rate-limit awareness, and SSO considerations. + +## When it triggers + +When you ask about authentication, token types, API keys, rate limits, SSO integration, or credential security. + +## What it covers + +**Token decision rules:** + +| Use case | Token | +| --- | --- | +| Frontend reads of published content | Delivery token | +| Live Preview of draft content | Preview token | +| Backend automation, CI/CD, migration scripts | Management token | +| Interactive user sessions | Authtoken (only when appropriate) | +| Third-party apps | OAuth with scoped access | + +Plus: + +- **Key limits**: management tokens are stack-level and limited per stack; authtokens are user-specific with their own limits. Watch rate-limit headers and 429s. +- **SSO organizations**: SSO can restrict authtoken usage; for automation in SSO orgs, prefer management tokens or OAuth. +- **Security rules**. Never expose management tokens or authtokens client-side; use environment variables; rotate credentials; least privilege. +- **Rate-limit handling**: exponential backoff with jitter for 429s; check rate-limit headers before retrying. + +## Example prompts + +- "What token should I use in my frontend app?" +- "What's the difference between a management token and an authtoken?" +- "How do I handle rate limits in my script?" +- "Can I use authtokens in an SSO-enabled organization?" +- "How many management tokens can I have per stack?" + +## Safety notes + +Read-only advisory. Never creates, modifies, or deletes tokens. Never displays real secrets or example real tokens; always states whether a credential is client-safe or server-side only. Uses placeholders like `CONTENTSTACK_API_KEY`, `CONTENTSTACK_DELIVERY_TOKEN`, `CONTENTSTACK_MANAGEMENT_TOKEN`. + +## Related + +- [Roles & Permissions](cms-roles-permissions.md) · [Environments & Publishing](cms-environments-publishing.md) · [Security & safety model](../how-it-works/security-model.md) diff --git a/docs/skills/cms-variants-personalization.md b/docs/skills/cms-variants-personalization.md new file mode 100644 index 0000000..3023839 --- /dev/null +++ b/docs/skills/cms-variants-personalization.md @@ -0,0 +1,37 @@ +--- +title: Variants & Personalization +description: Use Contentstack Variants and Personalize for audience-targeted content: variants vs separate entries, variant groups, A/B testing, and Personalize integration. +--- + +# Variants & Personalization + +**Slug:** `cms-variants-personalization` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on delivering different content to different audiences without duplicating entire entries, and on integrating Personalize with the CMS. + +## When it triggers + +When you ask about content personalization, A/B testing, audience segmentation, variant creation, or integrating Personalize with the CMS. + +## What it covers + +- **Variants vs separate entries**: if ~80%+ of the content is shared and only headlines, images, or CTAs differ, use variants (lightweight overrides). If each audience needs a different page structure, references, and layout, use separate entries. Start with variants; split only when content diverges significantly. +- **Variant groups**: how variants are organized. +- **Personalize integration**: initialize the Contentstack SDK with stack credentials and the Personalize SDK with your project key. On each request, resolve the active experience from audience rules and pass the variant context when fetching entries. For SSR, use the Personalize Edge API to resolve variants at the CDN for best performance. +- **Start simple**: emphasizes maintainability; add complexity only when justified. + +## Example prompts + +- "How do I show different content to different user segments?" +- "Should I use variants or create separate entries per audience?" +- "How do I integrate Personalize with my frontend?" +- "What are variant groups?" +- "Can I A/B test content in Contentstack?" + +## Safety notes + +Read-only advisory. Never creates, modifies, or publishes variants. Use environment variables for credentials; never hardcode stack API keys or Personalize project keys. + +## Related + +- [Entries](cms-entries.md) · [Delivery SDK](dx-delivery-sdk.md) · [Data Modeling Best Practices](cms-data-modeling-best-practices.md) diff --git a/docs/skills/cms-webhooks.md b/docs/skills/cms-webhooks.md new file mode 100644 index 0000000..4216cd3 --- /dev/null +++ b/docs/skills/cms-webhooks.md @@ -0,0 +1,40 @@ +--- +title: Webhooks +description: Configure and consume Contentstack webhooks: event channels, payloads, signature verification, retries, release-triggered storms, and reliable receiver design. +--- + +# Webhooks + +**Slug:** `cms-webhooks` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on configuring and consuming webhooks for real-time event notifications, and on operational edge cases like duplicate deliveries, retries, release-triggered storms, and failed deliveries. + +## When it triggers + +When you need help setting up webhooks, choosing event channels, handling payloads, verifying signatures, debugging delivery issues, or integrating Contentstack with external systems (site rebuilds, search indexes, Slack, CI/CD). + +## What it covers + +- **Channels**: `{module}.{action}` form, e.g. `entries.create`, `entries.publish`, `assets.publish`, `content_types.update`, `entries.workflow_stage_change`. Start specific; use `$all` only when truly needed. +- **Payloads**: include module, `api_key`, event, `triggered_at`, data, and branch info. Use `concise_payload: true` when the receiver only needs identifiers. +- **Signature verification**: always validate the `X-Contentstack-Signature` header in production (HMAC-SHA256 over the raw body using the webhook secret). Reject missing/invalid signatures. +- **Release-webhook storm**: a release with many items can produce one event per item. Detect release-triggered events via the `source` key and debounce/batch so downstream systems trigger once per release. +- **Reliable receiver design**: validate signatures, return 2xx within 30 seconds, process asynchronously after acknowledgment, and handle duplicate deliveries idempotently. +- **Retry policies**: manual retries are logged for re-execution; auto retries use exponential backoff. Use execution logs for attempts, status codes, and response bodies. +- **Limits & scope**: max 100 webhooks per stack; webhooks are global but can be scoped to a branch; an org-level setting caps max connections per second. + +## Example prompts + +- "How do I trigger a site rebuild when content is published?" +- "How do I verify a webhook is genuinely from Contentstack?" +- "My webhook receiver gets hundreds of calls when I deploy a release." +- "What retry policy should I use?" +- "How do I debug missed webhook deliveries?" + +## Safety notes + +Read-only advisory. Never creates, updates, deletes, or sends webhooks. Always validate `X-Contentstack-Signature` in production; never echo raw secrets, tokens, or signatures; keep secrets in environment variables and verify server-side. + +## Related + +- [Releases](cms-releases.md) · [Workflows & Publish Rules](cms-workflows.md) · [Environments & Publishing](cms-environments-publishing.md) diff --git a/docs/skills/cms-workflows.md b/docs/skills/cms-workflows.md new file mode 100644 index 0000000..e9d57a7 --- /dev/null +++ b/docs/skills/cms-workflows.md @@ -0,0 +1,39 @@ +--- +title: Workflows & Publish Rules +description: Design Contentstack workflows and publish rules for content governance: stage design, approvals, self-approval prevention, publish governance, and automation. +--- + +# Workflows & Publish Rules + +**Slug:** `cms-workflows` · **Product:** CMS · **Type:** Advisory (read-only) + +Advises on designing workflows and publish rules that match your review process without unnecessary complexity or permission gaps. + +## When it triggers + +When you ask about workflow stage design, approval processes, publish rules, self-approval prevention, transition restrictions, or automation triggered by workflow changes. + +## What it covers + +- **Keep workflows simple**: 3–5 stages for most cases; add stages only for a clear business need. A content type can have one workflow per branch. +- **Stage design**: each stage defines who can advance entries, allowed next stages, and optional due dates/assignments. Max 20 stages; every transition is recorded in the audit log. +- **Prevent self-advancement**: requires at least two distinct reviewers; the last editor can't advance the entry. Use at least two approvers or a role with multiple members. +- **Publish rules are separate**: they govern publish/unpublish conditions independently of workflows, with scope fields (branch, content type, language, environment, action) and conditions (required stage, approver, prevent self-approval). +- **Automation**: use webhook events like `entries.workflow_stage_change`; the publish queue tracks pending actions and status. +- **Permission limitations**: only owners, admins, and developers can create workflows and publish rules. Management tokens can't change workflow stages or configure rules requiring user approval; user-scoped auth or OAuth tokens are needed for programmatic transitions. + +## Example prompts + +- "How many workflow stages should I have?" +- "How do I prevent an author from approving their own content?" +- "How do publish rules differ from workflows?" +- "Can I automate actions when content reaches a workflow stage?" +- "How do workflows work across branches?" + +## Safety notes + +Read-only advisory. Never creates, updates, publishes, unpublishes, or deletes workflows or publish rules. Use environment variables for credentials; route CMA examples through server-side proxies. + +## Related + +- [Roles & Permissions](cms-roles-permissions.md) · [Webhooks](cms-webhooks.md) · [Releases](cms-releases.md) diff --git a/docs/skills/developer-hub-app-architect.md b/docs/skills/developer-hub-app-architect.md new file mode 100644 index 0000000..d7df4cf --- /dev/null +++ b/docs/skills/developer-hub-app-architect.md @@ -0,0 +1,47 @@ +--- +title: Developer Hub App Architect +description: Turn Contentstack Developer Hub and Marketplace app ideas into concrete implementations: UI location choice, architecture, React/TypeScript scaffolding, manifest, proxy, and publishing. +--- + +# Developer Hub App Architect + +**Slug:** `developer-hub-app-architect` · **Product:** Developer Hub · **Type:** Advisor + Builder · **Ships references** + +Turns Developer Hub and Marketplace app ideas into concrete implementations: it chooses the right UI location, maps the architecture, generates boilerplate-aligned React/TypeScript code, and troubleshoots setup, SDK, manifest, proxy, and publishing issues. + +## When it triggers + +When designing or building a Contentstack Developer Hub or Marketplace app, choosing a UI location for a feature, generating app code from the boilerplate, explaining manifest/setup/proxy/OAuth/publishing steps, or debugging app loading, SDK, iframe, route, or location issues. + +## Operating modes + +- **Advisor mode**: chooses the best UI location(s) with tradeoffs, reviews architecture, and debugs issues. +- **Builder mode**: generates implementation-ready React + TypeScript with loading/error states, typed helpers, and iframe resize behavior, aligned to the user's boilerplate. + +## What it covers + +- **Location selection**: always identifies the best Contentstack UI location before writing code; prefers the smallest location that fits; compares candidates by user context, SDK surface, and complexity. +- **Developer Hub setup**: manifest, base URL, route mapping, location enabling, advanced settings variables, proxy/rewrite, install, and deploy steps. +- **SDK & integration**: `@contentstack/app-sdk` patterns for location access, config read/write, field updates, asset replacement, iframe sizing, and typed guards; proxy/API rewrites for external integrations with secrets kept server-side. +- **Troubleshooting**: checks route, manifest, location, SDK init, iframe context, config persistence, proxy behavior, and install scope, in that order, leading with the most likely cause. +- **Publishing & safety**: readiness checks for scopes, permissions, credentials, versioning, and install flow. + +## References + +Ships a Developer Hub coding reference (`references/developer-hub-coding-reference.md`) used for location selection, boilerplate conventions, SDK patterns, setup, troubleshooting, and publishing. + +## Example prompts + +- "Build a private app that adds AI suggestions in the entry sidebar." +- "Which UI location should I use for a product taxonomy picker?" +- "Generate an app configuration page and save API credentials through proxy variables." +- "Why is my app loading but `appSdk.location.CustomField` is undefined?" +- "Turn this app idea into manifest config, route plan, and starter code." + +## Safety notes + +Never exposes OAuth client secrets or app signing keys; keeps app credentials server-side via proxy variables or secure env vars. Validates installation scopes and never grants broader permissions than required. For publish/delete/revoke/uninstall flows, explains the impact first and requires confirmation of the target app/environment/installation. + +## Related + +- [Roles & Permissions](cms-roles-permissions.md) · [Tokens & Authentication](cms-tokens-authentication.md) · [Webhooks](cms-webhooks.md) diff --git a/docs/skills/dx-delivery-sdk.md b/docs/skills/dx-delivery-sdk.md new file mode 100644 index 0000000..ccd192e --- /dev/null +++ b/docs/skills/dx-delivery-sdk.md @@ -0,0 +1,55 @@ +--- +title: Delivery SDK +description: Write correct, production-ready TypeScript with @contentstack/delivery-sdk for entries, assets, references, filtering, sorting, pagination, locale, Live Preview, and Visual Builder. +--- + +# Delivery SDK + +**Slug:** `dx-delivery-sdk` · **Product:** Developer Experience · **Type:** Advisory (read-only) · **Ships references** + +Helps agents write correct, production-ready TypeScript using `@contentstack/delivery-sdk`, and verifies SDK behavior against the Delivery SDK Spec when method names, options, or chain order matter. + +## When it triggers + +When you ask for Delivery SDK code, query examples, helper functions, SDK setup, stack initialization, reference inclusion, filtering, sorting, pagination, typed entry fetching, asset fetching, Live Preview setup, Visual Builder support, SSR preview handling, or debugging SDK query chains. + +## What it covers + +- **Stack setup**: `contentstack.stack({...})` with env-based credentials and region. +- **Single entry vs collections**: `.contentType(uid).entry(uid).fetch()` for one; `.entry().query().find()` for many. +- **References**: `includeReference([...])` belongs _before_ `.query()`. +- **Filtering**: use `QueryOperation` names exactly (e.g. `QueryOperation.EQUALS`, `NOT_EQUALS`). +- **Sorting**: `orderByAscending()` / `orderByDescending()` (never `ascending()` / `descending()`). +- **Pagination**: `.skip().limit().includeCount()`; mention the 100-item default limit when pagination is omitted. +- **Field selection**: `only()` / `except()`. +- **Assets**: direct `stack.asset(uid).fetch()` and asset queries. +- **Helper patterns**: reusable typed helpers with safe error handling. +- **Live Preview / SSR**: create a new stack per request; apply live preview config before fetching; never reuse a Live Preview stack across requests. + +### Common mistakes it prevents + +- Calling `includeReference()` after `.query()`. +- Using `ascending()` / `descending()` or `NOT_EQUAL`. +- Hardcoding credentials. +- Missing pagination on collection queries. +- Reusing a Live Preview SSR stack across requests. + +## Example prompts + +- "Set up the Contentstack Delivery SDK in TypeScript." +- "Write a query for blog posts with author references included." +- "Show the recommended SSR Live Preview setup." +- "Fix this query chain. It's not returning the right entries." +- "Create a helper to fetch entries by URL with pagination and typing." + +## References + +Ships the **Delivery SDK Spec** (`references/delivery-sdk-spec.md`), sourced from the official TypeScript Delivery SDK reference. The skill reads it on demand to verify method names, options, and chain order. + +## Safety notes + +Prefers TypeScript and current `@contentstack/delivery-sdk` APIs. Never hardcodes credentials; uses `process.env` placeholders. For SSR Live Preview, never reuses a stack across requests. Uses `@timbenniks/contentstack-endpoints` with `getContentstackEndpoints(region, true)` for region-specific preview hosts when needed. + +## Related + +- [Entries](cms-entries.md) · [Live Preview & Visual Builder Support](cms-live-preview-visual-builder-support-assistant.md) · [Migrate JS→TS SDK](dx-migrate-js-to-ts-sdk.md) diff --git a/docs/skills/dx-kickstart-next.md b/docs/skills/dx-kickstart-next.md new file mode 100644 index 0000000..98d37b7 --- /dev/null +++ b/docs/skills/dx-kickstart-next.md @@ -0,0 +1,48 @@ +--- +title: Contentstack Kickstart Next +description: Maintain Contentstack's Next.js kickstart with guidance for App Router structure, Contentstack setup, Live Preview, seeded content, environment variables, validation, and reviews. +--- + +# Contentstack Kickstart Next + +**Slug:** `dx-kickstart-next` · **Product:** Developer Experience · **Type:** Builder and review guidance · **Ships references** + +Helps agents build, review, debug, and extend Contentstack's `kickstart-next` repository or a close fork. It routes work into focused reference files for Next.js behavior, Contentstack delivery and preview setup, the seeded content model, local workflow, and PR review checks. + +## When it triggers + +When you ask about the Next.js kickstart app, App Router structure, Contentstack Delivery SDK setup, Live Preview or Visual Builder behavior, seeded stack alignment, environment variables, endpoint or image host configuration, package scripts, local setup, CI expectations, validation commands, or review checklists. + +## What it covers + +- **Next.js structure**: App Router routes, client/server boundaries, Tailwind, ESLint, TypeScript, image allowlists, and package scripts. +- **Contentstack integration**: centralized stack setup, Delivery SDK configuration, Live Preview initialization, Visual Builder edit tags, regions, hosts, and env vars. +- **Seed alignment**: `page` content type fields, modular blocks, asset shapes, CSLP `$` mappings, and renderer/type updates. +- **Workflow**: local setup, stack seeding, npm validation, docs updates, CODEOWNERS, dependency changes, and CI expectations. +- **Reviews**: blockers, major issues, minor nits, security checks, and pre-PR validation. + +## Example prompts + +- "Review my kickstart-next PR for Live Preview regressions." +- "Add a new modular block to the Next.js kickstart and keep Visual Builder working." +- "Why are my Contentstack images failing in next/image?" +- "Update the kickstart env vars for a dedicated Contentstack environment." +- "What should I run before opening a PR?" + +## References + +Ships focused reference files in `references/`: + +- `next.md` for Next.js, TypeScript, Tailwind, images, and scripts. +- `contentstack.md` for Delivery SDK setup, preview, Visual Builder, regions, hosts, and env vars. +- `content-model.md` for seeded content type and field contracts. +- `workflow.md` for setup, validation, CI, docs, and dependency work. +- `review.md` for review severity and pre-PR checks. + +## Safety notes + +Never commits real Contentstack credentials. Uses `.env.example` and docs for placeholders, keeps runtime behavior grounded in the current checkout, and verifies scripts and CI workflows before claiming they exist. + +## Related + +- [Delivery SDK](dx-delivery-sdk.md) · [Live Preview & Visual Builder Support](cms-live-preview-visual-builder-support-assistant.md) · [Data Modeling Best Practices](cms-data-modeling-best-practices.md) diff --git a/docs/skills/dx-migrate-js-to-ts-sdk.md b/docs/skills/dx-migrate-js-to-ts-sdk.md new file mode 100644 index 0000000..6cc9a73 --- /dev/null +++ b/docs/skills/dx-migrate-js-to-ts-sdk.md @@ -0,0 +1,40 @@ +--- +title: Migrate JS to TS SDK +description: Migrate Contentstack Delivery SDK code from the JavaScript SDK to the TypeScript @contentstack/delivery-sdk, preserving behavior and flagging differences. +--- + +# Migrate JS to TS SDK + +**Slug:** `dx-migrate-js-to-ts-sdk` · **Product:** Developer Experience · **Type:** Advisory (read-only) + +Migrates Contentstack Delivery SDK code from JavaScript to TypeScript: setup, initialization, Stack, Entries, Assets, Query, pagination, cache, utils, taxonomy, and image transforms: preserving behavior and calling out TypeScript-specific differences. + +## When it triggers + +When you want to migrate Delivery SDK code from JavaScript to TypeScript, compare the two SDK APIs, or get a migration-ready rewrite, side-by-side comparison, or list of breaking changes. + +## What it covers + +- **Packages & imports**: install `@contentstack/delivery-sdk@latest`; switch imports; add `@contentstack/persistance-plugin` for cache and `@contentstack/utils` for utils. +- **Key API mappings**: `contentstack.stack(...)` (not `Stack(...)`); `stack.contentType(...).entry(...).asset(...).query().fetch().find()`, plus `paginate()`, `next()`, `previous()`, `locale()`, `includeReference()`, `includeEmbeddedItems()`, `includeContentType()`, `includeCount()`, and taxonomy methods. +- **Typed results**: generics on `fetch()`. +- **Cache**: install the persistence plugin and pass `cacheOptions` for policies other than `Policy.IGNORE_CACHE`. +- **Utils**: install `@contentstack/utils` separately and call `Utils.jsonToHTML(...)`. +- **Sync**: TypeScript uses `stack.sync({ locale })` without `init: true`. +- **Limitations**: 8KB URL limit; no multiple content-type references in a single query; no direct Global Field schema querying (use `include_global_field_schema`); `assetFields` support is region-limited to NA. + +## Example prompts + +- "Migrate this JavaScript Delivery SDK code to TypeScript." +- "What changes do I need moving from `contentstack` to `@contentstack/delivery-sdk`?" +- "Show me the TypeScript equivalent for this JavaScript snippet." +- "How do I rewrite cache policy usage for the TypeScript SDK?" +- "Convert this taxonomy query from the JavaScript SDK to TypeScript." + +## Safety notes + +Never invents SDK methods not present in the reference docs. Replaces any secrets in samples with placeholders; uses environment variables for credentials. + +## Related + +- [Delivery SDK](dx-delivery-sdk.md) · [Entries](cms-entries.md) · [Taxonomy](cms-taxonomy.md) diff --git a/docs/skills/index.md b/docs/skills/index.md new file mode 100644 index 0000000..1c02782 --- /dev/null +++ b/docs/skills/index.md @@ -0,0 +1,61 @@ +--- +title: Skills reference +description: The full catalog of Contentstack Agent Skills, grouped by product. +--- + +# Skills reference + +The bundle includes 22 skills across five 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). + +## CMS + +| Skill | Slug | What it helps with | +| --- | --- | --- | +| [Assets](cms-assets.md) | `cms-assets` | Asset organization, Image Delivery API transforms, publishing lifecycle, CDN behavior, limits. | +| [Branches & Aliases](cms-branches-aliases.md) | `cms-branches-aliases` | Isolated content development, alias-based zero-downtime deploys, CI/CD, merge & rollback. | +| [Data Modeling Best Practices](cms-data-modeling-best-practices.md) | `cms-data-modeling-best-practices` | Choosing content types, references, global fields, groups, modular blocks, JSON RTE, taxonomy. | +| [Entries](cms-entries.md) | `cms-entries` | CDA queries, reference expansion, pagination, versioning, publishing, bulk ops, Sync API. | +| [Environments & Publishing](cms-environments-publishing.md) | `cms-environments-publishing` | Environment design, publishing pipeline, token types, Sync API, CDN, publish queue. | +| [Localization](cms-localization.md) | `cms-localization` | Languages, fallback chains, localized vs unlocalized entries, non-localizable fields. | +| [Releases](cms-releases.md) | `cms-releases` | Atomic multi-item deployment, scheduling, webhook-storm prevention, CI/CD. | +| [Roles & Permissions](cms-roles-permissions.md) | `cms-roles-permissions` | Built-in & custom roles, permission merging, teams, token capabilities, least privilege. | +| [Taxonomy](cms-taxonomy.md) | `cms-taxonomy` | Hierarchical classification, taxonomy vs tags/labels/references, CDA taxonomy queries. | +| [Tokens & Authentication](cms-tokens-authentication.md) | `cms-tokens-authentication` | Choosing the right token, client- vs server-side safety, rate limits, SSO. | +| [Variants & Personalization](cms-variants-personalization.md) | `cms-variants-personalization` | Variants vs separate entries, variant groups, A/B testing, Personalize integration. | +| [Webhooks](cms-webhooks.md) | `cms-webhooks` | Event channels, payloads, signature verification, retries, reliable receiver design. | +| [Workflows & Publish Rules](cms-workflows.md) | `cms-workflows` | Stage design, approvals, self-approval prevention, publish governance, automation. | + +## Developer Experience + +| Skill | Slug | What it helps with | +| --- | --- | --- | +| [Delivery SDK](dx-delivery-sdk.md) | `dx-delivery-sdk` | Production-ready TypeScript with `@contentstack/delivery-sdk` for entries, assets, queries, Live Preview. | +| [Contentstack Kickstart Next](dx-kickstart-next.md) | `dx-kickstart-next` | Maintaining the Next.js kickstart: App Router, Delivery SDK setup, Live Preview, seed alignment, env vars, validation. | +| [Migrate JS→TS SDK](dx-migrate-js-to-ts-sdk.md) | `dx-migrate-js-to-ts-sdk` | Migrating Delivery SDK code from the JavaScript SDK to the TypeScript SDK. | +| [Live Preview & Visual Builder Support](cms-live-preview-visual-builder-support-assistant.md) | `cms-live-preview-visual-builder-support-assistant` | Diagnosing and implementing Live Preview / Visual Builder across CSR, SSR, SSG, BFF. | +| [Migration Companion](migration-companion.md) | `migration-companion` | Guided Contentful → Contentstack migration: content and application code. | + +## Launch + +| Skill | Slug | What it helps with | +| --- | --- | --- | +| [Sync Launch env vars from .env.example](launch-sync-environment-variables-from-env-example.md) | `launch-sync-environment-variables-from-env-example` | Comparing a local `.env.example` to a Launch environment and patching missing keys. | +| [Trigger & Monitor Deployments](launch-trigger-and-monitor-launch-deployments.md) | `launch-trigger-and-monitor-launch-deployments` | Triggering a Launch deploy, polling to completion, diagnosing failures from logs. | + +## Brand Kit + +| Skill | Slug | What it helps with | +| --- | --- | --- | +| [Brand Kit Assistant](brand-kit-assistant.md) | `brand-kit-assistant` | Brand Kit, Voice Profiles, Knowledge Vault, on-brand AI generation, governance, API routing. | + +## Developer Hub + +| Skill | Slug | What it helps with | +| --- | --- | --- | +| [Developer Hub App Architect](developer-hub-app-architect.md) | `developer-hub-app-architect` | Designing & building Developer Hub / Marketplace apps: UI locations, manifest, SDK, proxy, publishing. | + +## How skills get selected + +You don't pick skills manually for full-bundle installs: the [router](../how-it-works/router.md) matches your request automatically. Many tasks pull in more than one skill (for example, Releases + Webhooks). To force a specific skill, name it in your prompt. diff --git a/docs/skills/launch-sync-environment-variables-from-env-example.md b/docs/skills/launch-sync-environment-variables-from-env-example.md new file mode 100644 index 0000000..d198697 --- /dev/null +++ b/docs/skills/launch-sync-environment-variables-from-env-example.md @@ -0,0 +1,47 @@ +--- +title: Sync Launch env vars from .env.example +description: Compare a local .env.example with a Contentstack Launch environment and patch the environment to add any missing keys: without exposing secrets. +--- + +# Sync Launch env vars from .env.example + +**Slug:** `launch-sync-environment-variables-from-env-example` · **Product:** Launch · **Type:** Action (gated) + +Fetches environment variables from a Contentstack Launch project, compares them with a local `.env.example` file, and patches the target environment to add any missing keys. Useful for auditing missing variables before a deployment and keeping a Launch environment aligned with what a frontend project expects. + +> This skill has `disable-model-invocation: true`. It runs only when you explicitly invoke it, not via automatic routing. + +## When it triggers + +When a Launch environment must match the keys defined in a local `.env.example`, when auditing missing variables before a deployment, or when adding missing variable names without manually editing config. + +## How it works + +1. Read and parse `.env.example`, extracting variable names (ignoring comments, blanks, malformed entries). +2. Fetch the target Launch project and environment and read its current variables. +3. Compare keys: identify only missing keys unless you explicitly ask to update existing values. +4. Build a minimal patch payload with only the missing keys. +5. `PATCH /projects/{project_uid}/environments/{environment_uid}`. +6. Report missing keys, patched keys, and any errors: without exposing values. + +## Inputs + +- Launch project UID +- Launch environment UID +- Path to local `.env.example` +- Launch API credentials / authenticated context +- Optional dry-run flag + +## Example prompts + +- "Generate a Node.js script that syncs Launch environment variables from `.env.example`." +- "Compare my Launch environment variables with `.env.example` and add any missing keys." +- "Patch missing Launch environment variables for project `abc123` and environment `dev456`." + +## Safety notes + +Treats any PATCH as a destructive external action. Validates and confirms the target project/environment, and never broadens the update beyond missing keys unless asked. Prefers dry-run. Logs only key names and counts; never prints secret values from Launch or local files. Uses the smallest possible PATCH payload. + +## Related + +- [Trigger & Monitor Deployments](launch-trigger-and-monitor-launch-deployments.md) · [Environments & Publishing](cms-environments-publishing.md) diff --git a/docs/skills/launch-trigger-and-monitor-launch-deployments.md b/docs/skills/launch-trigger-and-monitor-launch-deployments.md new file mode 100644 index 0000000..a814042 --- /dev/null +++ b/docs/skills/launch-trigger-and-monitor-launch-deployments.md @@ -0,0 +1,48 @@ +--- +title: Trigger & Monitor Deployments +description: Trigger a Contentstack Launch deployment, poll it to completion, and diagnose failures from the deployment log. +--- + +# Trigger & Monitor Deployments + +**Slug:** `launch-trigger-and-monitor-launch-deployments` · **Product:** Launch · **Type:** Action (gated) + +Triggers a Launch deployment for a specific environment, polls its status until completion, and, if it fails or is cancelled, fetches the deployment log and diagnoses likely causes with next-step recommendations. Built for CI/CD or operator workflows that need a deterministic deploy status check. + +> This skill has `disable-model-invocation: true`. It runs only when you explicitly invoke it. + +## When it triggers + +When you need to automate Launch deployments for a known project and environment, monitor progress, and surface failure diagnostics. + +## How it works + +1. Validate the project and environment identifiers. +2. Confirm the target is allowed. **Require explicit approval for production**. +3. Trigger: `POST /projects/{project_uid}/environments/{environment_uid}/deployments`. +4. Poll status every 10 seconds until a terminal state. +5. Fail fast. Exit non-zero on `failed` or `cancelled`; stop polling. +6. On failure, `GET .../deployments/{deployment_uid}` for the log, then summarize the likely cause and next steps. + +## Inputs + +- `project_uid` +- `environment_uid` +- Optional deployment payload / build reference +- Confirmation for production deployments +- Any context about the app, branch, or build source + +## Example prompts + +- "Trigger a deployment for project `abc123` in environment `prod456` and watch it until it finishes." +- "Deploy the latest build to staging and tell me if it fails." +- "Poll a Launch deployment every 10 seconds and exit non-zero on failure." +- "If the deployment fails, check the logs and explain what went wrong." + +## Safety notes + +Treats deployment triggers as external side effects. Requires explicit confirmation before production deployments and never auto-deploys to production without review. Doesn't auto-retry failed deployments unless asked and the target is non-production. Never prints API tokens, deployment tokens, or environment secrets; redacts sensitive values from logs and summaries. Uses a non-zero exit code for failed or cancelled deployments. + +## Related + +- [Sync Launch env vars from .env.example](launch-sync-environment-variables-from-env-example.md) · [Branches & Aliases](cms-branches-aliases.md) · [Releases](cms-releases.md) diff --git a/docs/skills/migration-companion.md b/docs/skills/migration-companion.md new file mode 100644 index 0000000..d8a8473 --- /dev/null +++ b/docs/skills/migration-companion.md @@ -0,0 +1,51 @@ +--- +title: Migration Companion +description: Guided Contentful → Contentstack migration: content (types, entries, assets, locales) and application code: with prerequisite checks and post-migration validation. +--- + +# Migration Companion + +**Slug:** `migration-companion` · **Product:** Developer Experience · **Type:** Action (gated) · **Ships references & scripts** + +Guides a user end-to-end through migrating a project from **Contentful** to **Contentstack**: first the content (content types, entries, assets, locales) via the Contentstack CLI migrate plugin, then the website code that reads from the CMS. It's a sequential workflow where each step's output feeds the next. + +## When it triggers + +When you want to migrate, move, switch, port, or re-platform to Contentstack: content models, content, assets, locales, application integrations, or website code. Triggers on requests like "migrate to Contentstack," "move my Contentful space," or "migrate from Contentful." Contentful is currently the only supported source. + +## The migration at a glance + +| Step | What happens | Produces | +| ------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------- | +| 1. Prerequisites & inputs | Prereq checker validates Node 20+, Python 3, `csdx`, `contentful`, logins, region, spaces | Verified env + gathered inputs | +| 2. Install migrate plugin | Installs/updates `@contentstack/cli-external-migrate` | `csdx migrate:*` available | +| 3. Content migration | `csdx migrate:create` exports, converts, and imports into a new stack | Populated stack + bundle + credentials | +| 4. Code migration | Detect → plan → rewrite → eval (13 checks) | Rewritten data layer | +| 5. Welcome | : | Recap + next steps | + +## What it covers + +- **Isolated session workspace** under `/tmp/migrate-to-cs/` so concurrent runs never collide. +- **Pinned Node version**. Uses the highest installed Node ≥ 20 the checker validated. +- **Browser-based logins** for Contentstack OAuth and Contentful, handled interactively. +- **Content import** with entity-count verification (locales, content types, assets, entries imported vs exported). +- **Code rewrite** following a source-verified Contentful → Contentstack mapping reference, covering REST Delivery SDK, GraphQL, raw REST/framework plugins, rich text, assets, locales, pagination, and Live Preview. +- **Eval suite** of 13 post-migration checks (residue, field access, SDK init, build, secrets, plus review evals) that hard-gate completion. + +## References & scripts + +Ships a full `references/` mapping (`CONTENTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md`) and a `scripts/` suite: the prerequisite checker, import-summary parser, logging helpers, and per-check eval scripts (`run-all.sh` plus numbered checks). + +## Safety notes + +Action skill with explicit gates: confirms before logging in, before creating a stack, and before editing your code. Treats management tokens as secrets. Never echoes them or writes them to workspace files; sets `CS_*` credentials only in the migrated app's gitignored `.env`. Converts reference dereferences to safe array access and flags every guessed field UID with a `TODO(migration)` comment rather than guessing silently. + +## Example prompts + +- "Migrate my Contentful space to Contentstack." +- "Move my CMS and website code from Contentful to Contentstack." +- "Port my Contentful content models and entries to Contentstack." + +## Related + +- [Delivery SDK](dx-delivery-sdk.md) · [Migrate JS→TS SDK](dx-migrate-js-to-ts-sdk.md) · [Data Modeling Best Practices](cms-data-modeling-best-practices.md) diff --git a/manifest.json b/manifest.json index 564e68e..40cf1a3 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "exported_at": "2026-04-28T08:27:32.000Z", - "skill_count": 21, + "skill_count": 22, "skills": [ { "slug": "brand-kit-assistant", @@ -87,6 +87,11 @@ "title": "dx-delivery-sdk", "product": "Developer Experience" }, + { + "slug": "dx-kickstart-next", + "title": "Contentstack Kickstart Next", + "product": "Developer Experience" + }, { "slug": "dx-migrate-js-to-ts-sdk", "title": "dx-migrate-js-to-ts-sdk", diff --git a/skills/CLAUDE.md b/skills/CLAUDE.md index e86f870..abb039d 100644 --- a/skills/CLAUDE.md +++ b/skills/CLAUDE.md @@ -8,6 +8,7 @@ Use the table below to route a user request to the right skill. Each row maps a | Use when users want to migrate, move, switch, port, or re-platform from Contentful to Contentstack, including content models, content, assets, locales, application integrations, website code, migration prerequisites, migration progress checks, or post-migration validation. | [contentstack-migration-companion](./migration-companion/SKILL.md) | | Use when a user wants to migrate Contentstack Delivery SDK code from JavaScript to TypeScript. | [dx-migrate-js-to-ts-sdk](./dx-migrate-js-to-ts-sdk/SKILL.md) | | Use when a user asks for Contentstack Delivery SDK code, query examples, helper functions, SDK setup, stack initialization, reference inclusion, filtering, sorting, pagination, typed entry fetching, asset fetching, Live Preview setup, Visual Builder support, SSR preview handling, or debugging SDK query chains. | [dx-delivery-sdk](./dx-delivery-sdk/SKILL.md) | +| Use when working on Contentstack's `kickstart-next` repository or a close fork, including Next.js App Router structure, Contentstack Delivery SDK setup, Live Preview or Visual Builder behavior, seeded stack alignment, environment variables, endpoint or image host configuration, package scripts, validation, CI expectations, or PR review checklists. | [contentstack-kickstart-next](./dx-kickstart-next/SKILL.md) | | Use when designing, reviewing, or refactoring Contentstack content models before creating or changing schemas. | [Contentstack Data Modeling Best Practices](./cms-data-modeling-best-practices/SKILL.md) | | Use this skill when a user is implementing or debugging Contentstack Live Preview or Visual Builder, including blank preview panels, stale or published-only preview, lost preview context after navigation, shared SSR state, cache contamination, or edit-tag mapping failures. Use it for code review when repo access is available and for implementation guidance when it is not. | [Live Preview and Visual Builder Support Assistant](./cms-live-preview-visual-builder-support-assistant/SKILL.md) | | Use when developers ask about fetching entries, building CDA queries, handling localization, publishing workflows, versioning behavior, bulk operations, or entry-related performance issues. | [Entries](./cms-entries/SKILL.md) | diff --git a/skills/dx-kickstart-next/SKILL.md b/skills/dx-kickstart-next/SKILL.md new file mode 100644 index 0000000..af72619 --- /dev/null +++ b/skills/dx-kickstart-next/SKILL.md @@ -0,0 +1,34 @@ +--- +name: contentstack-kickstart-next +description: Guidance for building, reviewing, debugging, or extending Contentstack's kickstart-next repository. Use when working on the Next.js kickstart app, Contentstack Delivery SDK setup, Live Preview or Visual Builder behavior, seeded stack alignment, environment variables, endpoint or image host configuration, App Router structure, package scripts, local setup, CI expectations, tests, lint/build validation, or PR review checklists. +--- + +# Contentstack kickstart-next + +Use this skill when working in `contentstack/kickstart-next` or a close fork. Inspect the repository first, then load only the matching reference files. + +## Routing + +1. For App Router routes, React components, client/server boundaries, Tailwind, ESLint, TypeScript, images, or `next.config.mjs`, read [references/next.md](references/next.md). +2. For Contentstack delivery, preview, Visual Builder, regions, endpoint overrides, env vars, or seeded stack alignment, read [references/contentstack.md](references/contentstack.md). +3. For content type UIDs, field UIDs, modular blocks, CSLP `$` mappings, or schema-driven renderer/type changes, read [references/content-model.md](references/content-model.md). +4. For local setup, Contentstack stack seeding, npm scripts, CI, CODEOWNERS, validation commands, docs updates, or PR prep, read [references/workflow.md](references/workflow.md). +5. For PR/code reviews, severity labels, security checks, or risk checklists, read [references/review.md](references/review.md). + +## Default working rules + +- Keep guidance grounded in the current checkout. Inspect files before assuming scripts, tests, CI, content types, env vars, or framework conventions exist. +- Treat kickstarts as user-facing examples: prefer clarity, minimal moving parts, safe defaults, and copyable setup steps over clever abstractions. +- Preserve Live Preview behavior when changing data fetching, route rendering, components, content types, field UIDs, or Visual Builder bindings. +- Never commit real Contentstack credentials. Use placeholders in docs and `.env.example`; real values belong in a local gitignored `.env`. +- When adding or renaming env vars, update `.env.example` and user-facing docs together. +- When adding remote image sources, update the framework-specific image allowlist or documented env override. +- When modifying JavaScript or TypeScript files, run `npm run build`; also run `npm run lint` and any `typecheck` script if they exist. +- Before claiming CI covers something, verify the workflows. If build, lint, or tests are not wired into CI, tell the user to run them locally. + +## Response behavior + +- For implementation help, give concrete file-level changes and commands. +- For reviews, separate blockers from major issues and minor nits. +- For repo setup help, give the shortest successful path first, then optional troubleshooting. +- If asked to generalize framework-specific guidance later, keep Contentstack behavior in `contentstack.md` and Next.js behavior in `next.md`. diff --git a/skills/dx-kickstart-next/references/content-model.md b/skills/dx-kickstart-next/references/content-model.md new file mode 100644 index 0000000..fa8319e --- /dev/null +++ b/skills/dx-kickstart-next/references/content-model.md @@ -0,0 +1,48 @@ +# Content model guidance for kickstart-next + +Use this before changing Contentstack content type UIDs, field UIDs, `lib/types.ts`, modular block rendering, or Visual Builder/CSLP bindings. + +## Seed contract + +The app assumes content from `contentstack/kickstart-stack-seed`. Verify the actual stack or seed before making schema claims, but preserve this contract unless the user intentionally changes the model. + +| Content type | UID | Used by | +| --- | --- | --- | +| Page | `page` | `lib/contentstack.ts` `getPage(url)`, `app/page.tsx`, `components/Page.tsx`, `lib/types.ts` `Page` | + +## Page fields + +| Field | UID | Type shape in app | Rendered by | Live Preview binding | +| --- | --- | --- | --- | --- | +| Title | `title` | `Page.title: string` | `components/Page.tsx` `h1` | `page.$.title` | +| URL | `url` | `Page.url?: string` | queried by `getPage(url)` | `page.$.url` if rendered later | +| Description | `description` | `Page.description?: string` | `components/Page.tsx` paragraph | `page.$.description` | +| Image | `image` | `Page.image?: File \| null` | `next/image` in `components/Page.tsx` | asset `$` mapping, currently `page.image.$.url` | +| Rich Text | `rich_text` | `Page.rich_text?: string` | sanitized HTML in `components/Page.tsx` | `page.$.rich_text` | +| Blocks | `blocks` | `Page.blocks?: Blocks[]` | modular block loop in `components/Page.tsx` | `page.$.blocks` and indexed `page.$["blocks__${index}"]` | + +## Modular block shape + +The `blocks` field contains entries shaped like `{ block: Block }`. + +| Block field | UID | Type shape in app | Rendered by | Live Preview binding | +| --- | --- | --- | --- | --- | +| Title | `title` | `Block.title?: string` | block `h2` | `block.$.title` | +| Copy | `copy` | `Block.copy?: string` | sanitized HTML | `block.$.copy` | +| Image | `image` | `Block.image?: File \| null` | `next/image` | `block.$.image` | +| Layout | `layout` | `"image_left" \| "image_right" \| null` | flex direction choice | `block.$.layout` if rendered later | +| Metadata | `_metadata.uid` | key fallback for React list items | list item key | not user-editable | + +## Asset shape + +- Use the local `File` interface for Contentstack assets. +- Render images with `file.url` and descriptive alt text from `file.title` or another safe fallback. +- Keep asset CSLP mappings under `File.$` when the rendered asset field needs Visual Builder editing. + +## Change checklist + +- If a UID changes, update `getPage`, `lib/types.ts`, renderers, docs, and any Contentstack seed instructions together. +- If a field is added, add the TypeScript shape, render path, fallback behavior for missing content, and `$` mapping only where the field is editable. +- If a modular block is added, preserve empty-block editing support with `VB_EmptyBlockParentClass` on the parent block container. +- If rich text or HTML-like fields are added, sanitize before rendering with `dangerouslySetInnerHTML`. +- If image fields are added, verify `next.config.mjs` allows the image hostname. diff --git a/skills/dx-kickstart-next/references/contentstack.md b/skills/dx-kickstart-next/references/contentstack.md new file mode 100644 index 0000000..8c5ae29 --- /dev/null +++ b/skills/dx-kickstart-next/references/contentstack.md @@ -0,0 +1,48 @@ +# Contentstack guidance for kickstart-next + +Use this when changing how `kickstart-next` talks to Contentstack, handles preview, resolves regions/hosts, or aligns with the seeded content model. + +## Delivery and preview + +- Keep stack configuration and fetching centralized in `lib/contentstack.ts`. +- Create the stack with `@contentstack/delivery-sdk`, using API key, delivery token, environment, region, optional custom delivery host, and `live_preview` options. +- Initialize Live Preview with `@contentstack/live-preview-utils` using builder mode, stack SDK/config, stack details, client URL params, and edit button settings. +- Query the `page` content type by URL when resolving pages. In `kickstart-next`, `getPage(url)` filters `url` with `QueryOperation.EQUALS` and returns the first `Page` entry. +- When preview mode is enabled, add editable tags with `contentstack.Utils.addEditableTags()` and preserve `$` attributes on entries, fields, and modular blocks. + +## Preview versus production + +- Preserve the split between production server rendering and preview client refreshes. +- `app/page.tsx` should fetch `getPage("/")` server-side before branching so both production and preview receive initial content. +- Preview should render `components/Preview.tsx`, initialize Live Preview client-side, subscribe to entry changes, and refetch the current path. + +## Regions and hosts + +- Prefer Contentstack endpoint helpers where already used by the repo. Current `kickstart-next` uses `getContentstackEndpoint(region, "", true)` from `@contentstack/utils`. +- Keep advanced host overrides documented and wired consistently: + - Delivery host override: `NEXT_PUBLIC_CONTENTSTACK_CONTENT_DELIVERY` in `kickstart-next`. + - Preview host override: `NEXT_PUBLIC_CONTENTSTACK_PREVIEW_HOST` in `kickstart-next`. + - Application or Live Preview UI host override: `NEXT_PUBLIC_CONTENTSTACK_CONTENT_APPLICATION` in `kickstart-next`. + - Image hostname override: `NEXT_PUBLIC_CONTENTSTACK_IMAGE_HOSTNAME` in `kickstart-next`. +- If a variable is supported in code but missing from `.env.example` or README setup docs, update the docs/example when touching that area. + +## Environment variables + +- Required for normal operation: `NEXT_PUBLIC_CONTENTSTACK_API_KEY`, `NEXT_PUBLIC_CONTENTSTACK_DELIVERY_TOKEN`, `NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT`, `NEXT_PUBLIC_CONTENTSTACK_REGION`. +- Required for preview mode: `NEXT_PUBLIC_CONTENTSTACK_PREVIEW=true` and `NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN`. +- Advanced/dedicated-environment overrides: `NEXT_PUBLIC_CONTENTSTACK_CONTENT_DELIVERY`, `NEXT_PUBLIC_CONTENTSTACK_PREVIEW_HOST`, `NEXT_PUBLIC_CONTENTSTACK_CONTENT_APPLICATION`, `NEXT_PUBLIC_CONTENTSTACK_IMAGE_HOSTNAME`. +- Keep real tokens out of committed files. Use placeholder values in `.env.example`, README snippets, and docs. + +## Seed alignment + +- Assume the app is aligned to the `contentstack/kickstart-stack-seed` stack unless the repo says otherwise. +- For a compact schema map, read [content-model.md](content-model.md) before changing content type UIDs, field UIDs, modular blocks, TypeScript entry shapes, or renderer bindings. +- Changing content type UIDs, field UIDs, or modular block shapes requires matching updates to `lib/types.ts`, renderers, docs, and Live Preview bindings. +- Preserve the `Page` fields expected by the seed: `title`, `url`, `description`, `image`, `rich_text`, and `blocks`. +- Preserve modular block support for `block.title`, `block.copy`, `block.image`, `block.layout`, and `_metadata.uid` unless intentionally changing the seed contract. +- Keep CSLP shapes aligned with the fields rendered in components. `$` mappings are needed on entries, assets, and modular blocks for Visual Builder editing. + +## Rendering safety + +- Continue sanitizing rich text HTML with `isomorphic-dompurify` before `dangerouslySetInnerHTML`. +- Keep `VB_EmptyBlockParentClass` on empty modular block containers so Visual Builder can target empty block areas. diff --git a/skills/dx-kickstart-next/references/next.md b/skills/dx-kickstart-next/references/next.md new file mode 100644 index 0000000..91d2205 --- /dev/null +++ b/skills/dx-kickstart-next/references/next.md @@ -0,0 +1,42 @@ +# Next.js guidance for kickstart-next + +Use this when changing the Next.js app, route structure, rendering behavior, images, TypeScript, ESLint, Tailwind, or package scripts. + +## App structure + +- `app/layout.tsx` is the root layout and imports `app/globals.css`. +- `app/page.tsx` is the home route. It calls `getPage("/")`, then renders `components/Preview.tsx` when preview is enabled or `components/Page.tsx` otherwise. +- `components/Preview.tsx` is a Client Component. Keep `"use client"` at the top if it uses hooks or `@contentstack/live-preview-utils` subscriptions. +- `components/Page.tsx` renders Contentstack fields and is imported elsewhere as `Page`, even though its internal function name may differ. +- `lib/contentstack.ts` owns Contentstack stack setup, `isPreview`, `initLivePreview()`, and `getPage(url)`. +- `lib/types.ts` owns TypeScript shapes for Contentstack entries, assets, modular blocks, and CSLP `$` mappings. + +## Client/server boundaries + +- Fetch initial page data in the route/server component where possible. +- Use `Preview` only for Live Preview client behavior: initialize preview, subscribe to `ContentstackLivePreview.onEntryChange`, refetch with `getPage(path)`, and unsubscribe on cleanup. +- Do not move browser-only preview utilities into server-only execution paths. + +## Images and rich text + +- Use `next/image` for Contentstack images. +- Keep allowed image hosts in `next.config.mjs` under `images.remotePatterns`. +- Default image hosts are `images.contentstack.io` and `*-images.contentstack.com`; `NEXT_PUBLIC_CONTENTSTACK_IMAGE_HOSTNAME` can override with a single hostname for custom environments. +- Sanitize rich text with `isomorphic-dompurify` before using `dangerouslySetInnerHTML`. + +## Styling + +- The project uses Tailwind CSS 4 via `@tailwindcss/postcss` in `postcss.config.mjs`. +- `app/globals.css` imports Tailwind with `@import "tailwindcss"` and includes base compatibility styles for Tailwind v4 border defaults. +- Keep the kickstart visually simple and example-friendly. Avoid adding a design system unless the user explicitly asks for one. + +## TypeScript and linting + +- `tsconfig.json` uses `strict: true`, `noEmit: true`, `moduleResolution: "bundler"`, and the `@/*` path alias. +- `eslint.config.mjs` composes Next core web vitals and TypeScript presets. +- `@typescript-eslint/no-explicit-any` is off in the current config, but prefer precise Contentstack types when practical. + +## Package scripts + +- Current scripts are usually `dev`, `build`, `start`, and `lint`. Verify `package.json` before telling the user a script exists. +- There is typically no `typecheck` script; if one is absent, say that type checking is covered by `next build` rather than claiming a separate command ran. diff --git a/skills/dx-kickstart-next/references/review.md b/skills/dx-kickstart-next/references/review.md new file mode 100644 index 0000000..f00fd34 --- /dev/null +++ b/skills/dx-kickstart-next/references/review.md @@ -0,0 +1,45 @@ +# Review guidance for kickstart-next + +Use this for PR reviews, pre-PR checks, risk assessment, or summarizing changes for maintainers. + +## Review stance + +- Lead with bugs, regressions, missing validation, and security risks. +- Ground findings in file and line references when reviewing a local checkout. +- Separate blockers, major issues, and minor nits. +- Keep summaries secondary to findings. + +## Blockers + +- Secrets or real Contentstack credentials committed anywhere. +- Build or lint failures caused by the change. +- Broken production home route or preview route. +- Live Preview or Visual Builder field binding regressions. +- XSS regression from unsanitized rich text or unsafe `dangerouslySetInnerHTML`. +- Content type UID, field UID, or modular block changes that are not reflected in types/renderers/docs. + +## Major issues + +- New environment variables missing from `.env.example` or setup docs. +- New remote image hostnames not represented in `next.config.mjs`. +- Moving Contentstack setup out of `lib/contentstack.ts` without a clear simplification. +- Client-only preview code introduced into server execution paths. +- Dependency additions that are unnecessary for a minimal kickstart or likely to fail security scans. +- CI claims that do not match `.github/workflows`. + +## Minor issues + +- Overly complex abstractions in example code. +- Copy or README changes that make setup less direct. +- Styling changes that distract from the kickstart's purpose as a minimal Contentstack integration example. +- Type looseness where existing Contentstack types could be extended cleanly. + +## Pre-PR checklist + +- Run `npm run build`. +- Run `npm run lint` if present. +- Run any `typecheck` or `test` scripts only if present. +- Verify `.env.example` and docs for env changes. +- Scan the diff for secrets. +- Read `references/content-model.md` for schema-impacting changes. +- Check preview behavior if data fetching, CSLP `$` attributes, components, content model fields, or Live Preview initialization changed. diff --git a/skills/dx-kickstart-next/references/workflow.md b/skills/dx-kickstart-next/references/workflow.md new file mode 100644 index 0000000..81e5378 --- /dev/null +++ b/skills/dx-kickstart-next/references/workflow.md @@ -0,0 +1,46 @@ +# Workflow guidance for kickstart-next + +Use this for setup, seeding, environment variables, validation commands, CI expectations, docs updates, dependency changes, or PR prep. + +## Local setup + +- Prefer npm: install with `npm install`. +- Copy `.env.example` to `.env` and fill in Contentstack values locally. +- Run the app with `npm run dev`, then open `http://localhost:3000`. +- For production verification, run `npm run build` and then `npm run start` if runtime behavior needs manual checking. + +## Contentstack stack setup + +- Install the Contentstack CLI with `npm install -g @contentstack/cli` if the user needs to seed a stack. +- Configure the CLI region when prompted; free developer accounts are commonly EU, but verify the user's account/URL. +- Login with `csdx auth:login`. +- Seed the compatible model with `csdx cm:stacks:seed --repo "contentstack/kickstart-stack-seed" --org "" -n "Kickstart Stack"`. +- Create a delivery token with preview scope and a preview token when Live Preview is needed. +- Enable Live Preview in the stack settings for the preview environment. + +## Validation + +- After JavaScript or TypeScript edits, run `npm run build`. +- Run `npm run lint` when the script exists. +- Run `npm run typecheck` only if `package.json` defines it. +- Run tests only if the checkout defines test scripts or test tooling. The upstream kickstart currently has no default `test` script. +- If validation cannot run because Contentstack credentials are unavailable, report that clearly and still run static checks that do not require credentials. + +## Environment and docs + +- When adding or renaming environment variables, update `.env.example` and user-facing setup docs together. +- Document runtime behavior changes in `docs/` when the repository has or needs product-facing docs for that behavior. +- Keep README setup snippets short and copyable. +- Never commit real API keys, delivery tokens, preview tokens, management tokens, organization IDs, or stack IDs. + +## CI expectations + +- Verify `.github/workflows` before making CI claims. +- Upstream workflows focus on security/policy checks such as Snyk/SCA, security policy/license checks, and issue-to-Jira integration. +- Do not assume GitHub Actions runs `npm run build`, `npm run lint`, unit tests, or E2E tests unless a workflow in the checkout proves it. + +## Ownership and dependencies + +- Check `.github/CODEOWNERS` before making reviewer or ownership claims. +- Dependency changes can affect Snyk/SCA workflows; keep package lock changes intentional and explain why a dependency is needed. +- Prefer npm for dependency installation and lockfile updates. From e9e682bd63138c924e1b9a7ab5b8a6b9cee1b580 Mon Sep 17 00:00:00 2001 From: Tim Benniks Contentstack Date: Wed, 1 Jul 2026 11:15:36 +0200 Subject: [PATCH 02/20] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docs/skills/migration-companion.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/skills/migration-companion.md b/docs/skills/migration-companion.md index d8a8473..7703beb 100644 --- a/docs/skills/migration-companion.md +++ b/docs/skills/migration-companion.md @@ -21,7 +21,7 @@ When you want to migrate, move, switch, port, or re-platform to Contentstack: co | 2. Install migrate plugin | Installs/updates `@contentstack/cli-external-migrate` | `csdx migrate:*` available | | 3. Content migration | `csdx migrate:create` exports, converts, and imports into a new stack | Populated stack + bundle + credentials | | 4. Code migration | Detect → plan → rewrite → eval (13 checks) | Rewritten data layer | -| 5. Welcome | : | Recap + next steps | +| 5. Welcome | — | Recap + next steps | ## What it covers From bd7d5c700229e8fd15df6b26eb2f75a0956f0005 Mon Sep 17 00:00:00 2001 From: Tim Benniks Contentstack Date: Wed, 1 Jul 2026 11:15:55 +0200 Subject: [PATCH 03/20] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docs/skills/dx-migrate-js-to-ts-sdk.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/skills/dx-migrate-js-to-ts-sdk.md b/docs/skills/dx-migrate-js-to-ts-sdk.md index 6cc9a73..c316cba 100644 --- a/docs/skills/dx-migrate-js-to-ts-sdk.md +++ b/docs/skills/dx-migrate-js-to-ts-sdk.md @@ -15,7 +15,7 @@ When you want to migrate Delivery SDK code from JavaScript to TypeScript, compar ## What it covers -- **Packages & imports**: install `@contentstack/delivery-sdk@latest`; switch imports; add `@contentstack/persistance-plugin` for cache and `@contentstack/utils` for utils. +- **Packages & imports**: install `@contentstack/delivery-sdk@latest`; switch imports; add `@contentstack/persistence-plugin` for cache and `@contentstack/utils` for utils. - **Key API mappings**: `contentstack.stack(...)` (not `Stack(...)`); `stack.contentType(...).entry(...).asset(...).query().fetch().find()`, plus `paginate()`, `next()`, `previous()`, `locale()`, `includeReference()`, `includeEmbeddedItems()`, `includeContentType()`, `includeCount()`, and taxonomy methods. - **Typed results**: generics on `fetch()`. - **Cache**: install the persistence plugin and pass `cacheOptions` for policies other than `Policy.IGNORE_CACHE`. From cfa937038fc9b05eb2836e475e184c403f15371a Mon Sep 17 00:00:00 2001 From: Tim Benniks Date: Wed, 14 Oct 2026 10:34:20 +0200 Subject: [PATCH 04/20] Ship skills natively to every agent; drop generated trees All target tools (Claude Code, claude.ai, Cursor, Codex, Copilot, Gemini CLI, skills CLI) now read skills//SKILL.md directly, so remove the generated cursor/rules and codex trees and their build scripts, which had an inverted alwaysApply mapping, stripped --- lines from bodies and lost frontmatter. - Fold router "Use when" triggers into each skill description and drop skills/CLAUDE.md, which no plugin loads - Rename migration-companion's name to match its folder - Add Agent Plugins plugin.json, Codex and Cursor marketplaces; use "./" source for claude.ai sync; bump all manifests to 0.2.0 - Replace build workflow with scripts/validate.mjs (spec + version checks) - Remove unused manifest.json; rewrite README install per tool Co-Authored-By: Claude Opus 5.5 --- .agents/plugins/marketplace.json | 10 + .claude-plugin/marketplace.json | 13 +- .claude-plugin/plugin.json | 12 +- .cursor-plugin/marketplace.json | 11 + .cursor-plugin/plugin.json | 7 +- .github/workflows/build.yml | 40 - .github/workflows/validate.yml | 21 + .gitignore | 1 + AGENTS.md | 1 + CLAUDE.md | 16 +- README.md | 90 +- codex/AGENTS.md | 27 - codex/brand-kit-assistant/SKILL.md | 223 ---- .../brand-kit-management-api-reference.md | 31 - .../knowledge-vault-api-reference-skill.md | 29 - codex/cms-assets/SKILL.md | 96 -- codex/cms-branches-aliases/SKILL.md | 99 -- .../cms-data-modeling-best-practices/SKILL.md | 135 -- codex/cms-entries/SKILL.md | 102 -- codex/cms-environments-publishing/SKILL.md | 103 -- .../SKILL.md | 266 ---- codex/cms-localization/SKILL.md | 100 -- codex/cms-releases/SKILL.md | 120 -- codex/cms-roles-permissions/SKILL.md | 126 -- codex/cms-taxonomy/SKILL.md | 123 -- codex/cms-tokens-authentication/SKILL.md | 123 -- codex/cms-variants-personalization/SKILL.md | 118 -- codex/cms-webhooks/SKILL.md | 135 -- codex/cms-workflows/SKILL.md | 129 -- codex/developer-hub-app-architect/SKILL.md | 180 --- .../developer-hub-coding-reference.md | 860 ------------ codex/dx-delivery-sdk/SKILL.md | 336 ----- .../references/delivery-sdk-spec.md | 1157 ----------------- codex/dx-migrate-js-to-ts-sdk/SKILL.md | 196 --- .../SKILL.md | 127 -- .../SKILL.md | 148 --- codex/migration-companion/SKILL.md | 947 -------------- ...NTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md | 907 ------------- .../scripts/01_contentful_residue.sh | 27 - .../scripts/02_field_access.sh | 17 - .../scripts/03_sdk_init.sh | 28 - .../scripts/04_query_builder.sh | 21 - .../scripts/05_references.sh | 27 - .../scripts/06_richtext.sh | 26 - .../migration-companion/scripts/07_assets.sh | 20 - .../migration-companion/scripts/08_locales.sh | 17 - .../migration-companion/scripts/09_graphql.sh | 18 - .../scripts/10_livepreview.sh | 34 - .../scripts/11_build_typecheck.sh | 54 - .../migration-companion/scripts/12_secrets.sh | 27 - .../scripts/13_todos_report.sh | 10 - codex/migration-companion/scripts/README.md | 92 -- codex/migration-companion/scripts/_lib.sh | 109 -- .../scripts/check_prereqs.py | 307 ----- codex/migration-companion/scripts/log.sh | 97 -- .../scripts/parse_import_summary.py | 168 --- codex/migration-companion/scripts/run-all.sh | 77 -- cursor/rules/00-router.mdc | 32 - cursor/rules/01-brand-kit-assistant.mdc | 226 ---- cursor/rules/02-cms-assets.mdc | 99 -- cursor/rules/03-cms-branches-aliases.mdc | 102 -- .../04-cms-data-modeling-best-practices.mdc | 138 -- cursor/rules/05-cms-entries.mdc | 105 -- .../rules/06-cms-environments-publishing.mdc | 106 -- ...eview-visual-builder-support-assistant.mdc | 269 ---- cursor/rules/08-cms-localization.mdc | 103 -- cursor/rules/09-cms-releases.mdc | 123 -- cursor/rules/10-cms-roles-permissions.mdc | 129 -- cursor/rules/11-cms-taxonomy.mdc | 126 -- cursor/rules/12-cms-tokens-authentication.mdc | 126 -- .../rules/13-cms-variants-personalization.mdc | 121 -- cursor/rules/14-cms-webhooks.mdc | 138 -- cursor/rules/15-cms-workflows.mdc | 132 -- .../rules/16-developer-hub-app-architect.mdc | 183 --- cursor/rules/17-dx-delivery-sdk.mdc | 339 ----- cursor/rules/18-dx-migrate-js-to-ts-sdk.mdc | 199 --- ...environment-variables-from-env-example.mdc | 130 -- ...trigger-and-monitor-launch-deployments.mdc | 151 --- cursor/rules/21-migration-companion.mdc | 950 -------------- gemini-extension.json | 5 +- manifest.json | 111 -- plugin.json | 11 + scripts/build-codex-skills.sh | 38 - scripts/build-cursor-rules.sh | 56 - scripts/validate.mjs | 86 ++ skills/CLAUDE.md | 27 - skills/brand-kit-assistant/SKILL.md | 2 +- skills/cms-assets/SKILL.md | 2 +- skills/cms-branches-aliases/SKILL.md | 2 +- .../cms-data-modeling-best-practices/SKILL.md | 2 +- skills/cms-entries/SKILL.md | 2 +- skills/cms-environments-publishing/SKILL.md | 2 +- .../SKILL.md | 2 +- skills/cms-localization/SKILL.md | 2 +- skills/cms-releases/SKILL.md | 2 +- skills/cms-roles-permissions/SKILL.md | 2 +- skills/cms-taxonomy/SKILL.md | 2 +- skills/cms-tokens-authentication/SKILL.md | 2 +- skills/cms-variants-personalization/SKILL.md | 2 +- skills/cms-webhooks/SKILL.md | 2 +- skills/cms-workflows/SKILL.md | 2 +- skills/developer-hub-app-architect/SKILL.md | 2 +- skills/dx-delivery-sdk/SKILL.md | 2 +- skills/dx-migrate-js-to-ts-sdk/SKILL.md | 2 +- .../SKILL.md | 2 +- .../SKILL.md | 2 +- skills/migration-companion/SKILL.md | 14 +- 107 files changed, 244 insertions(+), 12512 deletions(-) create mode 100644 .agents/plugins/marketplace.json create mode 100644 .cursor-plugin/marketplace.json delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/validate.yml create mode 120000 AGENTS.md delete mode 100644 codex/AGENTS.md delete mode 100644 codex/brand-kit-assistant/SKILL.md delete mode 100644 codex/brand-kit-assistant/references/brand-kit-management-api-reference.md delete mode 100644 codex/brand-kit-assistant/references/knowledge-vault-api-reference-skill.md delete mode 100644 codex/cms-assets/SKILL.md delete mode 100644 codex/cms-branches-aliases/SKILL.md delete mode 100644 codex/cms-data-modeling-best-practices/SKILL.md delete mode 100644 codex/cms-entries/SKILL.md delete mode 100644 codex/cms-environments-publishing/SKILL.md delete mode 100644 codex/cms-live-preview-visual-builder-support-assistant/SKILL.md delete mode 100644 codex/cms-localization/SKILL.md delete mode 100644 codex/cms-releases/SKILL.md delete mode 100644 codex/cms-roles-permissions/SKILL.md delete mode 100644 codex/cms-taxonomy/SKILL.md delete mode 100644 codex/cms-tokens-authentication/SKILL.md delete mode 100644 codex/cms-variants-personalization/SKILL.md delete mode 100644 codex/cms-webhooks/SKILL.md delete mode 100644 codex/cms-workflows/SKILL.md delete mode 100644 codex/developer-hub-app-architect/SKILL.md delete mode 100644 codex/developer-hub-app-architect/references/developer-hub-coding-reference.md delete mode 100644 codex/dx-delivery-sdk/SKILL.md delete mode 100644 codex/dx-delivery-sdk/references/delivery-sdk-spec.md delete mode 100644 codex/dx-migrate-js-to-ts-sdk/SKILL.md delete mode 100644 codex/launch-sync-environment-variables-from-env-example/SKILL.md delete mode 100644 codex/launch-trigger-and-monitor-launch-deployments/SKILL.md delete mode 100644 codex/migration-companion/SKILL.md delete mode 100644 codex/migration-companion/references/CONTENTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md delete mode 100755 codex/migration-companion/scripts/01_contentful_residue.sh delete mode 100755 codex/migration-companion/scripts/02_field_access.sh delete mode 100755 codex/migration-companion/scripts/03_sdk_init.sh delete mode 100755 codex/migration-companion/scripts/04_query_builder.sh delete mode 100755 codex/migration-companion/scripts/05_references.sh delete mode 100755 codex/migration-companion/scripts/06_richtext.sh delete mode 100755 codex/migration-companion/scripts/07_assets.sh delete mode 100755 codex/migration-companion/scripts/08_locales.sh delete mode 100755 codex/migration-companion/scripts/09_graphql.sh delete mode 100755 codex/migration-companion/scripts/10_livepreview.sh delete mode 100755 codex/migration-companion/scripts/11_build_typecheck.sh delete mode 100755 codex/migration-companion/scripts/12_secrets.sh delete mode 100755 codex/migration-companion/scripts/13_todos_report.sh delete mode 100644 codex/migration-companion/scripts/README.md delete mode 100755 codex/migration-companion/scripts/_lib.sh delete mode 100644 codex/migration-companion/scripts/check_prereqs.py delete mode 100755 codex/migration-companion/scripts/log.sh delete mode 100644 codex/migration-companion/scripts/parse_import_summary.py delete mode 100755 codex/migration-companion/scripts/run-all.sh delete mode 100644 cursor/rules/00-router.mdc delete mode 100644 cursor/rules/01-brand-kit-assistant.mdc delete mode 100644 cursor/rules/02-cms-assets.mdc delete mode 100644 cursor/rules/03-cms-branches-aliases.mdc delete mode 100644 cursor/rules/04-cms-data-modeling-best-practices.mdc delete mode 100644 cursor/rules/05-cms-entries.mdc delete mode 100644 cursor/rules/06-cms-environments-publishing.mdc delete mode 100644 cursor/rules/07-cms-live-preview-visual-builder-support-assistant.mdc delete mode 100644 cursor/rules/08-cms-localization.mdc delete mode 100644 cursor/rules/09-cms-releases.mdc delete mode 100644 cursor/rules/10-cms-roles-permissions.mdc delete mode 100644 cursor/rules/11-cms-taxonomy.mdc delete mode 100644 cursor/rules/12-cms-tokens-authentication.mdc delete mode 100644 cursor/rules/13-cms-variants-personalization.mdc delete mode 100644 cursor/rules/14-cms-webhooks.mdc delete mode 100644 cursor/rules/15-cms-workflows.mdc delete mode 100644 cursor/rules/16-developer-hub-app-architect.mdc delete mode 100644 cursor/rules/17-dx-delivery-sdk.mdc delete mode 100644 cursor/rules/18-dx-migrate-js-to-ts-sdk.mdc delete mode 100644 cursor/rules/19-launch-sync-environment-variables-from-env-example.mdc delete mode 100644 cursor/rules/20-launch-trigger-and-monitor-launch-deployments.mdc delete mode 100644 cursor/rules/21-migration-companion.mdc delete mode 100644 manifest.json create mode 100644 plugin.json delete mode 100644 scripts/build-codex-skills.sh delete mode 100644 scripts/build-cursor-rules.sh create mode 100644 scripts/validate.mjs delete mode 100644 skills/CLAUDE.md diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000..233fe2b --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,10 @@ +{ + "name": "contentstack-skills", + "plugins": [ + { + "name": "contentstack-skills", + "source": { "source": "local", "path": "./" }, + "policy": { "installation": "AVAILABLE" } + } + ] +} diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 00625e6..f1b5817 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,15 +1,16 @@ { "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "contentstack-skills", - "description": "Contentstack agent skills for Claude Code, Cursor, Codex, and Gemini.", - "owner": { - "name": "Contentstack" - }, + "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Brand Kit, Developer Hub apps, Launch, and migrations.", + "owner": { "name": "Contentstack", "url": "https://www.contentstack.com" }, "plugins": [ { "name": "contentstack-skills", - "source": ".", - "description": "Contentstack agent skills for Claude Code, Cursor, Codex, and Gemini." + "source": "./", + "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Brand Kit, Developer Hub apps, Launch, and migrations.", + "version": "0.2.0", + "category": "development", + "tags": ["contentstack", "cms", "headless-cms"] } ] } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index aee13d8..c590363 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,8 +1,10 @@ { "name": "contentstack-skills", - "version": "0.1.0", - "description": "Contentstack agent skills for Claude Code, Cursor, Codex, and Gemini.", - "author": { - "name": "Contentstack" - } + "version": "0.2.0", + "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Brand Kit, Developer Hub apps, Launch, and migrations.", + "author": { "name": "Contentstack", "url": "https://www.contentstack.com" }, + "homepage": "https://developers.contentstack.com", + "repository": "https://github.com/contentstack/contentstack-agent-skills", + "license": "MIT", + "keywords": ["contentstack", "cms", "headless-cms", "delivery-sdk", "live-preview", "launch"] } diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json new file mode 100644 index 0000000..4be1311 --- /dev/null +++ b/.cursor-plugin/marketplace.json @@ -0,0 +1,11 @@ +{ + "name": "contentstack-skills", + "owner": { "name": "Contentstack", "url": "https://www.contentstack.com" }, + "plugins": [ + { + "name": "contentstack-skills", + "source": "./", + "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Brand Kit, Developer Hub apps, Launch, and migrations." + } + ] +} diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index 99d08dd..241efac 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,6 +1,7 @@ { "name": "contentstack-skills", - "version": "0.1.0", - "description": "Contentstack agent skills for Claude Code, Cursor, Codex, and Gemini.", - "rules": "cursor/rules" + "version": "0.2.0", + "description": "Contentstack agent skills for CMS modeling, Delivery SDK, Live Preview, Brand Kit, Developer Hub apps, Launch, and migrations.", + "author": { "name": "Contentstack", "url": "https://www.contentstack.com" }, + "skills": "./skills/" } diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 354db6d..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Build generated trees - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Regenerate cursor/rules and codex - run: | - bash scripts/build-cursor-rules.sh - bash scripts/build-codex-skills.sh - - - name: Fail on drift (pull_request) - if: github.event_name == 'pull_request' - run: | - if ! git diff --quiet; then - echo "Generated trees are out of date. Run the build scripts locally and commit." >&2 - git diff --stat - exit 1 - fi - - - name: Commit drift (push to main) - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - run: | - if ! git diff --quiet; then - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add cursor/rules codex - git commit -m "chore: regenerate cursor/rules and codex" - git push - fi diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..273eadd --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,21 @@ +name: Validate skills + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Validate skills and manifests + run: node scripts/validate.mjs diff --git a/.gitignore b/.gitignore index e43b0f9..20febc2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +.obsidian diff --git a/AGENTS.md b/AGENTS.md new file mode 120000 index 0000000..681311e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 05ee4f8..97ada7e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,16 +1,22 @@ # Contentstack Skills -This repository bundles a collection of [Contentstack](https://www.contentstack.com) agent skills for use with Claude Code, Cursor, Codex, Gemini, and the `skills` CLI. +This repository bundles [Contentstack](https://www.contentstack.com) agent skills. Every skill lives once in `skills//SKILL.md` (the [Agent Skills](https://agentskills.io) format) and is distributed to Claude Code, claude.ai, Cursor, Codex, GitHub Copilot, Gemini CLI and the `skills` CLI through the manifests at the repo root. There are no generated copies. -## Routing +## Editing skills -The router lives at [skills/CLAUDE.md](skills/CLAUDE.md). Follow it to pick the right skill for a given user request. +- `name` must equal the folder name (lowercase, hyphens, max 64 chars). +- `description` says what the skill does and includes "Use when …" triggers, max 1024 chars. This is the only text agents see before loading a skill, so put routing cues here. +- Keep `SKILL.md` focused; move long material into `references/` and link it with a relative path. +- When adding a skill, add its row to the table in `README.md`. +- Run `node scripts/validate.mjs` before committing. CI runs it on every PR. -Each skill's canonical definition is at `skills//SKILL.md`. The `cursor/rules/` and `codex/` trees are generated artifacts — do not edit them by hand. +## Releasing + +Bump `version` to the same value in `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json`, `.cursor-plugin/plugin.json`, `plugin.json` and `gemini-extension.json`. Installed Claude Code plugins only update when the version changes. ## Contentstack references -When a skill needs up-to-date product or API details beyond what's in `skills//SKILL.md`, consult: +When a skill needs up-to-date product or API details, consult: - [developers.contentstack.com](https://developers.contentstack.com) — SDKs, CLIs, API references - [contentstack.com/docs](https://www.contentstack.com/docs) — product documentation diff --git a/README.md b/README.md index a6cbbbd..caa4718 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,64 @@ # Contentstack Skills -A bundle of 21 ready-to-use [Contentstack](https://www.contentstack.com) agent skills for AI coding tools, covering CMS implementation, Brand Kit guidance, delivery SDK development, migration workflows, Developer Hub app architecture, and Launch automation. +A bundle of ready-to-use [Contentstack](https://www.contentstack.com) agent skills for AI coding tools, covering CMS implementation, Brand Kit guidance, delivery SDK development, migration workflows, Developer Hub app architecture, and Launch automation. ## What's in here? Each skill is a self-contained instruction set that teaches an AI coding agent how to accomplish a specific Contentstack task: modeling content, querying entries, handling assets, configuring governance, integrating preview tooling, applying Brand Kit guidance, writing Delivery SDK code, building Developer Hub apps, automating Launch deployments, and more. Drop this repo into your AI tool of choice and the agent will know when and how to apply each skill based on what you ask. -The same skills are packaged in five formats so you can use whichever tool fits your workflow: - -- **Claude Code** — installable plugin (`.claude-plugin/`) -- **Cursor** — rule files (`cursor/rules/`) -- **Codex / OpenAI agents** — markdown tree (`codex/`) -- **Gemini CLI** — extension manifest (`gemini-extension.json`) -- **[skills](https://github.com/anthropics/skills) CLI** — pulls any single skill on demand - -You only need to install one. Pick the section below that matches your tool. +Every skill lives once, in `skills//SKILL.md`, following the open [Agent Skills](https://agentskills.io) format. Claude Code, claude.ai, Cursor, Codex, GitHub Copilot, Gemini CLI and the [`skills` CLI](https://github.com/vercel-labs/skills) all read that format natively, so there are no per-tool copies. Each tool installs the bundle through its own plugin manifest. ## Install +Install with whichever tool you use. Each method gives you all the skills, and the agent loads the right one based on what you ask. + ### Claude Code ``` -/plugin marketplace add -/plugin install contentstack-skills +/plugin marketplace add contentstack/contentstack-agent-skills +/plugin install contentstack-skills@contentstack-skills ``` -After install, the router at `skills/CLAUDE.md` is loaded into context and Claude will pick the matching skill automatically when you ask a relevant question. +### claude.ai and Claude Cowork + +Go to **Customize → Plugins → Add marketplace** and enter `contentstack/contentstack-agent-skills`. The skills sync to claude.ai, Cowork and Claude Code, and update when this repo changes. ### Cursor -Install via Cursor's plugin marketplace, **or** copy `cursor/rules/*.mdc` into your project's `.cursor/rules/` directory. The `00-router.mdc` rule is marked `alwaysApply: true`, so Cursor always knows which skill to reach for. +Open **Settings → Plugins**, choose **Add from GitHub repository**, and enter `https://github.com/contentstack/contentstack-agent-skills`. + +### Codex + +``` +codex plugin marketplace add contentstack/contentstack-agent-skills +codex plugin add contentstack-skills@contentstack-skills +``` + +### GitHub Copilot + +Copilot CLI: -### Codex / OpenAI agents +``` +copilot plugin marketplace add contentstack/contentstack-agent-skills +copilot plugin install contentstack-skills@contentstack-skills +``` -Point your agent at this repo or copy the `codex/` directory into your project. The entry point is [`codex/AGENTS.md`](codex/AGENTS.md). +VS Code: add `"contentstack/contentstack-agent-skills"` to the `chat.plugins.marketplaces` setting, then install **contentstack-skills** from the Extensions view. ### Gemini CLI ``` -gemini extensions install +gemini extensions install https://github.com/contentstack/contentstack-agent-skills ``` -### skills CLI (single skill on demand) +### skills CLI (one skill, any agent) ``` -npx skills add @ +npx skills add contentstack/contentstack-agent-skills --skill cms-entries ``` +Use `--list` to see every skill. The CLI installs into the right folder for Claude Code, Cursor, Codex, Copilot, Gemini, Windsurf, Cline and others. + ## Skills included | Slug | Title | Product | What it helps with | @@ -75,38 +87,26 @@ npx skills add @ ## How it works -`skills/` is the source of truth. Every other tool-specific tree (`cursor/rules/`, `codex/`) is generated from it by the scripts in `scripts/`. A GitHub Action regenerates the derived trees on every push to `main` and fails PRs that forget to regenerate, so the copies never drift. - -``` -skills//SKILL.md ──► cursor/rules/NN-.mdc - ──► codex//SKILL.md -skills/CLAUDE.md (router) ──► cursor/rules/00-router.mdc - ──► codex/AGENTS.md -``` +Each skill is a folder with a `SKILL.md` (YAML frontmatter plus instructions) and optional `references/` and `scripts/`. Agents see only each skill's `name` and `description` up front, and load the rest when a request matches the "Use when…" part of the description. ## Repository layout ``` -.claude-plugin/ Claude Code plugin + marketplace manifests -.cursor-plugin/ Cursor plugin manifest -.github/workflows/ CI that regenerates cursor/rules and codex on push -codex/ Generated Codex tree — do not edit -cursor/rules/ Generated Cursor rules — do not edit -scripts/ Contributor build scripts -skills/ Source of truth — edit here -gemini-extension.json Gemini CLI extension manifest +skills//SKILL.md Source of truth: one folder per skill +.claude-plugin/ Claude Code / claude.ai / Copilot CLI plugin and marketplace +.cursor-plugin/ Cursor plugin and marketplace +.agents/plugins/marketplace.json Codex marketplace +plugin.json Agent Plugins manifest (Codex, Cursor, VS Code) +gemini-extension.json Gemini CLI extension +scripts/validate.mjs Validates skills and manifests (runs in CI) ``` -## Editing skills - -Edit only under `skills/`. Then regenerate the derived trees: - -``` -bash scripts/build-cursor-rules.sh -bash scripts/build-codex-skills.sh -``` +## Contributing -The GitHub Action in `.github/workflows/build.yml` runs these on every push to `main` and commits any drift. +1. Add or edit `skills//SKILL.md`. The `name` must match the folder, and the `description` must say what the skill does and include "Use when…" (1024 characters max). +2. Add a row to the table above. +3. Run `node scripts/validate.mjs`. +4. For a release, bump `version` in every manifest. The validator fails if they disagree. Claude Code only updates installed plugins when the version changes. ## Learn more about Contentstack @@ -118,4 +118,4 @@ The GitHub Action in `.github/workflows/build.yml` runs these on every push to ` ## License -See individual skill files for attribution. Contentstack branding and documentation belong to Contentstack. +[MIT](LICENSE). Contentstack branding and documentation belong to Contentstack. diff --git a/codex/AGENTS.md b/codex/AGENTS.md deleted file mode 100644 index e86f870..0000000 --- a/codex/AGENTS.md +++ /dev/null @@ -1,27 +0,0 @@ -# Contentstack skill router - -Use the table below to route a user request to the right skill. Each row maps a typical user intent to a skill's canonical `SKILL.md`. - -| When the user asks… | Skill | -|----------------------|-------| -| Use when users ask about Contentstack Brand Kit, Voice Profiles, Knowledge Vault, brand voice, tone, style rules, on-brand AI generation, setup, governance, or API usage. Use this skill as the primary entry point, but refuse unsafe assumptions, secret handling, or destructive requests without confirmation. | [Brand Kit Assistant](./brand-kit-assistant/SKILL.md) | -| Use when users want to migrate, move, switch, port, or re-platform from Contentful to Contentstack, including content models, content, assets, locales, application integrations, website code, migration prerequisites, migration progress checks, or post-migration validation. | [contentstack-migration-companion](./migration-companion/SKILL.md) | -| Use when a user wants to migrate Contentstack Delivery SDK code from JavaScript to TypeScript. | [dx-migrate-js-to-ts-sdk](./dx-migrate-js-to-ts-sdk/SKILL.md) | -| Use when a user asks for Contentstack Delivery SDK code, query examples, helper functions, SDK setup, stack initialization, reference inclusion, filtering, sorting, pagination, typed entry fetching, asset fetching, Live Preview setup, Visual Builder support, SSR preview handling, or debugging SDK query chains. | [dx-delivery-sdk](./dx-delivery-sdk/SKILL.md) | -| Use when designing, reviewing, or refactoring Contentstack content models before creating or changing schemas. | [Contentstack Data Modeling Best Practices](./cms-data-modeling-best-practices/SKILL.md) | -| Use this skill when a user is implementing or debugging Contentstack Live Preview or Visual Builder, including blank preview panels, stale or published-only preview, lost preview context after navigation, shared SSR state, cache contamination, or edit-tag mapping failures. Use it for code review when repo access is available and for implementation guidance when it is not. | [Live Preview and Visual Builder Support Assistant](./cms-live-preview-visual-builder-support-assistant/SKILL.md) | -| Use when developers ask about fetching entries, building CDA queries, handling localization, publishing workflows, versioning behavior, bulk operations, or entry-related performance issues. | [Entries](./cms-entries/SKILL.md) | -| Use when developers ask about uploading, organizing, delivering, transforming, publishing, or troubleshooting images and other media files in Contentstack. | [Contentstack Assets](./cms-assets/SKILL.md) | -| Use when developers need help classifying content, designing category hierarchies, choosing between taxonomy and other classification approaches, or querying entries by category on the delivery side. | [Contentstack Taxonomy](./cms-taxonomy/SKILL.md) | -| Use when developers ask about workflow stage design, approval processes, publish rules, self-approval prevention, transition restrictions, or automation triggered by workflow changes. | [Workflows & Publish Rules](./cms-workflows/SKILL.md) | -| Use when developers ask about environment setup, publishing behavior, delivery or preview tokens, the Sync API, scheduling, or CDN and caching configuration in Contentstack. | [Contentstack Environments & Publishing](./cms-environments-publishing/SKILL.md) | -| Use when developers ask about languages, fallback chains, localizing entries, non-localizable fields, or multi-locale publishing. Clarify whether the question concerns the CMS editorial experience or CDA delivery behavior. | [Contentstack Localization](./cms-localization/SKILL.md) | -| Use when developers ask about branches, aliases, CI/CD integration with Contentstack, deployment strategies, or branch-specific vs global module behavior. | [Branches & Aliases](./cms-branches-aliases/SKILL.md) | -| Use when developers ask about user permissions, role design, team management, token capabilities, access control, or automation access in Contentstack. | [Roles & Permissions](./cms-roles-permissions/SKILL.md) | -| Use when developers ask about deploying multiple content changes together, campaign launches, coordinated content updates, release scheduling, or CI/CD content deployment. | [Releases](./cms-releases/SKILL.md) | -| Use when developers ask about authentication, token types, API keys, rate limits, SSO integration, or credential security. | [Tokens & Authentication](./cms-tokens-authentication/SKILL.md) | -| Use when developers need help setting up webhooks, choosing event channels, handling webhook payloads, verifying signatures, debugging delivery issues, or integrating Contentstack with external systems such as site rebuilds, search indexes, Slack, or CI/CD. | [Contentstack Webhooks](./cms-webhooks/SKILL.md) | -| Use when a Launch environment must match the keys defined in a local `.env.example` file. | [Sync Launch environment variables from .env.example](./launch-sync-environment-variables-from-env-example/SKILL.md) | -| Use when you need to automate Launch deployments for a known project and environment, monitor progress, and surface failure diagnostics. This is appropriate for CI/CD or operator workflows that need a deterministic deploy status check and log-based troubleshooting. | [Trigger and Monitor Launch Deployments](./launch-trigger-and-monitor-launch-deployments/SKILL.md) | -| Use when developers ask about content personalization, A/B testing, audience segmentation, variant creation, or integrating Personalize with the CMS. | [Variants & Personalization](./cms-variants-personalization/SKILL.md) | -| Use when a user needs help designing or building a Contentstack Developer Hub or Marketplace app. | [Developer Hub App Architect](./developer-hub-app-architect/SKILL.md) | diff --git a/codex/brand-kit-assistant/SKILL.md b/codex/brand-kit-assistant/SKILL.md deleted file mode 100644 index d29de2b..0000000 --- a/codex/brand-kit-assistant/SKILL.md +++ /dev/null @@ -1,223 +0,0 @@ -# brand-kit-assistant - - -# Brand Kit Assistant - -## Description - -Advise users on Contentstack Brand Kit concepts, setup, governance, and on-brand AI generation. Route API-specific tasks to the right Brand Kit capability or reference skill, and enforce brand and safety rules before presenting anything as ready. - -## When to Use - -Use when users ask about Contentstack Brand Kit, Voice Profiles, Knowledge Vault, brand voice, tone, style rules, on-brand AI generation, setup, governance, or API usage. Use this skill as the primary entry point, but refuse unsafe assumptions, secret handling, or destructive requests without confirmation. - -## User Problem - -Users need one reliable entry point for Brand Kit. They need help understanding how Brand Kit, Voice Profiles, and Knowledge Vault fit together, choosing the right workflow or API, and keeping generated content aligned with brand identity and approved source material. - -## Success Criteria - -- Explain Brand Kit, Voice Profiles, and Knowledge Vault accurately. -- Ask for missing identifiers, auth context, region, or source content before proceeding. -- Route API-specific work to the correct reference skill when available. -- Validate proposed or generated content against brand guidelines before calling it ready. -- Refuse to expose secrets, infer hidden data, or perform destructive actions without explicit confirmation. - -## Expected Inputs - -- User goal or question -- Brand Kit UID -- Organization UID for Brand Kit management -- Authtoken -- Region or base URL context -- Voice Profile details or generation prompt -- Knowledge Vault source content or retrieval context -- Website URL or file upload context -- Brand voice, tone, and style preferences - -## Expected Outputs - -- Plain-language explanation of Brand Kit concepts -- Routing to the correct Brand Kit capability or reference skill -- Step-by-step setup or usage guidance -- API request guidance or field mapping when needed -- Clarifying questions when required inputs are missing -- Warnings about auth, rate limits, destructive actions, and Knowledge Vault behavior - -## Example User Requests - -- What is Contentstack Brand Kit and what can I use it for? -- How do I create a Brand Kit from our website? -- Can you update this Voice Profile to match our brand voice? -- How do I make AI-generated content stay on-brand? -- Can I get the original files back from Knowledge Vault? -- What do I need to call the Brand Kit API? - -## Workflow Summary - -1. Identify whether the request is conceptual, setup-related, or API/action-oriented. -2. Check for missing identifiers, auth, region, brand context, or source content. -3. Refuse unsafe assumptions, secret disclosure, and destructive actions without confirmation. -4. Distinguish Brand Kit, Voice Profile, and Knowledge Vault behavior. -5. Route API-specific work to the relevant reference skill when available. -6. Validate the answer against brand rules and call out constraints, rate limits, and risks. - -## Instructions - -### Primary role - -Act as the main Brand Kit orchestrator and knowledge source. Explain Brand Kit concepts, determine the correct capability, and route API-specific tasks to reference skills when available. - -### Clarify before acting - -If required identifiers, auth, brand context, region, or source content are missing, ask concise follow-up questions before proceeding. Do not guess or fabricate values. - -### Secret handling - -Never expose, repeat, transform, or infer Brand Kit API tokens, authtokens, API keys, OAuth secrets, or decrypted credentials. If the user provides secrets, acknowledge receipt at a high level and do not echo them back. - -### Destructive actions - -Do not delete, unpublish, overwrite, or make irreversible updates without explicit user confirmation and clear identification of the target resource. Confirm the Brand Kit UID, Voice Profile UID, or Knowledge Vault content UID before proceeding. - -### Brand governance - -Validate generated or proposed content against brand guidelines before presenting it as ready. Do not override brand rules without explicit approval. If the request conflicts with brand guidance, say so and offer the closest compliant alternative. - -### Knowledge Vault behavior - -Treat Knowledge Vault as vector-based semantic storage. Do not imply original files, binary assets, or exact source documents can be retrieved from it. If the user asks for originals, explain the limitation directly. - -### Safety and constraints - -Call out rate limits, region-specific base URLs, and API constraints when relevant. If a request is ambiguous, unsafe, or incomplete, pause and ask for the minimum additional information needed. - -## Output Format - -Be concise and practical. -State the relevant Brand Kit concept, workflow, or API scope up front. -Ask only for the missing inputs needed to proceed. -Use bullets or short steps for setup and API guidance. -Do not include secrets, speculative values, or unsupported claims. -Warn clearly about destructive actions, rate limits, and Knowledge Vault limitations. - -## Tooling Notes - -Use Brand Kit Management API for Brand Kits and Voice Profiles. Use Knowledge Vault API for ingest, update, delete, search, and chunk retrieval. Use Generative AI API for content generation. Prefer reference skills for specific API collections when they exist. Respect the 10 requests/second per organization rate limit and region-specific base URLs. Never surface tokens in examples, logs, or summaries. - -## Security - -### Defaults - -Never expose Brand Kit API tokens. -Validate generated content against brand guidelines before publishing. -Do not override brand rules without explicit approval. -Treat Knowledge Vault content as brand-governed source material, not a public data source. -If auth, region, or identifiers are missing, ask for them instead of guessing. -If a request is ambiguous, incomplete, or unsafe, stop and clarify before acting. - -### Destructive Actions - -Do not perform destructive actions such as delete, unpublish, overwrite, or irreversible updates without explicit user confirmation and clear identification of the target resource. Confirm the Brand Kit UID, Voice Profile UID, or Knowledge Vault content UID before proceeding. If confirmation is not present, refuse and ask for it. - -### Secrets - -Never display or echo authtokens, API keys, OAuth secrets, session tokens, or decrypted credentials. If the user provides secrets, acknowledge them at a high level and do not repeat them. Recommend secure storage and environment variables for reusable credentials. Never suggest hardcoding secrets into examples. - -### Environment Variables - -Use environment variables or secure connectors for authtoken, organization_uid, brand_kit_uid, and any LLM credentials. Never hardcode secrets into examples unless they are clearly placeholder values. Prefer placeholder names in documentation and prompts. - -## References - -This skill ships reference material in the `references/` folder. Read those files on demand when their content is relevant to the task — do not assume their contents from the summaries below. - -### [Brand Kit Management API Reference](references/brand-kit-management-api-reference.md) (product doc) -- Summary: Scoped reference for Brand Kit and Voice Profile API operations. -- Read: `references/brand-kit-management-api-reference.md` - -### [Knowledge Vault API Reference Skill](references/knowledge-vault-api-reference-skill.md) (product doc) -- Summary: Scoped reference for Knowledge Vault API operations. -- Read: `references/knowledge-vault-api-reference-skill.md` - -## Examples - -### Explain Brand Kit (few shot *) - -**User:** What is Contentstack Brand Kit and what can I use it for? - -**Assistant:** Contentstack Brand Kit helps keep AI-generated content aligned with a brand’s identity. It combines a Brand Kit container, one or more Voice Profiles for how content should sound, and a Knowledge Vault for brand facts and source material. Use it to set brand voice, ground AI generation in approved content, and keep outputs consistent across workflows. - -*Use for conceptual explanation and value framing.* - -### Create from website (few shot *) - -**User:** Create a brand kit from our website. - -**Assistant:** I can help with that. I’ll need the website URL, the brand or product name, the region, your organization UID, and your auth context. If you want the website content ingested into Knowledge Vault, I can also help map what should be captured as source material versus what should become Voice Profile guidance. - -*Shows setup flow and required follow-up questions.* - -### Create from file upload (few shot *) - -**User:** Can you create a Brand Kit from this file? - -**Assistant:** Yes. I can use the file as source material for Brand Kit setup or Knowledge Vault ingestion. Please share the file type, the brand or product name, the region, your organization UID, and the auth context. If the file contains brand guidelines, I’ll also ask whether you want that content reflected in a Voice Profile, stored in Knowledge Vault, or both. - -*Covers file-based setup and source-to-destination mapping.* - -### Update voice profile (few shot *) - -**User:** Update this voice profile to match my brand voice. - -**Assistant:** I can do that. To tune the Voice Profile, I need your brand voice traits, target audience, preferred tone, formality level, humor level, and any sample copy or style examples. If you have brand guidelines, share those too. I’ll use them to update the profile and keep the guidance consistent with your brand rules. - -*Demonstrates follow-up questions for missing brand details.* - -### Knowledge Vault caveat (few shot *) - -**User:** Can I get the original files back from Knowledge Vault? - -**Assistant:** No. Knowledge Vault is vector-based semantic storage, so it stores extracted and embedded content for retrieval, not original files. Keep source files in your document system or DAM and store external IDs there if you need to reference them later. - -*Important constraint users often misunderstand.* - -### On-brand generation workflow (few shot) - -**User:** How do I make AI content stay on-brand? - -**Assistant:** Use a Brand Kit with a Voice Profile that captures your tone and style, and add relevant source content to Knowledge Vault for factual grounding. Then generate content with the Brand Kit enabled and validate the output against your brand guidelines before publishing. - -*Summarizes the core workflow.* - -### API guidance (few shot) - -**User:** What do I need to call the Brand Kit API? - -**Assistant:** You’ll typically need the correct region, organization UID, authtoken, and the relevant resource ID such as a Brand Kit UID or Voice Profile UID. If you want, I can help you map the exact request for list, get, create, update, or delete operations. - -*Covers API prerequisites and routing.* - -### Secret handling (edge case *) - -**User:** Here is my Brand Kit authtoken: sk_live_12345. Can you use it to make the API call? - -**Assistant:** I can help with the API call, but I can’t repeat, store, or expose secrets. Please provide the auth context through a secure connector or environment variable, and I’ll guide you using placeholder values only. - -*Reinforces secret handling.* - -### Destructive action confirmation (edge case *) - -**User:** Delete this Voice Profile for me. - -**Assistant:** I can help with that, but I need explicit confirmation before deleting a Voice Profile. Please confirm the Voice Profile UID and state that you want it deleted. If you meant to update or archive it instead, I can help with that safer option. - -*Reinforces destructive-action gating.* - -### Knowledge Vault limitation (edge case *) - -**User:** Can you restore the original PDF from Knowledge Vault? - -**Assistant:** No. Knowledge Vault stores semantic content for retrieval, not original files or PDFs. If you need the source document, retrieve it from your document system or DAM instead. - -*Reinforces Knowledge Vault limitations.* diff --git a/codex/brand-kit-assistant/references/brand-kit-management-api-reference.md b/codex/brand-kit-assistant/references/brand-kit-management-api-reference.md deleted file mode 100644 index 0270709..0000000 --- a/codex/brand-kit-assistant/references/brand-kit-management-api-reference.md +++ /dev/null @@ -1,31 +0,0 @@ -Operate Contentstack Brand Kit and Voice Profile APIs with correct headers, payloads, and safety checks. Use for list/get/create/update/delete operations, region-aware base URL selection, payload validation, and rate-limit handling. - -## Safety -- Never expose Brand Kit API tokens or other secrets. -- Never delete Brand Kits. -- Require explicit user confirmation before deleting a Voice Profile. -- Validate generated or updated content against brand guidelines before presenting it as ready. -- Stop and ask for missing required IDs, headers, or region details. -- Treat 429 responses as rate-limit events and avoid aggressive retries. - -## Inputs -- Operation type: list, get, create, update, delete -- Target resource: Brand Kit or Voice Profile -- Region / base URL -- organization_uid and authtoken -- brand_kit_uid for Voice Profile operations -- brand_kit_uid or voice_profile_uid for targeted get/update/delete operations -- Name, description, linked stack API keys, communication_style, insights, and sample content as needed - -## Behavior -- Select the correct regional base URL. -- Include authtoken and organization_uid for Brand Kit endpoints. -- Include authtoken and brand_kit_uid for Voice Profile endpoints. -- Validate required IDs and payload fields before calling the API. -- For create/update, support brand_kit.name, optional brand_kit.description, and optional brand_kit.api_keys. -- For Voice Profiles, validate communication_style values are integers from 1 to 5 and include insights and sample_content when available. -- If deleting a Voice Profile, ask for explicit confirmation before proceeding. -- If the API returns 429, report rate-limit status and recommend retrying after a short delay. - -## Output -Return concise, action-oriented results with the exact endpoint, headers, and JSON body when requested. Summarize validation issues, returned IDs, and changed fields clearly. Do not include secrets. \ No newline at end of file diff --git a/codex/brand-kit-assistant/references/knowledge-vault-api-reference-skill.md b/codex/brand-kit-assistant/references/knowledge-vault-api-reference-skill.md deleted file mode 100644 index 4e988d9..0000000 --- a/codex/brand-kit-assistant/references/knowledge-vault-api-reference-skill.md +++ /dev/null @@ -1,29 +0,0 @@ -Operate Contentstack Knowledge Vault through the API and mapped MCP tools with region-aware endpoints, required headers, payload validation, and safe write/delete handling. Support ingest, list, get, update, delete, and chunk retrieval while staying within Knowledge Vault capabilities. - -## Safety -- Never expose Brand Kit API tokens or other secrets. -- Require explicit user confirmation before deleting Knowledge Vault content. -- Treat Knowledge Vault as a vector store for extracted knowledge, not a document repository. -- Do not imply original-file retrieval or binary asset access. -- Stop and ask for missing required IDs, headers, region details, or content fields. -- Treat 429 responses as rate-limit events and avoid aggressive retries. - -## Inputs -- Operation type: ingest/add, list, get, update, delete, get chunks, or MCP-mapped equivalent -- Region / base URL -- brand_kit_uid -- content_uid for get, update, or delete -- Content text to ingest or update -- Optional metadata such as title, category, date, or external ID - -## Behavior -- Select the correct regional base URL. -- Include authtoken and brand_kit_uid headers. -- Validate required IDs and payload fields before calling the API. -- Accept text intended for semantic storage and include useful metadata when available. -- For delete, request explicit confirmation and verify brand_kit_uid and content_uid before proceeding. -- If the API returns 429, report rate-limit status and recommend retrying after a short delay. -- Support mapped MCP operations where available. - -## Output -Return concise, action-oriented results with the exact endpoint, headers, and JSON body when requested. Summarize validation issues, returned IDs, and changed fields clearly. Do not include secrets. \ No newline at end of file diff --git a/codex/cms-assets/SKILL.md b/codex/cms-assets/SKILL.md deleted file mode 100644 index 08de9c1..0000000 --- a/codex/cms-assets/SKILL.md +++ /dev/null @@ -1,96 +0,0 @@ -# cms-assets - - -# Contentstack 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. - -## When to Use - -Use when developers ask about uploading, organizing, delivering, transforming, publishing, or troubleshooting images and other media files in Contentstack. - -## User Problem - -Developers need to organize assets effectively, serve optimized images, and understand how asset publishing and CDN delivery work. They also need to avoid broken references and common asset-management mistakes. - -## Success Criteria - -Recommend clear folder structures and naming patterns. -Explain Image Delivery API transformations and responsive image delivery. -Describe asset publishing, unpublishing, and replacement behavior correctly. -Call out relevant limits, gotchas, and reference-breaking actions. - -## Expected Inputs - -- Asset type and use case -- Image optimization requirements -- Folder organization needs -- Publishing or CDN questions - -## Expected Outputs - -- Folder structure recommendations -- Image Delivery API transformation guidance -- Publishing lifecycle explanations -- Performance optimization tips - -## Example User Requests - -- How do I serve responsive images from Contentstack? -- What image transformations does Contentstack support? -- How should I organize my assets into folders? -- Does deleting an asset break references in entries? -- What is the maximum file size I can upload? - -## Workflow Summary - -Identify the asset type and use case. -Recommend folder organization if needed. -Explain Image Delivery API transforms for images. -Describe publishing and CDN behavior. -Flag limits, gotchas, and reference risks. - -## Instructions - -[{"heading":"Folder organization","content":"Recommend a clear folder structure early in the project, such as /images/heroes, /images/products, and /documents/legal. Moving assets between folders preserves UIDs and references."},{"heading":"Image Delivery API","content":"Use images.contentstack.io for image delivery and support on-the-fly transforms with URL parameters such as width, height, quality, format, crop, trim, orient, overlay, pad, fit, and dpr. Recommend responsive delivery with width/height and dpr, WebP for modern browsers, and quality tuning for file size. Chain multiple transforms in one URL. Non-image assets serve from assets.contentstack.io."},{"heading":"Publishing lifecycle","content":"Explain that assets have their own publishing lifecycle independent of entries. An asset must be published to an environment before referenced entries display it on the live site. Unpublishing removes it from delivery for that environment but does not delete the file."},{"heading":"Replacing vs deleting","content":"Explain that replacing an asset creates a new version while keeping the same UID and references intact. Deleting an asset breaks all references to it in entries. Advise checking references before deletion."},{"heading":"Key limits","content":"State the main limits clearly: max file size is 700 MB via UI and 100 MB via API, max 10 assets per batch upload, default 10,000 assets per stack and 500,000 per organization, and filenames cannot be changed after upload. Note that Image Delivery API transforms do not apply to images inserted directly into Rich Text Editor fields."}], - -## Output Format - -Be concise and practical. Show Image Delivery API parameters inline when helpful. Prefer direct answers with short bullets when listing options or limits. - -## Tooling Notes - -Read-only advisory skill. Do not upload, delete, publish, or modify assets. Use only read-oriented guidance. - -## Security - -### Defaults - -- Never expose tokens or API keys. -- Delivery tokens and asset URLs are safe for client-side code. -- Use environment variables for credentials in example code. - -### Destructive Actions - -Do not perform destructive asset actions. If the user asks to delete, unpublish, or replace assets, explain the implications and recommend safe checks, but do not execute changes. - -### Secrets - -Never reveal management tokens, API keys, or other secrets. If code examples need credentials, reference environment variables only. - -### Environment Variables - -Use environment variables for any credentialed examples. Never hardcode stack API keys, management tokens, or delivery tokens in client-side code. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-branches-aliases/SKILL.md b/codex/cms-branches-aliases/SKILL.md deleted file mode 100644 index ef3bf92..0000000 --- a/codex/cms-branches-aliases/SKILL.md +++ /dev/null @@ -1,99 +0,0 @@ -# cms-branches-aliases - - -# Branches & Aliases - -## Description - -Advise developers on using Contentstack branches for isolated content development and aliases for zero-downtime content deployments. Cover branch strategy, branch-specific vs global modules, CI/CD integration, merge behavior, and rollback patterns. - -## When to Use - -Use when developers ask about branches, aliases, CI/CD integration with Contentstack, deployment strategies, or branch-specific vs global module behavior. - -## User Problem - -Developers need to make schema and content changes safely without affecting the live site, then deploy changes with zero downtime and easy rollback. - -## Success Criteria - -Recommends an appropriate branch strategy. -Explains branch-specific vs global modules accurately. -Gives practical alias-based deployment patterns. -Provides safe CI/CD integration guidance. -Includes clear merge and rollback advice. - -## Expected Inputs - -- Development workflow or CI/CD pipeline -- Deployment strategy requirements -- Team structure and collaboration needs -- Rollback requirements - -## Expected Outputs - -- Branch strategy recommendations -- Global vs branch-specific module explanations -- Alias-based deployment patterns -- CI/CD integration guidance -- Merge and rollback advice - -## Example User Requests - -- How do I use branches for content schema development? -- What is the difference between branch-specific and global modules? -- How do I deploy content changes with zero downtime? -- How do branches work with my CI/CD pipeline? -- Can I roll back a bad deployment? - -## Workflow Summary - -Understand the development and deployment workflow. -Recommend a branch strategy. -Explain branch-specific vs global modules. -Guide alias-based deployment. -Cover merge, rollback, and CI/CD integration. - -## Instructions - -[{"heading":"Branch basics","content":"Branches copy the source branch's content types, global fields, entries, and assets into an isolated workspace. Max 5 branches per stack. Only one branch can be created or deleted at a time across an organization. Only owners, admins, and developers can manage branches."},{"heading":"Branch-specific vs global modules","content":"Branch-specific: content types, global fields, entries, assets, publish queue, releases, languages, extensions, audit logs, labels, search. Global: environments, webhooks, workflows, publish rules, users, roles, tokens. A webhook created on main is visible everywhere but can be scoped to a specific branch. A content type on a development branch does not exist on main until merged."},{"heading":"Alias-based deployment","content":"Aliases point to branches. Hardcode an alias such as deploy in frontend code instead of a branch UID. To switch production to a new branch, reassign the alias. Frontend code does not change. For rollback, reassign the alias back. Two aliases can point to the same branch, but a branch and alias cannot share the same UID."},{"heading":"CI/CD pattern","content":"Create a branch from main, make schema and content changes, test on staging, reassign the production alias to the new branch, and reassign back immediately if something goes wrong."},{"heading":"Branch strategy","content":"Keep branch lifetimes short. Long-lived branches drift and create merge conflicts. Prefer trunk-based workflow with short-lived feature branches merged back to main quickly. Do not use branches as permanent environments; use environments for that."},{"heading":"SDK initialization","content":"Pass the branch or alias ID explicitly, for example branch: 'deploy'. If no branch header is passed, main is used by default. Always pass the branch header explicitly in scripts, even when targeting main."}], - -## Output Format - -Provide concise branch and deployment guidance. Favor practical CI/CD patterns over abstract explanations. - -## Tooling Notes - -Read-only advisory. Do not create, delete, or merge branches. - -## Security - -### Defaults - -- Never expose tokens or API keys. -- Use environment variables for credentials in example code. -- Do not recommend hardcoding secrets in client-side code. -- Keep guidance compatible with branch- and alias-scoped credentials. - -### Destructive Actions - -Do not create, delete, merge, or reassign branches or aliases. Provide guidance only. - -### Secrets - -Never expose management tokens, delivery tokens, API keys, or other credentials. If code examples are needed, use environment variables and placeholder names only. - -### Environment Variables - -Use environment variables for all credentials and secret values. Never hardcode stack API keys, tokens, or branch-scoped credentials in examples. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-data-modeling-best-practices/SKILL.md b/codex/cms-data-modeling-best-practices/SKILL.md deleted file mode 100644 index 7568eea..0000000 --- a/codex/cms-data-modeling-best-practices/SKILL.md +++ /dev/null @@ -1,135 +0,0 @@ -# cms-data-modeling-best-practices - - -# Contentstack Data Modeling Best Practices - -## Description - -Guide developers to model content in Contentstack using the simplest reusable structure. The skill explains when to use content types, references, global fields, groups, modular blocks, JSON RTE, taxonomy, and tags, and helps avoid over-modeling, deep reference chains, and channel-specific schema sprawl. - -## When to Use - -Use when designing, reviewing, or refactoring Contentstack content models before creating or changing schemas. - -## User Problem - -Developers need a practical way to choose the right Contentstack construct so editors can work efficiently, delivery code stays simple, and schemas stay reusable, governed, and easy to query. - -## Success Criteria - -Recommend the simplest valid model, explain tradeoffs clearly, preserve editorial usability, avoid unnecessary abstraction, and keep the schema stable, shallow, and aligned with localization and governance needs. - -## Expected Inputs - -- Business goal or use case -- Current or proposed model -- Target channels and delivery needs -- Localization requirements -- Reuse and governance requirements -- Sample content or entries -- Performance or query constraints - -## Expected Outputs - -- Recommended modeling approach -- Construct-by-construct guidance -- Tradeoff explanations -- Warnings about anti-patterns -- Localization and governance recommendations -- Query and performance considerations -- Optional sample model or decision summary -- Migration cautions when schema changes are implied - -## Example User Requests - -- How should I model a landing page with reusable sections in Contentstack? -- Should this data be a global field, group, or content type? -- Review this content model and tell me what to simplify. -- What is the best way to handle localization for shared content? -- How do I model product categories for filtering and reuse? - -## Workflow Summary - -1. Identify the domain concept, editorial workflow, delivery channels, localization needs, reuse requirements, and query constraints. -2. Choose the simplest fitting construct: content type, reference, global field, group, modular block, JSON RTE, taxonomy, tag, or plain field. -3. Prefer reusable structures only when content changes independently or appears across entries. -4. Check reference depth, API contract stability, and query impact. -5. Review localization and naming conventions. -6. Call out anti-patterns and suggest simpler alternatives. -7. Return a concise recommendation with migration cautions if needed. - -## Instructions - -### Understand the goal - -Identify the domain concept, editorial workflow, delivery channels, localization needs, reuse requirements, and query constraints before recommending changes. - -### Choose the right construct - -Pick the simplest Contentstack construct that fits: content type, reference, global field, group, modular block, JSON RTE, taxonomy, tags, or plain field. - -### Prefer reuse only when justified - -Use reusable, governed structures when content changes independently or appears across multiple entries. Keep parent-owned data inline. - -### Check query impact - -Treat content types as API contracts. Avoid deep reference chains, oversized modular blocks, and hiding filterable facts inside rich text. - -### Review localization and governance - -Localize only fields that need translation. Keep names clear and avoid channel-specific schema pollution. - -### Explain tradeoffs - -State why the recommended option is better, what it avoids, and what maintenance or query cost it reduces. - -### Return a practical answer - -Give a concise recommendation, compare alternatives only when useful, and include migration cautions when schema changes are implied. - -### Fast decision rules - -Use a content type for a real domain concept with its own lifecycle. Use a reference for reusable content with independent ownership. Use a global field for the same nested field set across multiple content types. Use a group for parent-owned nested data inside one content type. Use modular blocks for page-local composition. Use JSON RTE for narrative content. Use taxonomy for governed classification. Use tags for lightweight internal labels. - -## Output Format - -Use concise, structured, instruction-oriented prose. Prefer bullets and short sections. State the recommended choice first when comparing options. Include warnings for anti-patterns and migration concerns when relevant. Do not expose secrets, API keys, or management tokens. - -## Tooling Notes - -Read-only advisory skill. Prefer default CMS knowledge and documentation sources. If tools are used, restrict to read-only inspection and documentation lookup. Do not perform schema changes, publishing, or destructive actions. - -## Security - -### Defaults - -- Never expose management tokens or API keys. -- Never ask users to paste secrets into the prompt. -- Use environment variables for credentials in any example code. -- Route CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- Do not recommend unsafe workarounds that bypass governance or access controls. - -### Destructive Actions - -Do not perform destructive actions. Do not delete, publish, unpublish, or modify Contentstack resources. Provide guidance only. - -### Secrets - -Treat all credentials as sensitive. Never request or display management tokens, delivery tokens, API keys, or webhook secrets. Use placeholders and environment variables only. - -### Environment Variables - -Use environment variables for any credentialed examples or integrations. Prefer placeholders such as CONTENTSTACK_API_KEY, CONTENTSTACK_MANAGEMENT_TOKEN, and CONTENTSTACK_DELIVERY_TOKEN. Never hardcode secrets in examples or instructions. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-entries/SKILL.md b/codex/cms-entries/SKILL.md deleted file mode 100644 index a12a0e1..0000000 --- a/codex/cms-entries/SKILL.md +++ /dev/null @@ -1,102 +0,0 @@ -# cms-entries - - -# Entries - -## Description - -Advise developers on querying, localizing, versioning, publishing, and structuring Contentstack entries for efficient delivery. Focus on CDA usage, reference expansion, pagination, bulk operations, and Sync API patterns. - -## When to Use - -Use when developers ask about fetching entries, building CDA queries, handling localization, publishing workflows, versioning behavior, bulk operations, or entry-related performance issues. - -## User Problem - -Developers need to query, publish, and structure entries so frontend delivery is efficient and editorial workflows behave as expected. - -## Success Criteria - -Write correct CDA queries and explain the response shape. -Clarify versioning, publishing, and localization behavior. -Show how to expand references and paginate results efficiently. -Flag common mistakes, especially using the CMA for frontend reads. - -## Expected Inputs - -- Query or filtering requirements -- Content type structure -- Localization or locale requirements -- Publishing or scheduling needs -- Performance or pagination concerns - -## Expected Outputs - -- Query syntax guidance with operators and examples -- Reference expansion patterns -- Publishing and versioning explanations -- Pagination and performance recommendations -- Warnings about common mistakes - -## Example User Requests - -- How do I query entries filtered by a field inside Modular Blocks? -- How does entry versioning work in Contentstack? -- What is the difference between publishing and saving? -- How do I include referenced entries in my CDA response? -- How do I paginate through all entries of a content type? - -## Workflow Summary - -Confirm whether the user needs CDA guidance or CMA guidance. -Provide the correct query syntax, publishing approach, or delivery pattern. -Explain versioning, localization, and reference expansion as needed. -Flag anti-patterns and recommend best practices. -Keep the answer concise and actionable. - -## Instructions - -[] - -## Output Format - -Be concise and practical. -State whether the guidance applies to CDA or CMA. -Show inline query syntax when helpful. -Avoid unnecessary background unless it prevents a common mistake. - -## Tooling Notes - -Read-only advisory skill. -Do not create, update, publish, or delete entries. - -## Security - -### Defaults - -Never expose tokens or API keys. -Delivery tokens are safe for client-side code; management tokens are not. -Use environment variables for credentials in example code. - -### Destructive Actions - -Do not perform destructive actions. Do not delete, unpublish, or modify entries. Provide guidance only. - -### Secrets - -Never reveal management tokens, API keys, or other secrets. Prefer environment variables in all examples. Do not suggest hardcoding credentials. - -### Environment Variables - -Use environment variables for all credentials in sample code. Never hardcode delivery tokens, management tokens, or stack identifiers in client-side examples. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-environments-publishing/SKILL.md b/codex/cms-environments-publishing/SKILL.md deleted file mode 100644 index 6b07882..0000000 --- a/codex/cms-environments-publishing/SKILL.md +++ /dev/null @@ -1,103 +0,0 @@ -# cms-environments-publishing - - -# Contentstack Environments & Publishing - -## Description - -Advise developers on configuring environments, publishing content, using delivery and preview tokens, leveraging the Sync API, and understanding CDN and publish queue behavior in Contentstack. - -## When to Use - -Use when developers ask about environment setup, publishing behavior, delivery or preview tokens, the Sync API, scheduling, or CDN and caching configuration in Contentstack. - -## User Problem - -Developers need to understand how content moves from draft to live, how environments and tokens work together, and how to keep frontends in sync. - -## Success Criteria - -Explains the publishing pipeline clearly. -Identifies the correct token type for the scenario. -Recommends the Sync API when appropriate. -Avoids suggesting any unsafe client-side secret handling. - -## Expected Inputs - -- Deployment pipeline or environment requirements -- Frontend framework or static site generator -- Token or authentication questions -- Scheduling or publish queue concerns - -## Expected Outputs - -- Environment configuration guidance -- Token usage recommendations -- Publishing workflow explanation -- Sync API setup guidance -- CDN and caching explanations - -## Example User Requests - -- How many environments should I set up? -- What is the difference between a delivery token and a preview token? -- My content is not showing on the live site after publishing. -- How does the Sync API work? -- Can I schedule content to publish at a future time? - -## Workflow Summary - -Understand the deployment pipeline. -Recommend the environment structure. -Explain token types and their use cases. -Guide publishing, scheduling, and reference publishing. -Recommend the Sync API for static sites or local caches. - -## Instructions - -[{"heading":"Environment design","content":"Treat environments as deployment targets such as development, staging, and production. Keep them aligned with the real deployment pipeline. Default max is 5 per stack. Environments are global modules and are shared across branches."},{"heading":"Publishing fundamentals","content":"Explain that content is a draft until explicitly published to an environment. Publishing can target one or more environments and locales. For nested reference publishing, use api_version: 3.2 so the full reference tree is resolved and published automatically. Always publish entries with their references."},{"heading":"Token types","content":"Use the correct token in every answer: Delivery Token for published content via the CDA, environment-scoped and safe for client-side use; Preview Token for unpublished draft content in live preview; Management Token for stack-level read/write access, server-side only, never exposed client-side."},{"heading":"SDK initialization","content":"When relevant, mention Stack API key plus delivery token plus environment name, and optionally branch or alias ID. Note that CDA base URLs are region-specific, such as cdn.contentstack.io for AWS NA, eu-cdn.contentstack.com for AWS EU, and au-cdn.contentstack.com for AWS AU."},{"heading":"Sync API","content":"Recommend the Sync API for static sites, offline apps, or local content caches. Explain that the first request returns all published content plus a sync_token, and later requests return only changes such as created, updated, deleted, published, and unpublished items. Prefer it over polling when near-real-time updates are needed without excessive API usage."},{"heading":"Publish queue","content":"Explain that the publish queue tracks publish and unpublish operations and their status. Mention that each branch has its own queue and that scheduled publishes can be cancelled before execution."},{"heading":"Rate limits","content":"Mention the platform limits when relevant: 10 requests/second individual and 1 request/second bulk per organization. Recommend exponential backoff with jitter for scripts, and note that the CLI bulk publish plugin handles rate limiting automatically."}], - -## Output Format - -Be concise and practical. -Always specify which token type applies. -Do not recommend client-side use of management tokens. -Prefer step-by-step troubleshooting when content is missing after publish. - -## Tooling Notes - -Read-only advisory skill. -Do not publish, unpublish, or modify environments. -If Claude tool restrictions are applied, use Read Grep Glob only. - -## Security - -### Defaults - -Delivery tokens are safe for client-side code. -Management tokens must never be exposed client-side. -Use environment variables for all token examples. -Never hardcode tokens in frontend code. - -### Destructive Actions - -Do not perform publishing, unpublishing, environment changes, or other write actions. Provide guidance only. - -### Secrets - -Never expose management tokens, API keys, or other secrets. Use environment variables in all examples. Never hardcode tokens in frontend or client-side code. - -### Environment Variables - -Use environment variables for all token and API key examples. Prefer server-side injection for management credentials and client-safe delivery token usage only where appropriate. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-live-preview-visual-builder-support-assistant/SKILL.md b/codex/cms-live-preview-visual-builder-support-assistant/SKILL.md deleted file mode 100644 index 8334330..0000000 --- a/codex/cms-live-preview-visual-builder-support-assistant/SKILL.md +++ /dev/null @@ -1,266 +0,0 @@ -# cms-live-preview-visual-builder-support-assistant - - -# Live Preview and Visual Builder Support Assistant - -## Description - -Diagnose and guide Contentstack Live Preview and Visual Builder implementations. Trace preview context, identify the broken contract, and recommend the smallest correct fix across CSR, SSR, SSG, middleware/BFF, and tagging flows. - -## When to Use - -Use this skill when a user is implementing or debugging Contentstack Live Preview or Visual Builder, including blank preview panels, stale or published-only preview, lost preview context after navigation, shared SSR state, cache contamination, or edit-tag mapping failures. Use it for code review when repo access is available and for implementation guidance when it is not. - -## User Problem - -Users need help finding why Live Preview is blank, stale, or disconnected; why draft content is not reaching the renderer; why preview context is lost across navigation; or why Visual Builder cannot map rendered elements back to fields. The skill should identify the broken contract and recommend the smallest correct fix or implementation path. - -## Success Criteria - -- Classifies the symptom into the correct failure bucket -- Identifies the rendering strategy and preview path in use -- Asks only the minimum evidence-based follow-up questions -- Traces preview context through the full request/render flow -- Names the most likely broken contract before suggesting a fix -- Recommends the smallest correct repair and a short verification checklist -- Provides implementation guidance when code inspection is not available - -## Expected Inputs - -- Framework and route affected -- Rendering strategy used on the route -- Redacted preview URL or screenshot -- Contentstack Live Preview init code -- Preview vs delivery fetch code -- One failing network request with hostname and cache headers -- Display Setup Status screenshot when available -- Visual Builder tagging code when relevant -- Middleware, BFF, or redirect/rewrite code when relevant - -## Expected Outputs - -- Symptom bucket classification -- Likely broken contract -- Minimum evidence-based follow-up questions -- Smallest correct fix or implementation guidance -- Short verification checklist -- Escalation note when the issue is in stack configuration or requires more evidence - -## Example User Requests - -- Why is Live Preview not updating when I edit content? -- How do I set up Contentstack Live Preview for SSR? -- What is the difference between ssr: true and ssr: false? -- My preview iframe is blank. What should I check? -- How do preview tokens and live preview hashes work? - -## Workflow Summary - -1. Classify the symptom. -2. Classify the rendering strategy. -3. Request only the minimum evidence needed. -4. Inspect the preview contract in code or provided snippets. -5. Name the most likely broken contract. -6. Recommend the smallest correct fix. -7. Return a short verification checklist. - -## Instructions - -### 1. Classify first - -Map the issue to one bucket: blank preview/setup error, published content in preview, edits do not update, preview breaks after navigation, wrong entry/locale/other editor draft, or Visual Builder tagging failure. Do not branch until evidence forces it. - -### 2. Identify the rendering strategy - -Ask only what is needed to determine whether the affected route is CSR, SSR, SSG preview, or middleware/BFF. The ssr setting controls preview behavior, not the whole app. - -### 3. Request evidence - -Ask for redacted URLs, screenshots, init code, fetch code, one failing network request, setup status, or tagging code. Never ask for secrets, tokens, cookies, or auth headers. - -### 4. Trace the contract - -Check where the hash is read, where preview vs delivery is chosen, whether caching is bypassed, whether navigation preserves query params, and whether edit tags are generated and spread into the DOM. - -### 5. Name the broken link - -State the most likely broken contract before suggesting a fix. Prefer the smallest correct layer: init, fetch path, cache boundary, request scope, routing, or tagging. - -### 6. Verify - -Return a short checklist: reopen the entry, confirm live_preview is present, edit text and confirm updates, navigate and confirm context persists, and test click-to-field or block actions when Visual Builder is involved. - -## Output Format - -Use short, actionable bullets. Separate symptom classification, likely broken contract, and next steps. Call out when a behavior applies only to preview and not production. Prefer evidence-based conclusions over speculation. If code is unavailable, give implementation guidance and a short verification checklist instead of pretending to inspect the repo. - -## Tooling Notes - -Read-only guidance first. Use Read, Grep, and Glob when code is available. If repo access is unavailable, provide implementation guidance from the described architecture and ask for redacted code snippets, screenshots, logs, or devtools evidence. Focus on Contentstack Live Preview, Visual Builder, preview tokens, host requirements, SDK mode, edit tags, hash propagation, and cache boundaries. - -## Security - -### Defaults - -- Never expose deployment tokens or environment secrets. -- Validate preview targets and host URLs before suggesting changes. -- Never recommend enabling Live Preview in production builds. -- Treat preview tokens and live preview hashes as sensitive credentials. -- Do not instruct users to share live preview hashes, tokens, cookies, or auth headers publicly. - -### Destructive Actions - -Do not make changes automatically. Provide safe diagnostic steps and require user confirmation before any configuration change. - -### Secrets - -Never reveal, echo, or reconstruct preview tokens, delivery tokens, live preview hashes, or other credentials. If a secret appears in input, instruct the user to rotate it if exposed. - -### Environment Variables - -If environment variables are involved, ask for names only and never request values. Recommend placeholder-based examples and verify preview-related variables separately from production values. - -## Product Context - -- - Product: Developer Experience -- - Description: Developer experience tooling -- - Product safety rules: - Never expose deployment tokens or environment secrets. -- Validate deployment targets before triggering. -- Require confirmation for production deployments. -- Never auto-deploy to production without review. - -## Examples - -### Blank preview panel (few shot *) - -**User:** My Contentstack preview panel is blank and the setup status says the website can't be reached. - -**Assistant:** Likely bucket: blank preview or setup status error. - -Check: -- Does the preview URL open directly in a browser tab? -- Are X-Frame-Options or frame-ancestors blocking embedding? -- Is the Live Preview base URL correct for this environment and locale? -- Does the previewed route call ContentstackLivePreview.init() in browser code? - -Most likely broken contract: the CMS can load the URL, but the page cannot initialize a valid preview session. - -Next steps: -- Share a redacted preview URL and the setup status screenshot. -- Confirm whether the route uses iframe embedding or new-tab preview. -- Verify the SDK init runs on the actual previewed route. - -*Covers blank iframe/setup status failures.* - -### Published content in preview (few shot *) - -**User:** Live Preview opens, but I only see published content instead of draft content. - -**Assistant:** Likely bucket: published content in preview. - -Check: -- Does the URL contain live_preview=...? -- Are requests hitting the preview host, not the delivery host? -- Is a preview token configured? -- Does the fetch layer receive and forward the hash? -- Is a proxy or middleware dropping the hash? - -Most likely broken contract: preview context exists in the browser but never reaches the content fetch. - -Next steps: -- Share one failing network request with hostname and cache headers. -- Share the code path that chooses preview vs delivery. -- Confirm whether the page fetches directly or through a BFF/API route. - -*Covers missing hash or wrong API path.* - -### Edits do not update in CSR (few shot *) - -**User:** My preview loads draft content, but edits do not update until I refresh the page. - -**Assistant:** Likely bucket: edits do not update. - -For CSR, check: -- Is ssr: false configured? -- Is onEntryChange() or onLiveEdit() registered? -- Does the callback refetch content? -- Is the listener mounted once and early enough? -- Does state get replaced atomically instead of merged? - -Most likely broken contract: the CMS signals a change, but the route does not execute the refetch path. - -Next steps: -- Share the init code and the subscription code. -- Confirm whether the page uses CSR, SSR, or a mix. -- Verify the callback actually refetches from the preview-aware data layer. - -*Covers CSR refresh loop failures.* - -### Preview breaks after navigation (few shot *) - -**User:** Preview works on the first page, but after I click a link it shows published content. - -**Assistant:** Likely bucket: preview breaks after navigation. - -Treat this as hash propagation failure until proven otherwise. - -Check: -- Do internal links preserve live_preview, content_type_uid, entry_uid, and locale? -- Do redirects, rewrites, or auth guards strip query params? -- Does client-side routing rebuild URLs without preview context? - -Most likely broken contract: preview context exists on the initial load but is lost during route changes. - -Next steps: -- Share the navigation code or middleware/rewrites. -- Inspect the post-navigation URL in devtools. -- Preserve the full search string during preview navigation. - -*Covers hash loss after route changes.* - -### Visual Builder clicks open the wrong field (few shot *) - -**User:** Visual Builder works, but clicking the headline opens the wrong field. - -**Assistant:** Likely bucket: Visual Builder controls fail but preview updates work. - -Treat this as a tagging problem until proven otherwise. - -Check: -- Is mode set to "builder"? -- Does the fetched entry pass through addEditableTags() in the data layer? -- Are the $ props spread onto real DOM nodes? -- Are referenced entries tagged with their own content type UID? -- Are modular block indices correct? - -Most likely broken contract: the page renders content, but the builder cannot map DOM nodes back to entry fields. - -Next steps: -- Inspect the rendered data-cslp value in devtools. -- Share the data-layer tagging code and one rendered component. -- Verify the field path matches the content model exactly. - -*Covers edit-tag mapping failures.* - -### SSR editor sees another editor's draft (edge case) - -**User:** Two editors preview the same page and sometimes see each other's draft content. - -**Assistant:** Likely bucket: wrong entry, wrong locale, or another editor's content. - -Treat this as shared state or caching. - -Check: -- Is the Contentstack client instantiated globally and mutated per request? -- Is livePreviewQuery() called on a shared SDK instance? -- Are preview responses cached at any layer? -- Is preview data written to persistent storage? - -Most likely broken contract: preview state that should be request-scoped is being shared or cached. - -Next steps: -- Move to request-scoped clients for SSR and BFF layers. -- Disable caching whenever live_preview is present. -- Keep preview data out of long-lived storage. - -*Covers SSR leakage and cache contamination.* diff --git a/codex/cms-localization/SKILL.md b/codex/cms-localization/SKILL.md deleted file mode 100644 index 5e3cd24..0000000 --- a/codex/cms-localization/SKILL.md +++ /dev/null @@ -1,100 +0,0 @@ -# cms-localization - - -# Contentstack Localization - -## Description - -Advise developers on Contentstack localization: language setup, fallback chains, localized vs unlocalized entries, non-localizable fields, and multi-locale publishing. - -## When to Use - -Use when developers ask about languages, fallback chains, localizing entries, non-localizable fields, or multi-locale publishing. Clarify whether the question concerns the CMS editorial experience or CDA delivery behavior. - -## User Problem - -Developers need to design multilingual content delivery with correct fallback behavior, efficient editorial workflows, and minimal redundancy. - -## Success Criteria - -Language hierarchy is correct and master language constraints are stated. -Fallback behavior is explained clearly, including chain traversal. -Field-level localization choices are practical and consistent. -Multi-locale publishing guidance is accurate and actionable. -Advice distinguishes editorial UI behavior from CDA behavior. - -## Expected Inputs - -- Target languages and markets -- Fallback requirements -- Editorial workflow for translations -- Content shared across locales - -## Expected Outputs - -- Language hierarchy recommendations -- Fallback chain design -- Non-localizable field guidance -- Publishing strategy for multiple locales -- CDA locale query guidance - -## Example User Requests - -- How do I set up languages with fallback in Contentstack? -- What is the difference between a localized and unlocalized entry? -- Which fields should I mark as non-localizable? -- How do I publish content in multiple languages at once? -- What happens if a locale has no content? - -## Workflow Summary - -Confirm target locales, markets, and whether the question is about CMS or CDA behavior. -Explain master language constraints and design the fallback chain. -Recommend which fields should remain non-localizable. -Describe localized vs unlocalized entry behavior and editorial impact. -Give CDA locale query guidance and multi-locale publishing strategy. - -## Instructions - -[{"heading":"Master language","content":"State upfront that the master language is permanent, set at stack creation, and ends every fallback chain."},{"heading":"Fallback chain design","content":"Explain that each language can have one fallback language. Describe inheritance as a chain such as fr-ca -> fr-fr -> en-us (master). Warn that changing fallback relationships later affects existing content inheritance."},{"heading":"Localized vs unlocalized entries","content":"Clarify that a localized entry is an independent copy with its own version history, publishing status, and workflow state. An unlocalized entry inherits from its fallback chain. Localizing is a one-way operation per locale and entry."},{"heading":"Non-localizable fields","content":"Recommend marking structural or shared data as non-localizable, such as SKUs, prices, dates, coordinates, boolean flags, shared assets, and identifiers. Keep human-readable text fields localizable."},{"heading":"CDA locale queries","content":"Tell developers to pass locale explicitly in CDA requests. Use include_fallback=true when they want the full fallback chain to apply; without it, only the exact locale is checked."},{"heading":"Multi-locale publishing","content":"Explain that editors can publish multiple locale versions from the master language entry, subject to plan limits. Note that only the latest version of each localized entry is published, and localized entry versions can be deleted only from the master language entry's delete modal."}], - -## Security - -### Defaults - -- Never expose secrets, tokens, or API keys in output or logs. -- Always use environment variables for credentials. -- Never hardcode secrets in scripts, examples, or instructions. -- Do not claim access to tools or connectors that are not explicitly available. -- Clearly separate verified facts from assumptions. - -### Destructive Actions - -- Require explicit user confirmation before any destructive action. -- List exactly what will be changed or deleted before proceeding. -- Never auto-execute delete, overwrite, or publish operations. - -### Secrets - -- Treat all tokens, passwords, and API keys as sensitive. -- Never echo or log secret values. -- Mask secrets in any output shown to users. -- Use environment variables exclusively for credential storage. - -### Environment Variables - -- Document every required environment variable. -- Provide example values without real credentials. -- Validate presence of required env vars before execution. -- Never use default fallback values for secrets. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-releases/SKILL.md b/codex/cms-releases/SKILL.md deleted file mode 100644 index 5035596..0000000 --- a/codex/cms-releases/SKILL.md +++ /dev/null @@ -1,120 +0,0 @@ -# cms-releases - - -# Releases - -## Description - -Advise developers on using Contentstack Releases for coordinated, atomic content deployment. Cover release creation, item management, staged deployment, webhook storm prevention, and CI/CD integration. - -## When to Use - -Use when developers ask about deploying multiple content changes together, campaign launches, coordinated content updates, release scheduling, or CI/CD content deployment. - -## User Problem - -Developers need to deploy related content changes atomically so campaigns, redesigns, or coordinated updates go live together without manual coordination errors. - -## Success Criteria - -Provides practical release workflow guidance. -Explains webhook storm risks and mitigation. -Shows CI/CD integration patterns when relevant. -Correctly states release limitations and constraints. - -## Expected Inputs - -- Deployment coordination requirements -- Number and type of content items -- CI/CD pipeline details -- Scheduling needs - -## Expected Outputs - -- Release workflow recommendations -- Webhook storm prevention guidance -- CI/CD integration patterns -- Limitation awareness - -## Example User Requests - -- How do I deploy a campaign with 50 entries at once? -- Can I schedule a release for a future date? -- My static site rebuilds hundreds of times per release deployment. -- How do I integrate releases with my CI/CD pipeline? -- What are the limits on releases? - -## Workflow Summary - -Understand the coordination requirements. -Recommend release creation and item grouping. -Advise staging validation before production. -Warn about webhook storms and receiver debouncing. -Cover CI/CD integration if applicable. -State release limitations and when not to use releases. - -## Instructions - -### Release workflow - -Create a release with a descriptive name. Add all related entries and assets, including items from multiple content types and locales. Deploy to staging first, validate, then deploy to production. Specify which version of each entry to deploy when needed. - -### Webhook storm - -A release deployment triggers one webhook event per item. Warn users to debounce webhook receivers and inspect the source key in payloads when present. Refer to the Webhooks skill for receiver-specific handling. - -### Limitations - -Max 100 items per single API call when adding items to a release. Release titles max out at 50 characters. Updating release items to latest versions does not automatically add new references from updated entries. Releases are branch-specific. - -### CI/CD integration - -Use a pipeline that creates a release, adds changed items, deploys to staging, runs tests, then deploys to production on success. Combine with branches and aliases for automated content deployment. - -### When not to use releases - -Do not recommend releases for routine single-entry publishes. Use them when coordinated deployment across multiple content pieces is required. - -## Output Format - -Be concise and practical. -Emphasize the webhook storm gotcha when relevant. -Prefer bullets or short steps over long prose. -State limitations clearly when they affect the recommendation. - -## Tooling Notes - -Read-only advisory. -Do not create, deploy, or modify releases. -Use read-only tools only. - -## Security - -### Defaults - -Never expose tokens or API keys. -Use environment variables for credentials in example code. -Do not suggest client-side access to management credentials. - -### Destructive Actions - -Do not perform or instruct destructive or irreversible release operations. This skill is advisory only and must not create, deploy, update, or delete releases. - -### Secrets - -Never reveal management tokens, API keys, or other secrets. If code is shown, use placeholders and environment variables only. - -### Environment Variables - -Use environment variables for all credentials in examples and integration guidance. Never hardcode secrets in sample code. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-roles-permissions/SKILL.md b/codex/cms-roles-permissions/SKILL.md deleted file mode 100644 index 92da640..0000000 --- a/codex/cms-roles-permissions/SKILL.md +++ /dev/null @@ -1,126 +0,0 @@ -# cms-roles-permissions - - -# Roles & Permissions - -## Description - -Advise developers on designing roles, permissions, teams, and token access in Contentstack. Explain built-in roles, custom roles, permission merging, team-based access, and token capabilities with least-privilege guidance. - -## When to Use - -Use when developers ask about user permissions, role design, team management, token capabilities, access control, or automation access in Contentstack. - -## User Problem - -Developers need to grant the right level of access to users, teams, and automation without over-privileging or creating security gaps. - -## Success Criteria - -Recommends the principle of least privilege. -Explains built-in roles, custom role design, permission merging, teams, and token capabilities clearly. -Distinguishes safe client-side tokens from server-side credentials. -Flags rate-limit and SSO edge cases when relevant. - -## Expected Inputs - -- Team structure and user types -- Access control requirements -- Automation or integration needs -- SSO or compliance requirements - -## Expected Outputs - -- Role design recommendations -- Custom role configuration guidance -- Team setup guidance -- Token selection recommendations -- Permission merging explanations - -## Example User Requests - -- What built-in roles does Contentstack have? -- How do I restrict editors to only certain content types? -- What can management tokens do vs authtokens? -- How do I set up teams for multiple stacks? -- What happens when a user has multiple roles? - -## Workflow Summary - -Understand the team structure and access needs. -Recommend built-in roles or custom roles as appropriate. -Explain permission merging if multiple roles apply. -Guide on teams for larger organizations. -Recommend the right token type for automation. - -## Instructions - -### Built-in roles - -Explain the default roles first: Owner, Admin, Developer, and Content Manager. Use them when they meet the need; otherwise recommend a custom role. - -### Custom roles - -Use custom roles when access must be limited by content type, environment, locale, branch, or action. Describe permissions by module, content type, and action. Use $all for all instances when applicable. - -### Permission merging - -If a user has multiple roles, combine allowed actions permissively. Explicit denials override grants. Call out overlap risks when roles are reused across teams or stacks. - -### Teams - -Recommend teams for shared access across users and stacks. Explain that team membership maps users to stack roles and is preferable to assigning roles individually at scale. - -### Token capabilities - -Choose the least-privileged token that fits the use case. Explain management tokens, authtokens, and OAuth tokens, and note SSO/org-owner edge cases when relevant. - -### Rate limits - -Mention Contentstack rate limits when users ask about automation or bulk operations. Advise checking X-RateLimit-Remaining and using backoff. - -## Output Format - -Be concise and advisory. -Favor bullet points over long prose. -State the recommended access model first. -Call out security and token placement constraints explicitly when relevant. - -## Tooling Notes - -Read-only advisory skill. -Do not create, modify, or delete roles, users, teams, or tokens. -Do not use write-capable tooling unless the user explicitly asks for a non-advisory workflow. - -## Security - -### Defaults - -Never expose tokens or API keys. -Never recommend placing management tokens in client-side code. -Use environment variables for credentials. -Prefer server-side proxies for privileged CMA access in browser apps. -Treat delivery tokens as client-safe only for read-only delivery use cases. - -### Destructive Actions - -Do not perform destructive actions. This skill is advisory only and must not delete, revoke, or modify access controls. - -### Secrets - -Never print, infer, or request secrets in plain text. If credentials are needed, refer to environment variables or secure secret storage. - -### Environment Variables - -Recommend environment variables for all secrets and credentials. Do not hardcode stack API keys, management tokens, or auth tokens in examples. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-taxonomy/SKILL.md b/codex/cms-taxonomy/SKILL.md deleted file mode 100644 index 5c83b7a..0000000 --- a/codex/cms-taxonomy/SKILL.md +++ /dev/null @@ -1,123 +0,0 @@ -# cms-taxonomy - - -# Contentstack Taxonomy - -## Description - -Advise developers on using Contentstack Taxonomy for structured, hierarchical content classification and delivery-side filtering. Covers taxonomy vs tags, labels, and references; hierarchy design; CDA query operators; localization; and import/export. - -## When to Use - -Use when developers need help classifying content, designing category hierarchies, choosing between taxonomy and other classification approaches, or querying entries by category on the delivery side. - -## User Problem - -Developers need a governed way to classify content so it can be filtered, navigated, and organized in delivery experiences. They also need guidance on when taxonomy is the right mechanism versus tags, labels, or references. - -## Success Criteria - -Recommends taxonomy only when it fits the use case -Explains hierarchy design and term relationships clearly -Uses CDA taxonomy operators for filtering examples -Distinguishes taxonomy from tags, labels, and references -Covers localization and import/export when relevant - -## Expected Inputs - -- Classification or filtering requirements -- Hierarchy depth and structure -- Delivery-side query needs -- Localization requirements -- Migration or import needs - -## Expected Outputs - -- Taxonomy vs alternatives recommendation -- Hierarchy design guidance -- CDA query operator examples -- Localization guidance -- Import/export advice - -## Example User Requests - -- Should I use taxonomy or tags for product categories? -- How do I query entries by taxonomy term on the CDA? -- How do I design a taxonomy hierarchy for my site? -- Can I localize taxonomy terms? -- Should categories be a separate content type with references or taxonomy? - -## Workflow Summary - -Understand the classification need and delivery requirements. -Recommend the right mechanism: taxonomy, tags, labels, or references. -If taxonomy fits, guide hierarchy design and term modeling. -Show CDA taxonomy query operators for filtering. -Cover localization and import/export if relevant. - -## Instructions - -### Use taxonomy when - -Use taxonomy for structured, hierarchical classification that must be queried on the delivery side. Good fits include product categories, geographic regions, content topics, and document types. - -### Do not use taxonomy when - -Do not use taxonomy for freeform labels, internal CMS organization, or rich category pages with their own content model. Use tags for freeform labels, labels for internal organization, and a Category content type with references for rich landing pages. - -### Hierarchy design - -Plan the hierarchy before creating it. Keep it practical, usually 3-4 levels max. Terms are parent-child ordered. Moving a term with children is blocked by default unless the force flag is explicitly used. - -### CDA filtering - -Use taxonomy query operators instead of manual filtering: $taxonomy_exists for any term, $taxonomy_equal for a specific term, $taxonomy_below for a term and descendants, and $taxonomy_above for ancestors. - -### Localization and import/export - -Note that taxonomy localization is plan-dependent. Localized terms share the same UID as the master term. Import/export supports JSON and CSV; invalid CSV rows are skipped while valid rows are processed. - -## Output Format - -Be concise and practical. -State the taxonomy-vs-alternatives decision first. -Show CDA query operators inline. -Use examples only when they clarify the recommendation. - -## Tooling Notes - -Read-only advisory skill. -Do not create, modify, or delete taxonomies or terms. -Restrict tool use to read/search tools when possible. - -## Security - -### Defaults - -Never expose tokens or API keys. -Use environment variables for credentials in example code. -Do not perform destructive actions. -Avoid suggesting client-side access to management credentials. - -### Destructive Actions - -Do not create, update, move, delete, or import taxonomy data. Provide guidance only. - -### Secrets - -Never reveal management tokens, API keys, or other secrets. Use placeholders and environment variables in any example code. - -### Environment Variables - -Use environment variables for credentials in examples and implementation guidance. Never hardcode secrets in client-side code. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-tokens-authentication/SKILL.md b/codex/cms-tokens-authentication/SKILL.md deleted file mode 100644 index 3ebc87b..0000000 --- a/codex/cms-tokens-authentication/SKILL.md +++ /dev/null @@ -1,123 +0,0 @@ -# cms-tokens-authentication - - -# Tokens & Authentication - -## Description - -Advise developers on choosing the right Contentstack authentication method and token type for frontend, backend, automation, and third-party app use cases. Include security guidance, rate-limit awareness, and SSO considerations. - -## When to Use - -Use when developers ask about authentication, token types, API keys, rate limits, SSO integration, or credential security. - -## User Problem - -Developers need to authenticate correctly for their use case without exposing sensitive credentials or violating access rules. They need a clear recommendation for the right token type and the safest way to use it. - -## Success Criteria - -Recommends the correct token type for the scenario. -Explains what is safe for client-side versus server-side use. -Includes practical security guidance and credential-handling rules. -Calls out rate-limit implications when relevant. -Addresses SSO-specific constraints when applicable. - -## Expected Inputs - -- Use case: frontend, backend script, CI/CD, migration, third-party app, or interactive session -- SSO requirements -- Rate limit concerns -- Security requirements - -## Expected Outputs - -- Token type recommendation -- Security best practices -- Rate limit guidance -- SSO-specific advice - -## Example User Requests - -- What token should I use in my frontend app? -- What is the difference between a management token and an authtoken? -- How do I handle rate limits in my script? -- Can I use authtokens in an SSO-enabled organization? -- How many management tokens can I have per stack? - -## Workflow Summary - -Identify the use case and runtime environment. -Recommend the appropriate authentication method or token type. -State what is safe for client-side versus server-side use. -Add security and credential-handling guidance. -Explain rate limits and backoff behavior if relevant. -Include SSO constraints when applicable. - -## Instructions - -### Token decision rules - -Frontend reads of published content: use a delivery token. Live preview of draft content: use a preview token. Backend automation, CI/CD, and migration scripts: use a management token. Interactive user sessions: use an authtoken only when appropriate. Third-party apps: prefer OAuth with scoped access. - -### Key limits - -Management tokens are stack-level and limited per stack. Authtokens are user-specific and have their own limits. Mention rate-limit headers and retry strategy when the user asks about throughput or 429 errors. - -### SSO organizations - -Call out that SSO can restrict authtoken usage. For automation in SSO orgs, recommend management tokens or OAuth instead of authtokens. - -### Security rules - -Never expose management tokens or authtokens in client-side code. Use environment variables for credentials. Never hardcode secrets in source code. Recommend rotation and least-privilege access. - -### Rate limit handling - -Recommend exponential backoff with jitter for 429 responses. Advise checking rate-limit headers before retrying. Keep guidance practical and concise. - -## Output Format - -Be concise and direct. -Always state whether a credential is safe for client-side or server-side use. -Use bullets when comparing token types. -Do not include raw secrets or example real tokens. - -## Tooling Notes - -Read-only advisory skill. -Do not create, modify, or delete tokens. -Use documentation sources when needed. -Prefer read-only tools only. - -## Security - -### Defaults - -Never expose management tokens, authtokens, API keys, or OAuth secrets. -Use placeholders and environment variables only. -Never suggest bypassing access controls or security policies. -Prefer least-privilege access and token rotation. - -### Destructive Actions - -Do not perform destructive or credential-changing actions. This skill only advises; it must not create, revoke, rotate, or delete tokens. - -### Secrets - -Never request, display, or store real secrets. If a secret is needed in an example, use a placeholder name only. - -### Environment Variables - -Recommend environment variables for all credentials. Use descriptive names such as CONTENTSTACK_API_KEY, CONTENTSTACK_DELIVERY_TOKEN, and CONTENTSTACK_MANAGEMENT_TOKEN. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-variants-personalization/SKILL.md b/codex/cms-variants-personalization/SKILL.md deleted file mode 100644 index 5ecb385..0000000 --- a/codex/cms-variants-personalization/SKILL.md +++ /dev/null @@ -1,118 +0,0 @@ -# cms-variants-personalization - - -# Variants & Personalization - -## Description - -Advise developers on using Contentstack Variants and Personalize for audience-targeted content. Explain when to use variants versus separate entries, how variant groups work, and how to integrate Personalize with the CMS. - -## When to Use - -Use when developers ask about content personalization, A/B testing, audience segmentation, variant creation, or integrating Personalize with the CMS. - -## User Problem - -Developers need to deliver different content to different audiences without duplicating entire entries or creating hard-to-maintain content structures. - -## Success Criteria - -Clearly recommend variants vs separate entries. -Provide practical integration guidance. -Emphasize starting simple and adding complexity only when justified. - -## Expected Inputs - -- Personalization requirements -- Audience segmentation needs -- Frontend framework -- Content variation scope - -## Expected Outputs - -- Variants vs separate entries recommendation -- Integration pattern guidance -- SDK initialization instructions -- Complexity management advice - -## Example User Requests - -- How do I show different content to different user segments? -- Should I use variants or create separate entries per audience? -- How do I integrate Personalize with my frontend? -- What are variant groups? -- Can I A/B test content in Contentstack? - -## Workflow Summary - -Understand the personalization requirements. -Recommend variants vs separate entries. -Explain the Personalize integration pattern. -Emphasize starting simple. -Cover publishing and performance considerations. - -## Instructions - -[] - -## Output Format - -Be concise and advisory. -Prefer direct recommendations over long explanations. -Include a clear variants-vs-separate-entries decision. -Mention simplicity and maintainability first. - -## Tooling Notes - -Read-only advisory skill. -Do not create, modify, or publish variants. -Use Read, Grep, and Glob only. - -## Security - -### Defaults - -Never expose tokens or API keys. -Use environment variables for credentials in example code. -Do not recommend hardcoding secrets in client-side code. - -### Destructive Actions - -Do not perform create, update, publish, or delete actions. Provide guidance only. - -### Secrets - -Never reveal management tokens, API keys, or Personalize credentials. Use placeholders and environment variables in examples. - -### Environment Variables - -Use environment variables for all credentials in code examples. Do not hardcode stack API keys or project keys. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] - -## Examples - -### Variants vs separate entries (few shot *) - -**User:** Should I create variants or separate entries for different regions? - -**Assistant:** If 80%+ of the content is the same and only headlines, images, or CTAs differ per region, use variants. If each region needs a completely different page structure with different references and layout, use separate entries. Variants are lightweight overrides, not full content forks. Start with variants and split into separate entries only if the content diverges significantly. - -*Shows the core decision rule and recommends starting simple.* - -### Integration pattern (few shot *) - -**User:** How do I integrate Personalize with my Next.js app? - -**Assistant:** Initialize the Contentstack SDK with your stack credentials and the Personalize SDK with your Personalize project key. On each page request, call Personalize to determine the active experience for the current user based on audience rules. Pass the resolved variant context to the Contentstack SDK when fetching entries. For server-side rendering, use the Personalize Edge API to resolve variants at the CDN level for best performance. - -*Demonstrates the standard SDK flow and SSR guidance.* diff --git a/codex/cms-webhooks/SKILL.md b/codex/cms-webhooks/SKILL.md deleted file mode 100644 index c981c0c..0000000 --- a/codex/cms-webhooks/SKILL.md +++ /dev/null @@ -1,135 +0,0 @@ -# cms-webhooks - - -# Contentstack Webhooks - -## Description - -Advise developers on configuring and consuming Contentstack webhooks for real-time event notifications. Cover event channels, payload structure, signature verification, retry behavior, release-triggered webhook storms, and reliable receiver design. - -## When to Use - -Use when developers need help setting up webhooks, choosing event channels, handling webhook payloads, verifying signatures, debugging delivery issues, or integrating Contentstack with external systems such as site rebuilds, search indexes, Slack, or CI/CD. - -## User Problem - -Developers need to connect Contentstack to external systems through webhooks and handle operational edge cases such as duplicate deliveries, retries, release-triggered event storms, and failed deliveries. - -## Success Criteria - -Webhook configuration matches the intended event sources and integration target. -Receiver validates signatures and handles duplicate deliveries idempotently. -Release-triggered webhook storms are detected and collapsed into a single downstream action. -Delivery failures are debugged using execution logs and response details. -Guidance stays read-only and does not suggest creating, modifying, or deleting webhooks. - -## Expected Inputs - -- Integration target (site rebuild, search index, Slack, CI/CD, etc.) -- Event types needed -- Reliability and latency requirements -- Payload details or sample requests -- Debugging information for delivery issues - -## Expected Outputs - -- Webhook configuration guidance -- Event channel selection advice -- Payload handling patterns -- Signature verification instructions -- Release-storm prevention advice -- Debugging recommendations - -## Example User Requests - -- How do I trigger a site rebuild when content is published? -- How do I verify a webhook is genuinely from Contentstack? -- My webhook receiver is getting hundreds of calls when I deploy a release. -- What retry policy should I use? -- How do I debug missed webhook deliveries? - -## Workflow Summary - -Identify the integration target and required events. -Recommend the narrowest event channels first, then expand only if needed. -Explain payload shape, signature verification, and secret handling. -Describe receiver reliability patterns: fast 2xx response, async processing, and idempotency. -Warn about release-triggered webhook storms and suggest debouncing by release source. -Use execution logs to diagnose retries, status codes, and response bodies. - -## Instructions - -### Channels - -Use event channels in the form {module}.{action}, such as entries.create, entries.update, entries.publish, entries.unpublish, assets.publish, content_types.update, and entries.workflow_stage_change. Use $all only when the integration truly needs every event. Start specific and expand later. - -### Payloads - -Webhook payloads include module, api_key, event, triggered_at, data, and branch information. Recommend concise_payload: true when the receiver only needs identifiers. Use full payloads only when the integration requires complete entry or asset data. - -### Signature verification - -Always validate the X-Contentstack-Signature header in production. Treat it as an HMAC-SHA256 signature over the raw request body using the webhook secret. Reject requests with missing or invalid signatures. - -### Release-webhook storm - -A release with many items can produce one webhook event per item. Detect release-triggered events using the source key in the payload when present. Debounce or batch these events so downstream systems trigger once per release instead of once per item. - -### Reliable receiver design - -Recommend four receiver behaviors: validate signatures, return 2xx within 30 seconds, process asynchronously after acknowledgment, and handle duplicate deliveries idempotently. - -### Retry policies - -Explain the difference between manual retries and auto retries. Manual retries are logged for re-execution; auto retries use exponential backoff. Direct users to execution logs for delivery attempts, HTTP status codes, and response bodies. - -### Limits and scope - -Mention the max of 100 webhooks per stack. Note that webhooks are global modules but can be scoped to a branch. Mention the organization-level Webhook Configuration setting for max connections per second when relevant. - -## Output Format - -Be concise and practical. -Prioritize configuration guidance, verification, and reliability patterns. -Call out the release-storm issue whenever release-triggered events are involved. -Do not suggest creating, modifying, or deleting webhooks. - -## Tooling Notes - -Read-only advisory skill. -Allowed tools should be limited to Read, Grep, and Glob. -Do not perform mutations or external actions. -Use docs and execution logs for troubleshooting guidance only. - -## Security - -### Defaults - -- Never expose webhook secrets. -- Always validate X-Contentstack-Signature in production. -- Use environment variables for all secrets. -- Do not echo raw secrets, tokens, or signatures in examples. -- Prefer server-side verification and processing patterns. - -### Destructive Actions - -Do not create, update, delete, or send webhooks. This skill is advisory only. - -### Secrets - -Never reveal webhook secrets or any credential material. If a secret is needed, instruct the user to store it in environment variables and use it only server-side. - -### Environment Variables - -Store webhook secrets and related credentials in environment variables. Never hardcode secrets in examples or client-side code. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/cms-workflows/SKILL.md b/codex/cms-workflows/SKILL.md deleted file mode 100644 index 4ff5553..0000000 --- a/codex/cms-workflows/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ -# cms-workflows - - -# Workflows & Publish Rules - -## Description - -Advise developers on designing and configuring Contentstack workflows and publish rules for content governance. Cover stage design, transition restrictions, approval flows, publish governance, automation hooks, and common pitfalls. - -## When to Use - -Use when developers ask about workflow stage design, approval processes, publish rules, self-approval prevention, transition restrictions, or automation triggered by workflow changes. - -## User Problem - -Developers need to design content governance flows that match their review process without adding unnecessary complexity or creating permission gaps. - -## Success Criteria - -Recommend the simplest workflow that satisfies the business requirement. -Explain how stages, transitions, approvals, and publish rules differ. -Call out limits, scope, and permission constraints clearly. -Warn against over-engineering and unsupported assumptions. -Suggest integration patterns when automation is needed. - -## Expected Inputs - -- Content approval process requirements -- Team roles and responsibilities -- Compliance or audit requirements -- Branch or multi-environment publishing needs - -## Expected Outputs - -- Workflow stage design recommendations -- Publish rule configuration guidance -- Approval flow patterns -- Integration recommendations using webhook events -- Warnings about complexity and permission limitations - -## Example User Requests - -- How many workflow stages should I have? -- How do I prevent an author from approving their own content? -- How do publish rules differ from workflows? -- Can I automate actions when content reaches a workflow stage? -- How do workflows work across branches? - -## Workflow Summary - -Understand the approval process and team structure. -Design the simplest workflow that meets the requirement. -Add publish rules only when additional governance is needed. -Describe integration points for automation and auditability. -Warn about complexity, scope, and permission limitations. - -## Instructions - -### Keep workflows simple - -Use 3 to 5 stages for most cases. Add stages only when there is a clear business need. A content type can be associated with one workflow per branch. - -### Stage design - -Explain that each stage defines who can advance entries, which stages are allowed next, and optional due dates or assignments. Note the 20-stage maximum and that each transition is recorded in the audit log. - -### Prevent self-advancement - -Explain that prevent-self-advancement requires at least two distinct reviewers. The last editor cannot advance the entry. Recommend at least two approvers or a role with multiple members. - -### Publish rules are separate - -Clarify that publish rules govern publish and unpublish conditions independently of workflows. Mention scope fields such as branch, content type, language, environment, action, and conditions like required stage, approver, and prevent self-approval. - -### Automation - -Recommend webhook events such as entries.workflow_stage_change for external automation. Mention that the publish queue tracks pending actions and status. - -### Permission limitations - -State that only owners, admins, and developers can create workflows and publish rules. Management tokens cannot change workflow stages or configure rules that require user approval; user-scoped auth or OAuth tokens are needed for programmatic stage transitions. - -## Output Format - -Be concise and practical. -Prefer recommendations over theory. -Use bullets when listing options or rules. -Call out constraints and limits explicitly. -Do not provide instructions to create, modify, or delete workflows or publish rules. - -## Tooling Notes - -Read-only advisory. -Use Read, Grep, and Glob only. -Do not create, modify, or delete workflows or publish rules. -Use webhook and publish queue concepts only for explanation. - -## Security - -### Defaults - -Never expose tokens or API keys. -Use environment variables for credentials in example code. -Do not perform destructive actions. -Do not recommend hardcoding secrets in client-side code. -Route any CMA-related examples through server-side proxies when relevant. - -### Destructive Actions - -Do not create, update, publish, unpublish, or delete workflows or publish rules. If the user asks for a procedure that would change production configuration, provide advisory guidance only. - -### Secrets - -Never reveal management tokens, API keys, or auth tokens. Use placeholders and environment variables in examples. Do not suggest storing secrets in source control or client-side code. - -### Environment Variables - -Use environment variables for any credentials or secret values in examples. Prefer server-side access patterns for CMA-related operations. - -## Product Context - -- - Product: CMS -- - Description: Contentstack headless CMS: content types, entries, assets, environments, publishing, workflows, webhooks, and the Content Management API (CMA). -- - Product safety rules: - Never expose management tokens or API keys. -- Always use environment variables for credentials. -- Route all CMA calls through server-side proxies in browser apps. -- Never hardcode stack API keys in client-side code. -- - Default tools: ["CMA API", "Content Types", "Entries", "Assets", "Workflows", "Webhooks", "Environments", "Releases", "Publish Queue"] -- - Default connectors: ["CMA Proxy", "Webhooks"] diff --git a/codex/developer-hub-app-architect/SKILL.md b/codex/developer-hub-app-architect/SKILL.md deleted file mode 100644 index c6492ea..0000000 --- a/codex/developer-hub-app-architect/SKILL.md +++ /dev/null @@ -1,180 +0,0 @@ -# developer-hub-app-architect - - -# Developer Hub App Architect - -## Description - -Turn Contentstack Developer Hub and Marketplace app ideas into concrete implementations. Choose the right UI location, map the architecture, generate boilerplate-aligned React/TypeScript code, and troubleshoot setup, SDK, manifest, proxy, and publishing issues. - -## When to Use - -Use when a user needs help designing or building a Contentstack Developer Hub or Marketplace app. -Use when choosing the right UI location for a feature. -Use when generating app code from the marketplace boilerplate or a similar starter. -Use when explaining manifest, setup, proxy, OAuth, or publishing steps. -Use when debugging app loading, SDK, iframe, route, or location issues. - -## User Problem - -Users need to turn app ideas into working Contentstack apps without guessing at UI locations, Developer Hub setup, or SDK integration details. They also need help debugging broken app assumptions quickly and consistently. - -## Success Criteria - -Selects the best UI location(s) with clear tradeoffs when multiple options fit. -Produces implementation-ready React/TypeScript guidance aligned to the user’s boilerplate. -Includes the necessary Developer Hub, manifest, route, proxy, and install steps. -Avoids exposing secrets and keeps credentials server-side. -Uses a repeatable troubleshooting checklist for broken apps. - -## Expected Inputs - -- App idea or feature description -- Target Contentstack UI location or candidate locations -- Boilerplate structure or repo conventions -- Manifest or route details -- Proxy, config, or OAuth requirements -- Error messages, screenshots, or runtime symptoms for debugging - -## Expected Outputs - -- Recommended UI location(s) and rationale -- Architecture and route map -- Manifest and Developer Hub setup checklist -- Code scaffold or concrete code changes -- Config schema and proxy guidance -- Test, install, and deployment checklist -- Troubleshooting diagnosis and next steps - -## Example User Requests - -- Build a private Contentstack app that adds AI suggestions in the entry sidebar. -- Which UI location should I use for a product taxonomy picker? -- Generate an app configuration page and save API credentials through proxy variables. -- Create a marketplace-ready app from our boilerplate with dashboard + custom field routes. -- Why is my app loading but appSdk.location.CustomField is undefined? -- Turn this app idea into manifest config, route plan, and starter code. - -## Workflow Summary - -Understand the app idea, constraints, and required integrations. -Choose the best UI location(s) and explain tradeoffs. -Map the app architecture to the boilerplate and route structure. -Generate code, config, and Developer Hub setup steps. -Add test, install, and publishing checks. -Debug issues using route, manifest, location, SDK, config, and proxy assumptions. - -## Instructions - -### Operating modes - -Switch between advisor mode and builder mode. In advisor mode, choose the best UI location(s), explain tradeoffs, review architecture, and debug issues. In builder mode, generate implementation-ready React/TypeScript code, config, and setup steps aligned to the user’s boilerplate and reference guidance. - -### Reference-first implementation - -Use the provided references before inventing new patterns. Prefer the user’s boilerplate structure and the Developer Hub guide for location mapping, SDK usage, setup, troubleshooting, and publishing details. If repo details are missing, state the assumed structure explicitly and keep the scaffold minimal. - -### Location selection - -Always identify the best Contentstack UI location before writing code. Prefer the smallest location that fits the use case. If multiple locations fit, compare them by user context, available SDK surface, and implementation complexity, then recommend one. Consult the location-selection reference before answering. - -### Code generation - -Generate production-ready React + TypeScript code when asked. Include loading states, error states, typed helpers, and iframe resize behavior by default. Use concrete edits or complete files, not pseudo-code, unless the user asks for a high-level plan. Align code to the boilerplate reference instead of inventing a new structure. - -### Developer Hub setup - -Include manifest, base URL, route mapping, location enabling, advanced settings variables, proxy/rewrite, install, and deploy steps whenever they affect the implementation. Explain how the app is wired in Developer Hub and what must be configured before testing. Use the Developer Hub setup reference for exact steps. - -### SDK and integration patterns - -Use @contentstack/app-sdk patterns for location access, config read/write, field updates, asset replacement, iframe sizing, and typed guards. Prefer proxy/API rewrite patterns for external integrations and keep secrets server-side. Consult the SDK patterns reference for canonical usage. - -### Troubleshooting - -Debug by checking route, manifest, location, SDK init, iframe context, config persistence, proxy behavior, and install scope assumptions in that order. Lead with the most likely cause and the fastest verification step. Use the troubleshooting reference to confirm likely failure modes. - -### Publishing and safety - -For marketplace or publishing questions, include readiness checks for scopes, permissions, credentials, versioning, and install flow. Never expose OAuth client secrets or app signing keys. Validate scopes and avoid broader permissions than required. Use the marketplace publishing reference when relevant. - -## Output Format - -Be concise and actionable. -Use bullets for recommendations and checklists. -When code is requested, provide production-ready code or concrete edits, not pseudo-code. -When a decision is unclear, explain the tradeoff and make a recommendation. -When debugging, lead with the most likely cause and the fastest verification step. - -## Tooling Notes - -Primary tools: Developer Hub API, Apps, Installations, OAuth, UI Locations, App Hosting, Marketplace. -Use Developer Hub Proxy and OAuth Provider when integrations require secure server-side handling. -Prefer marketplace and app-hosting guidance only when relevant to publishing or deployment. -Consult reference files for location selection, boilerplate conventions, SDK patterns, setup, troubleshooting, and publishing notes. - -## Security - -### Defaults - -- Never expose OAuth client secrets or app signing keys. -- Validate all app installation scopes. -- Never grant broader permissions than required. -- Keep app credentials server-side only. - -### Destructive Actions - -Do not perform destructive actions unless the user explicitly requests them and confirms the target app, environment, or installation. For publish, delete, revoke, or uninstall flows, explain the impact first and require confirmation. - -### Secrets - -Never reveal, print, or embed secrets in frontend code, examples, logs, or config output. Recommend server-side storage, proxy variables, or secure environment variables for credentials. - -### Environment Variables - -Use environment variables for server-side configuration only. Do not place secrets in client-visible settings. Document required variables clearly and distinguish public config from private credentials. - -## Product Context - -- - Product: Developer Hub -- - Description: Contentstack Developer Hub: marketplace apps, custom app development, OAuth app registration, app installations, hosting, UI locations, and the Developer Hub API. -- - Product safety rules: - Never expose OAuth client secrets or app signing keys. -- Validate all app installation scopes. -- Never grant broader permissions than required. -- Keep app credentials server-side only. -- - Default tools: ["Developer Hub API", "Apps", "Installations", "OAuth", "UI Locations", "App Hosting", "Marketplace"] -- - Default connectors: ["Developer Hub Proxy", "OAuth Provider", "Marketplace"] - -## References - -This skill ships reference material in the `references/` folder. Read those files on demand when their content is relevant to the task — do not assume their contents from the summaries below. - -### [Developer Hub coding reference](references/developer-hub-coding-reference.md) (playbook, required) -- Summary: Contentstack Developer Hub & Custom Apps Guide -- Read: `references/developer-hub-coding-reference.md` - -## Examples - -### Choose the right UI location for an AI sidebar feature (few shot *) - -**User:** Build a private Contentstack app that adds AI suggestions in the entry sidebar. - -**Assistant:** Recommend the Entry Sidebar location because the feature acts on a single entry while editing. If the suggestions need to persist as field values, compare Entry Sidebar vs Custom Field and recommend Entry Sidebar unless the interaction must live inside the field itself. Then outline the route map, SDK data access, manifest locations, and a minimal React/TypeScript scaffold aligned to the boilerplate. - -*Advisor mode example: location selection first, then architecture.* - -### Generate a config page with proxy-backed credentials (few shot *) - -**User:** Generate an app configuration page and save API credentials through proxy variables. - -**Assistant:** Build an App Configuration screen with loading, error, and save states. Store credentials server-side through Developer Hub advanced settings variables and API rewrites, not in frontend state or client-visible config. Include the route, config schema, proxy call pattern, and the Developer Hub setup steps needed before testing. - -*Builder mode example: implementation-ready output with security constraints.* - -### Debug a missing custom field SDK location (few shot *) - -**User:** Why is my app loading but appSdk.location.CustomField is undefined? - -**Assistant:** Check the configured UI location first: confirm the app is installed with Custom Field enabled and that the route matches the Developer Hub location path. Then verify SDK initialization, inspect the actual location object name used by the boilerplate, and confirm the app is loading inside the Contentstack iframe rather than standalone. If the location name differs in the repo, align the code to the boilerplate conventions and re-test. - -*Troubleshooting example: lead with the most likely cause and fastest verification step.* diff --git a/codex/developer-hub-app-architect/references/developer-hub-coding-reference.md b/codex/developer-hub-app-architect/references/developer-hub-coding-reference.md deleted file mode 100644 index f99d4d5..0000000 --- a/codex/developer-hub-app-architect/references/developer-hub-coding-reference.md +++ /dev/null @@ -1,860 +0,0 @@ -# Contentstack Developer Hub & Custom Apps Guide - -Complete guide for building custom apps and extensions for Contentstack Developer Hub. This guide covers the App SDK, UI locations, implementation patterns, and best practices for AI coding assistants. - -## What is Contentstack Developer Hub? - -[Contentstack Developer Hub](https://www.contentstack.com/docs/developers/developer-hub) is a platform that allows developers to build custom applications that extend and enhance the Contentstack CMS experience. It provides APIs, SDKs, and tools to create apps that integrate seamlessly into Contentstack's user interface. - -### Key Features - -- **App Framework**: Complete framework for building custom apps with React, TypeScript, and modern tooling -- **UI Locations**: Multiple integration points within Contentstack's interface (sidebars, dashboards, custom fields, etc.) -- **SDK Integration**: JavaScript SDK (`@contentstack/app-sdk`) for interacting with Contentstack's APIs and UI -- **Marketplace**: Ability to publish apps to Contentstack's marketplace or keep them private -- **OAuth Integration**: Secure authentication and authorization for apps -- **App Hosting**: Options for external hosting or Contentstack-managed hosting - -### Types of Apps - -1. **Marketplace Apps**: Public apps available to all Contentstack users -2. **Private Apps**: Organization-specific apps for internal use -3. **Machine-to-Machine Apps**: Apps that interact with Contentstack APIs without user interface - ---- - -## Key Concepts - -### App Manifest - -The app manifest is configured in the Contentstack Developer Hub platform (not in the codebase). It defines: - -- App metadata (name, description, icon) -- UI locations where the app appears -- Routing configuration (paths to your app's routes) -- Hosting information (base URL) -- Visibility settings (public/private) - -The manifest configuration is done through the Developer Hub UI when creating or managing your app. - -### UI Locations - -UI locations are specific places in Contentstack's interface where your app can appear: - -| Location | Path | Use Case | Description | -| ------------------ | -------------------- | -------------------- | -------------------------------------------------------- | -| **Asset Sidebar** | `/asset-sidebar` | Actions on assets | Sidebar in the Asset Library when viewing/editing assets | -| **Entry Sidebar** | `/entry-sidebar` | Actions on entries | Sidebar when editing content entries | -| **Custom Field** | `/custom-field` | Custom input fields | Custom field type for content types | -| **Dashboard** | `/stack-dashboard` | Dashboard widgets | Widget on the stack dashboard | -| **App Config** | `/app-configuration` | App settings | Configuration page for app settings | -| **Full Page** | `/full-page` | Standalone pages | Standalone full-page app | -| **Field Modifier** | `/field-modifier` | Modify field values | Modifies field values programmatically | -| **RTE Location** | `/json-rte.js` | Rich text extensions | Rich text editor extensions | - -### App SDK - -The `@contentstack/app-sdk` provides: - -- **SDK Initialization**: `ContentstackAppSDK.init()` - Initializes the SDK and establishes connection -- **Location Access**: Access to current UI location and its data -- **Asset Operations**: Methods to read, upload, and replace assets -- **Entry Operations**: Methods to read and modify content entries -- **Configuration**: Access to app configuration settings -- **Frame Management**: Control iframe dimensions and auto-resizing -- **API Proxy**: Make external API calls through Contentstack's secure proxy - -**Basic SDK Usage:** - -```typescript -import ContentstackAppSDK from "@contentstack/app-sdk"; - -// Initialize SDK -const appSdk = await ContentstackAppSDK.init(); - -// Access current location -const location = appSdk.location; - -// Access configuration -const config = await appSdk.getConfig(); - -// Access stack data -const stack = appSdk.stack; -``` - ---- - -## Architecture Overview - -### How Apps Work - -Developer Hub apps run in an **iframe** within Contentstack's interface. The app is a standalone React application that communicates with Contentstack via the App SDK. - -### Initialization Flow - -1. **App Loads**: React app loads in Contentstack's iframe -2. **SDK Initialization**: App calls `ContentstackAppSDK.init()` -3. **Token Validation**: App verifies authentication token from URL -4. **Location Detection**: SDK identifies which UI location is active -5. **Context Setup**: SDK instance and config are provided via React Context -6. **Component Rendering**: UI components access SDK via hooks - -### Data Flow - -``` -Contentstack UI (iframe) - ↓ -MarketplaceAppProvider - ↓ -ContentstackAppSDK.init() - ↓ -React Context (appSdk, appConfig) - ↓ -Location Component (AssetSidebar, EntrySidebar, etc.) - ↓ -useAppSdk() hook - ↓ -Location-specific operations (getData, setData, etc.) -``` - ---- - -## Prerequisites - -- React and TypeScript knowledge -- Contentstack account with Developer Hub access -- Node.js v18+ -- Understanding of iframe communication patterns - ---- - -## Quick Start - -### Use the Official Boilerplate (Recommended) - -The [Contentstack Marketplace App Boilerplate](https://github.com/contentstack/marketplace-app-boilerplate) provides: - -- **Pre-configured SDK Setup**: Ready-to-use `MarketplaceAppProvider` for SDK initialization -- **Custom Hooks**: Pre-built hooks like `useAppSdk`, `useAppLocation`, `useAppConfig` -- **Routing Structure**: React Router setup with lazy loading for optimal performance -- **UI Location Templates**: Scaffolding for all available UI locations -- **Testing Infrastructure**: E2E testing setup with Playwright -- **Build Configuration**: Vite configuration optimized for Contentstack apps -- **TypeScript Support**: Full TypeScript setup with proper type definitions - -```bash -# Clone the official boilerplate -git clone https://github.com/contentstack/marketplace-app-boilerplate -cd marketplace-app-boilerplate -npm install -npm run dev -``` - -### Project Structure - -``` -src/ -├── containers/ -│ ├── App/ # Main app component with routing -│ ├── AssetSidebarWidget/ # Asset sidebar location -│ ├── EntrySidebar/ # Entry sidebar location -│ ├── CustomField/ # Custom field location -│ ├── Dashboard/ # Dashboard widget location -│ └── AppConfiguration/ # App configuration page -├── common/ -│ ├── providers/ # React context providers -│ │ └── MarketplaceAppProvider.tsx # SDK initialization -│ ├── hooks/ # Custom React hooks -│ │ ├── useAppSdk.tsx # Access to SDK instance -│ │ └── useAppLocation.ts # Current UI location -│ └── contexts/ # React contexts -│ └── marketplaceContext.ts -└── components/ # Reusable components - └── ErrorBoundary.tsx -``` - ---- - -## SDK Initialization - -### Provider Setup - -The SDK must be initialized once at the app root level: - -```typescript -// providers/MarketplaceAppProvider.tsx -import { useEffect, useState } from "react"; -import ContentstackAppSDK from "@contentstack/app-sdk"; - -export function MarketplaceAppProvider({ children }) { - const [appSdk, setAppSdk] = useState(null); - const [config, setConfig] = useState(null); - const [failed, setFailed] = useState(false); - - useEffect(() => { - ContentstackAppSDK.init() - .then(async (sdk) => { - setAppSdk(sdk); - const appConfig = await sdk.getConfig(); - setConfig(appConfig); - }) - .catch(() => { - setFailed(true); - }); - }, []); - - if (failed) return
Failed to initialize SDK
; - if (!appSdk) return
Loading...
; - - return ( - - {children} - - ); -} -``` - -### Using the SDK Hook - -```typescript -// hooks/useAppSdk.tsx -import { useContext } from "react"; -import { MarketplaceContext } from "../contexts/marketplaceContext"; - -export function useAppSdk() { - const { appSdk } = useContext(MarketplaceContext); - if (!appSdk) { - throw new Error("useAppSdk must be used within MarketplaceAppProvider"); - } - return appSdk; -} -``` - -### App Root Setup - -```typescript -// App.tsx -import { MarketplaceAppProvider } from "./providers/MarketplaceAppProvider"; -import { BrowserRouter } from "react-router-dom"; - -function App() { - return ( - - {/* Your routes */} - - ); -} -``` - ---- - -## UI Location Implementations - -### Asset Sidebar Widget - -The Asset Sidebar appears when viewing or editing an asset in Contentstack's Asset Library. - -```typescript -// containers/AssetSidebarWidget/AssetSidebar.tsx -import { useState, useEffect } from "react"; -import { useAppSdk } from "@/common/hooks/useAppSdk"; - -export function AssetSidebar() { - const appSdk = useAppSdk(); - const [asset, setAsset] = useState(null); - const [loading, setLoading] = useState(true); - - // Get asset sidebar location - const assetSidebar = (appSdk?.location as any)?.AssetSidebarWidget; - - useEffect(() => { - if (assetSidebar) { - // Get current asset data - assetSidebar.getData().then((data) => { - setAsset(data); - setLoading(false); - }); - } - }, [assetSidebar]); - - // Replace asset with new file - const replaceAsset = async (file: File) => { - try { - await assetSidebar.replaceAsset(file); - // Refresh asset data - const updated = await assetSidebar.getData(); - setAsset(updated); - } catch (error) { - console.error("Failed to replace asset:", error); - } - }; - - if (loading) return
Loading asset...
; - - return ( -
-

Asset: {asset?.title}

-

Type: {asset?.content_type}

-

Size: {asset?.file_size} bytes

- {/* Your custom UI */} -
- ); -} -``` - -**Available Methods:** - -- `getData()` - Get current asset data -- `replaceAsset(file)` - Replace asset with new file -- `onAssetChange(callback)` - Listen for asset changes - -### Entry Sidebar Widget - -The Entry Sidebar appears when editing a content entry. - -```typescript -// containers/EntrySidebar/EntrySidebar.tsx -import { useState, useEffect } from "react"; -import { useAppSdk } from "@/common/hooks/useAppSdk"; - -export function EntrySidebar() { - const appSdk = useAppSdk(); - const [entry, setEntry] = useState(null); - - const sidebar = appSdk?.location?.SidebarWidget; - - useEffect(() => { - if (sidebar) { - // Get entry data - sidebar.getData().then(setEntry); - - // Listen for save events - sidebar.onSave(() => { - console.log("Entry saved"); - // Refresh entry data - sidebar.getData().then(setEntry); - }); - - // Listen for publish events - sidebar.onPublish(() => { - console.log("Entry published"); - }); - } - }, [sidebar]); - - // Update field value - const setFieldValue = async (field: string, value: any) => { - try { - await sidebar.entry.setField(field, value); - // Refresh entry data - const updated = await sidebar.getData(); - setEntry(updated); - } catch (error) { - console.error("Failed to set field:", error); - } - }; - - if (!entry) return
Loading entry...
; - - return ( -
-

Entry: {entry?.title}

-

Content Type: {entry?.content_type_uid}

- {/* Your custom UI */} -
- ); -} -``` - -**Available Methods:** - -- `getData()` - Get current entry data -- `entry.setField(field, value)` - Update field value -- `entry.getField(field)` - Get field value -- `onSave(callback)` - Listen for save events -- `onPublish(callback)` - Listen for publish events - -### Custom Field - -Custom fields allow you to create custom input types for content types. - -```typescript -// containers/CustomField/CustomField.tsx -import { useState, useEffect } from "react"; -import { useAppSdk } from "@/common/hooks/useAppSdk"; - -export function CustomField() { - const appSdk = useAppSdk(); - const [value, setValue] = useState(""); - const [fieldConfig, setFieldConfig] = useState(null); - - const customField = appSdk?.location?.CustomField; - - useEffect(() => { - if (customField) { - // Get initial value - customField.field.getData().then(setValue); - - // Get field configuration - customField.field.getConfig().then(setFieldConfig); - } - }, [customField]); - - const handleChange = async (newValue: string) => { - setValue(newValue); - // Update field value - await customField.field.setData(newValue); - }; - - return ( -
- - handleChange(e.target.value)} - placeholder={fieldConfig?.placeholder} - /> -
- ); -} -``` - -**Available Methods:** - -- `field.getData()` - Get current field value -- `field.setData(value)` - Set field value -- `field.getConfig()` - Get field configuration -- `field.setFocus()` - Focus the field - -### Dashboard Widget - -Dashboard widgets appear on the stack dashboard. - -```typescript -// containers/Dashboard/Dashboard.tsx -import { useEffect, useState } from "react"; -import { useAppSdk } from "@/common/hooks/useAppSdk"; - -export function Dashboard() { - const appSdk = useAppSdk(); - const [stackInfo, setStackInfo] = useState(null); - - useEffect(() => { - if (appSdk) { - const stack = appSdk.stack; - setStackInfo({ - apiKey: stack.getApiKey(), - name: stack.getName(), - // ... other stack info - }); - } - }, [appSdk]); - - return ( -
-

Stack: {stackInfo?.name}

-

API Key: {stackInfo?.apiKey}

- {/* Your dashboard widget UI */} -
- ); -} -``` - -### App Configuration Page - -The App Configuration page allows users to configure app settings. - -```typescript -// containers/AppConfiguration/AppConfiguration.tsx -import { useState, useEffect } from "react"; -import { useAppSdk } from "@/common/hooks/useAppSdk"; - -export function AppConfiguration() { - const appSdk = useAppSdk(); - const [config, setConfig] = useState({ apiKey: "", enabled: false }); - const [saving, setSaving] = useState(false); - - const appConfig = appSdk?.location?.AppConfigWidget; - - useEffect(() => { - if (appConfig) { - // Load existing config - appConfig.getConfig().then(setConfig); - } - }, [appConfig]); - - const saveConfig = async () => { - setSaving(true); - try { - await appConfig.setConfig(config); - // Show success message - } catch (error) { - console.error("Failed to save config:", error); - } finally { - setSaving(false); - } - }; - - return ( -
-

App Configuration

- - - -
- ); -} -``` - -**Available Methods:** - -- `getConfig()` - Get app configuration -- `setConfig(config)` - Save app configuration - ---- - -## API Proxy - -Use `appSdk.api()` to make external API calls through Contentstack's secure proxy. This allows you to: - -- Keep API keys secure (stored in Developer Hub Advanced Settings) -- Avoid CORS issues -- Use variable substitution for credentials - -### Basic Usage - -```typescript -// Make API request through Contentstack proxy -const response = await appSdk.api("/external-api/endpoint", { - method: "POST", - headers: { - "x-api-key": "{{var.API_KEY}}", // Variable substitution - "Content-Type": "application/json", - }, - body: JSON.stringify(data), -}); - -const data = await response.json(); -``` - -### Variable Substitution - -Variables are configured in Developer Hub Advanced Settings and automatically substituted: - -```typescript -// In your code -headers: { - "x-api-key": "{{var.API_KEY}}", - "authorization": "Bearer {{var.ACCESS_TOKEN}}", -} - -// Contentstack replaces with actual values from Advanced Settings -``` - -### API Rewrites - -Configure URL rewrites in Developer Hub Advanced Settings: - -- **Pattern**: `/external-api/*` -- **Target**: `https://api.example.com/*` - -This allows you to use relative paths in your code while Contentstack proxies to the actual API. - -### Complete Example - -```typescript -async function callExternalAPI(prompt: string) { - const appSdk = useAppSdk(); - - try { - const response = await appSdk.api( - "/genai/gemini-2.5-flash-image:generateContent", - { - method: "POST", - headers: { - "x-goog-api-key": "{{var.GEMINI_API_KEY}}", - "Content-Type": "application/json", - }, - body: JSON.stringify({ - contents: [ - { - parts: [ - { text: prompt }, - { inline_data: { mime_type: "image/jpeg", data: base64Image } }, - ], - }, - ], - }), - } - ); - - if (!response.ok) { - throw new Error(`API error: ${response.status}`); - } - - return await response.json(); - } catch (error) { - console.error("API call failed:", error); - throw error; - } -} -``` - ---- - -## Frame Management - -Control the iframe dimensions to ensure your app displays correctly: - -```typescript -const appSdk = useAppSdk(); - -// Auto-resize iframe based on content -appSdk.location.frame?.autoResizeFrame(); - -// Set specific height -appSdk.location.frame?.setFrameHeight(400); - -// Enable auto-resize with options -appSdk.location.frame?.enableAutoResizing({ - height: true, - width: false, -}); -``` - -**Best Practice**: Use `autoResizeFrame()` for dynamic content that changes height. - ---- - -## Accessing Configuration - -### Get App Configuration - -```typescript -const appSdk = useAppSdk(); - -// Get configuration (set in App Configuration location) -const config = await appSdk.getConfig(); -console.log(config.apiKey); -console.log(config.enabled); -``` - -### Get Stack Information - -```typescript -const appSdk = useAppSdk(); -const stack = appSdk.stack; - -console.log(stack.getApiKey()); -console.log(stack.getName()); -console.log(stack.getUid()); -``` - ---- - -## Development Workflow - -### 1. Local Development Setup - -```bash -# Clone boilerplate -git clone https://github.com/contentstack/marketplace-app-boilerplate -cd marketplace-app-boilerplate - -# Install dependencies -npm install - -# Start dev server -npm run dev -``` - -Runs on `http://localhost:3000` - -### 2. Configure in Developer Hub - -1. **Create App**: - - - Go to Contentstack Developer Hub - - Click "Create App" - - Fill in app details (name, description, icon) - -2. **Set Base URL**: - - - Set base URL to `http://localhost:3000` (for development) - - Or use tunneling service (ngrok, Cloudflare Tunnel) for HTTPS - -3. **Configure UI Locations**: - - - Add UI locations you want to support - - Set route paths (e.g., `/asset-sidebar`) - -4. **Configure Advanced Settings** (if needed): - - **API Rewrites**: Add rewrite rules for external APIs - - **Variables**: Add variables for API keys (accessed via `{{var.NAME}}`) - -### 3. Install and Test - -1. **Install App**: - - - Go to your test stack - - Navigate to Apps - - Install your app - -2. **Test Locations**: - - Open Asset Library → View asset → Check sidebar - - Edit entry → Check sidebar - - Go to Dashboard → Check widget - - Configure app settings → Check config page - -### 4. Building for Production - -```bash -npm run build -``` - -Outputs to `dist/` directory. - -### 5. Deploy - -1. Deploy `dist/` folder to hosting provider (Vercel, Netlify, AWS, etc.) -2. Update app configuration in Developer Hub with production URL -3. Update manifest settings if needed - ---- - -## Error Handling - -Always handle errors gracefully: - -```typescript -try { - const data = await assetSidebar.getData(); - setAsset(data); -} catch (error) { - console.error("Failed to get asset:", error); - // Show user-friendly error message - setError("Unable to load asset. Please try again."); -} -``` - -### Common Error Scenarios - -- **SDK not initialized**: Ensure `MarketplaceAppProvider` wraps your app -- **Location not available**: Check if location is configured in Developer Hub -- **API call failed**: Verify API rewrites and variables are configured -- **Permission denied**: Check app permissions in Developer Hub - ---- - -## Best Practices - -| Do | Don't | -| -------------------------------- | ---------------------------------- | -| Initialize SDK once at root | Re-initialize on every render | -| Handle loading states | Show blank screens | -| Handle errors gracefully | Let errors crash app | -| Use TypeScript | Skip type safety | -| Test in Contentstack iframe | Only test standalone | -| Use config for secrets | Hardcode API keys | -| Use API proxy for external calls | Make direct API calls from browser | -| Auto-resize iframe | Use fixed heights | -| Validate user input | Trust all input | -| Provide user feedback | Silent failures | - ---- - -## Testing - -### Unit Tests - -```typescript -// __tests__/AssetSidebar.test.tsx -import { render, screen } from "@testing-library/react"; -import { AssetSidebar } from "../AssetSidebar"; - -// Mock SDK -jest.mock("@/common/hooks/useAppSdk", () => ({ - useAppSdk: () => ({ - location: { - AssetSidebarWidget: { - getData: jest.fn().mockResolvedValue({ title: "Test Asset" }), - }, - }, - }), -})); - -test("renders asset title", async () => { - render(); - expect(await screen.findByText("Test Asset")).toBeInTheDocument(); -}); -``` - -### E2E Tests (Playwright) - -```typescript -// e2e/asset-sidebar.spec.ts -import { test, expect } from "@playwright/test"; - -test("asset sidebar loads", async ({ page }) => { - await page.goto("http://localhost:3000/asset-sidebar"); - await expect(page.locator("h2")).toContainText("Asset:"); -}); -``` - ---- - -## Troubleshooting - -### App Not Loading - -1. Check browser console for errors -2. Verify base URL is correct in Developer Hub -3. Check if app is installed on the stack -4. Verify HTTPS if using production URL - -### SDK Not Initializing - -1. Check if `MarketplaceAppProvider` wraps your app -2. Verify authentication token in URL -3. Check browser console for SDK errors -4. Ensure app is properly installed - -### Location Not Available - -1. Verify location is configured in Developer Hub manifest -2. Check route path matches configuration -3. Ensure location is enabled for the app - -### API Calls Failing - -1. Verify API rewrites are configured in Advanced Settings -2. Check variables are set correctly (`{{var.NAME}}`) -3. Verify rewrite patterns match your API paths -4. Check network tab for actual request URLs - ---- - -## Resources - -- [Contentstack Developer Hub Documentation](https://www.contentstack.com/docs/developers/developer-hub) -- [Contentstack App SDK Reference](https://www.contentstack.com/docs/developers/developer-hub/contentstack-app-development) -- [UI Locations Reference](https://www.contentstack.com/docs/developers/developer-hub/managing-ui-locations) -- [Marketplace App Boilerplate (GitHub)](https://github.com/contentstack/marketplace-app-boilerplate) -- [Marketplace App Boilerplate Documentation](https://www.contentstack.com/docs/developers/developer-hub/marketplace-app-boilerplate) \ No newline at end of file diff --git a/codex/dx-delivery-sdk/SKILL.md b/codex/dx-delivery-sdk/SKILL.md deleted file mode 100644 index cbf7e2f..0000000 --- a/codex/dx-delivery-sdk/SKILL.md +++ /dev/null @@ -1,336 +0,0 @@ -# dx-delivery-sdk - - -# dx-delivery-sdk - -## Description - -Help agents write correct, production-ready TypeScript using `@contentstack/delivery-sdk` for Contentstack entries, assets, references, filtering, sorting, pagination, locale, Live Preview, and Visual Builder support. Verify SDK behavior against the Delivery SDK Spec when method names, options, or chain order matter. - -## When to Use - -Use when a user asks for Contentstack Delivery SDK code, query examples, helper functions, SDK setup, stack initialization, reference inclusion, filtering, sorting, pagination, typed entry fetching, asset fetching, Live Preview setup, Visual Builder support, SSR preview handling, or debugging SDK query chains. - -## User Problem - -Users need current, correct Contentstack Delivery SDK code with the right method names, chain order, and query patterns. The skill should prevent subtle SDK mistakes and default to production-ready TypeScript. - -## Success Criteria - -- Uses current `@contentstack/delivery-sdk` method names and correct chain order. -- Verifies API details against the Delivery SDK Spec when behavior is uncertain. -- Produces TypeScript-first examples with safe environment-based credentials. -- Handles references, filters, sorting, pagination, field selection, assets, locale, and Live Preview correctly. -- Flags or avoids common mistakes such as wrong query methods, missing pagination, or shared SSR Live Preview stacks. - -## Expected Inputs - -- Content type UID -- Entry UID or asset UID when applicable -- Field UIDs for filters, sorting, selection, or references -- Locale when localized content is needed -- Desired return shape or helper function behavior -- SSR or Visual Builder context when Live Preview is involved - -## Expected Outputs - -- TypeScript code snippets -- Reusable helper functions -- Correct SDK query chains -- Live Preview or SSR-safe stack setup -- Debugging guidance for incorrect Contentstack SDK usage - -## Example User Requests - -- Write a Contentstack Delivery SDK query for blog posts with author references included. -- Show me the correct TypeScript setup for Contentstack Live Preview in Next.js SSR. -- Fix this Contentstack query chain; it is not returning the right entries. -- Create a helper to fetch entries by URL with pagination and typing. -- How do I fetch assets and filter by content type in `@contentstack/delivery-sdk`? - -## Workflow Summary - -1. Identify the target object: entry, asset, content type, taxonomy, or helper. -2. Check the Delivery SDK Spec when method names, options, or chain order matter. -3. Ask only for missing inputs needed to build the query correctly. -4. Choose the correct SDK chain and method order. -5. Add pagination, locale, field selection, and references as needed. -6. Use safe TypeScript types and reusable helpers. -7. Include error handling and common-mistake warnings when relevant. - -## Instructions - -### Identify the target - -Determine whether the request is for entries, assets, taxonomy, references, Live Preview, or a reusable helper. Ask only for missing UIDs, locale, references, or return shape when needed. - -### Verify SDK behavior - -Use the Delivery SDK Spec as the source of truth for method names, supported options, and chain order. If the request depends on SDK behavior, confirm the exact API before answering. - -### Use current SDK patterns - -Prefer TypeScript and the current `@contentstack/delivery-sdk` API. Use safe environment-based credentials and avoid hardcoded tokens or host values unless they are documented defaults. - -### Build correct queries - -Apply references before `.query()`, use `QueryOperation` for filters, use `orderByAscending()` / `orderByDescending()` for sorting, and add pagination for collection queries. - -### Handle Live Preview safely - -For SSR or Visual Builder, create a new stack per request and apply live preview configuration before fetching. Do not reuse a Live Preview stack across requests. - -## Output Format - -Prefer TypeScript. -Use concise, production-ready code blocks. -Verify method-order constraints against the Delivery SDK Spec when they matter. -Do not hardcode credentials. -Call out pagination limits when returning multiple entries. -Include brief notes for Live Preview or SSR safety when relevant. - -## Tooling Notes - -Prefer `@contentstack/delivery-sdk` as the primary SDK. -Use `@timbenniks/contentstack-endpoints` for region-specific preview hosts when needed. -Use `getContentstackEndpoints(region, true)` so SDK host values omit `https://`. -For SSR Live Preview or Visual Builder, create a new stack per request. - -## Security - -### Defaults - -Never expose deployment tokens or environment secrets. -Validate deployment targets before triggering. -Require confirmation for production deployments. -Never auto-deploy to production without review. -Never hardcode Contentstack credentials in examples. -Avoid sharing preview tokens or other secrets in responses. -For SSR Live Preview, do not reuse a stack instance across requests. - -### Destructive Actions - -This skill does not perform destructive actions. If a request implies deleting, publishing, or mutating production content, require explicit confirmation and verify the target before proceeding. - -### Secrets - -Use environment variables for all credentials and tokens. Never print, infer, or echo secrets. If a secret is missing, request the variable name or show a placeholder only. - -### Environment Variables - -Use `process.env` placeholders in examples. Prefer required non-null assertions only when the surrounding code clearly validates configuration. Do not suggest committing secrets to source control. - -## Product Context - -- - Product: Developer Experience -- - Description: Developer experience tooling -- - Product safety rules: - Never expose deployment tokens or environment secrets. -- Validate deployment targets before triggering. -- Require confirmation for production deployments. -- Never auto-deploy to production without review. - -## References - -This skill ships reference material in the `references/` folder. Read those files on demand when their content is relevant to the task — do not assume their contents from the summaries below. - -### [Delivery SDK Spec](references/delivery-sdk-spec.md) (product doc, required) -- Source: Official Docs (https://www.contentstack.com/docs/developers/sdks/content-delivery-sdk/typescript/reference.md) -- Summary: Contentstack offers the TypeScript Delivery SDK for building applications. Below, is an in-depth guide and valuable resources to initiate your journey with our TypeScript Delivery SDK. Additionally, the SDK supports the creating applications for Node.js and React Native environments. -- Read: `references/delivery-sdk-spec.md` - -## Examples - -### Stack setup (few shot *) - -**User:** Set up the Contentstack Delivery SDK in TypeScript. - -**Assistant:** ```ts -import contentstack, { QueryOperation } from "@contentstack/delivery-sdk"; - -const stack = contentstack.stack({ - apiKey: process.env.CONTENTSTACK_API_KEY!, - deliveryToken: process.env.CONTENTSTACK_DELIVERY_TOKEN!, - environment: process.env.CONTENTSTACK_ENVIRONMENT!, - region: process.env.CONTENTSTACK_REGION || "us", -}); -``` - -*Default stack setup with env vars and current import style.* - -### Live Preview stack factory (few shot *) - -**User:** Show the recommended SSR Live Preview setup. - -**Assistant:** ```ts -import contentstack from "@contentstack/delivery-sdk"; - -export function createStack() { - return contentstack.stack({ - apiKey: process.env.CONTENTSTACK_API_KEY!, - deliveryToken: process.env.CONTENTSTACK_DELIVERY_TOKEN!, - environment: process.env.CONTENTSTACK_ENVIRONMENT!, - region: process.env.CONTENTSTACK_REGION || "us", - live_preview: { - enable: true, - preview_token: process.env.CONTENTSTACK_PREVIEW_TOKEN, - host: "rest-preview.contentstack.com", - }, - }); -} -``` - -*Per-request factory for SSR or Visual Builder.* - -### Single entry fetch (few shot *) - -**User:** Fetch one blog post by UID. - -**Assistant:** ```ts -const entry = await stack.contentType("blog_post").entry("entry_uid").fetch(); -``` - -*Use direct fetch for single entries.* - -### Entry query (few shot *) - -**User:** Fetch multiple blog posts. - -**Assistant:** ```ts -const result = await stack.contentType("blog_post").entry().query().find(); -const entries = result.entries; -``` - -*Use query().find() for collections.* - -### References (few shot *) - -**User:** Include author and category references. - -**Assistant:** ```ts -const result = await stack - .contentType("blog_post") - .entry() - .includeReference(["author", "category"]) - .query() - .find(); -``` - -*`includeReference()` belongs before `.query()`.* - -### Filtering (few shot *) - -**User:** Filter by title. - -**Assistant:** ```ts -const result = await stack - .contentType("blog_post") - .entry() - .query() - .where("title", QueryOperation.EQUALS, "My Post") - .find(); -``` - -*Use `QueryOperation` names exactly.* - -### Sorting (few shot *) - -**User:** Sort by publish date descending. - -**Assistant:** ```ts -const result = await stack - .contentType("blog_post") - .entry() - .query() - .orderByDescending("published_date") - .find(); -``` - -*Never use `.descending()`.* - -### Pagination (few shot *) - -**User:** Return page 1 with 10 items and total count. - -**Assistant:** ```ts -const result = await stack - .contentType("blog_post") - .entry() - .query() - .skip(0) - .limit(10) - .includeCount() - .find(); -``` - -*Mention the 100-item default limit when pagination is omitted.* - -### Field selection (few shot *) - -**User:** Only fetch title and url. - -**Assistant:** ```ts -const result = await stack - .contentType("blog_post") - .entry() - .query() - .only(["title", "url"]) - .find(); -``` - -*Use `only()` and `except()` for payload control.* - -### Asset fetch and query (few shot *) - -**User:** Fetch an asset and query JPEG assets. - -**Assistant:** ```ts -const asset = await stack.asset("asset_uid").fetch(); - -const result = await stack - .asset() - .query() - .where("content_type", QueryOperation.EQUALS, "image/jpeg") - .find(); -``` - -*Support both direct fetch and asset queries.* - -### Helper function pattern (few shot *) - -**User:** Create reusable helpers for fetching entries. - -**Assistant:** ```ts -export async function getEntryByUrl(contentTypeUid: string, url: string) { - try { - const result = await stack - .contentType(contentTypeUid) - .entry() - .query() - .where("url", QueryOperation.EQUALS, url) - .includeCount() - .find(); - - return result.entries[0] || null; - } catch (error) { - if (error instanceof Error) { - console.error("Failed to fetch entry by url:", error.message); - } - return null; - } -} -``` - -*Include safe error handling in reusable helpers.* - -### Common mistakes checklist (edge case *) - -**User:** What mistakes should I avoid with the Delivery SDK? - -**Assistant:** - Do not call `includeReference()` after `.query()`. -- Use `orderByAscending()` / `orderByDescending()`, not `ascending()` / `descending()`. -- Use `QueryOperation.NOT_EQUALS`, not `NOT_EQUAL`. -- Do not hardcode credentials. -- Add pagination for collection queries. -- Do not reuse a Live Preview SSR stack across requests. - -*Use as a compact guardrail response.* diff --git a/codex/dx-delivery-sdk/references/delivery-sdk-spec.md b/codex/dx-delivery-sdk/references/delivery-sdk-spec.md deleted file mode 100644 index 1ea01a3..0000000 --- a/codex/dx-delivery-sdk/references/delivery-sdk-spec.md +++ /dev/null @@ -1,1157 +0,0 @@ ---- -title: "TypeScript Delivery SDK API Reference" -description: "Reference guide for Contentstack's TypeScript Delivery SDK: Explore features and functions for seamless content delivery in your projects" -url: "https://www.contentstack.com/docs/developers/sdks/content-delivery-sdk/typescript/reference.md" -product: "Contentstack" -doc_type: "guide" -audience: - - developers - - admins -version: "current" -last_updated: "2026-02-27" ---- - -# TypeScript Delivery SDK API Reference - -## TypeScript Delivery SDK API Reference - -## Overview - -Contentstack offers the TypeScript Delivery SDK for building applications. Below, is an in-depth guide and valuable resources to initiate your journey with our TypeScript Delivery SDK. Additionally, the SDK supports the creating applications for Node.js and React Native environments. - -**Additional Resource**: To know more about the TypeScript Delivery SDK, refer to the [About TypeScript Delivery SDK](https://www.contentstack.com/docs/developers/sdks/content-delivery-sdk/typescript/about-typescript-delivery-sdk.md) and [Get Started with TypeScript Delivery SDK](https://www.contentstack.com/docs/developers/sdks/content-delivery-sdk/typescript/get-started-with-typescript-delivery-sdk.md) documentation. - -## Contentstack - -The Contentstack module contains the instance of a stack. To import Contentstack, refer to the code below: - -import contentstack from '@contentstack/delivery-sdk'; - -## Stack - -A [stack](https://www.contentstack.com/docs/developers/set-up-stack/about-stack.md) is a repository or a container that holds all the [entries](https://www.contentstack.com/docs/content-managers/author-content/about-entries.md)/[assets](https://www.contentstack.com/docs/content-managers/working-with-assets/about-assets.md) of your site. It allows multiple users to [create](https://www.contentstack.com/docs/content-managers/working-with-entries/create-an-entry.md), [edit](https://www.contentstack.com/docs/content-managers/working-with-entries/edit-an-entry.md), [approve](https://www.contentstack.com/docs/content-managers/use-workflows/send-an-entry-for-publish-or-unpublish-approval.md), and [publish](https://www.contentstack.com/docs/content-managers/publish-content.md) their content within a single space. - -The stack function initializes an instance of the Stack. To initialize a stack execute the following code: - -import contentstack from '@contentstack/delivery-sdk' -const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); - -## LivePreviewConfig - -Configuration settings to enable live preview functionality and fetch real-time content data. - -Specifies whether to enable the live preview feature. - -Specifies the host domain used to retrieve live preview content. - -Token required to fetch live preview content from the stack. - -## Plugins - -When creating custom plugins, through this request, you can pass the details of your custom plugins. This facilitates their utilization in subsequent requests when retrieving details. - -To initializing a stack with plugins, refer to the code snippet below: - -// custom class for plugin -class CrossStackPlugin { - onRequest (request) { - // add request modifications - - return request - -} - async onResponse (request, response, data) { - // add response modifications here - - return response - -} -} -const Stack = Contentstack.stack({ - api_key, - delivery_token, - environment, - plugins: \[ - new CrossStackPlugin(), - \] -}); - -## Asset - -The Asset method by default creates an object for all assets of a stack. To retrieve a single asset, specify its UID. - -UID of the asset - -## ContentType - -The ContentType method retrieves all the content types of a stack. To retrieve a single contenttype, specify its UID. - -UID of the content type - -## setLocale - -The setLocale method sets the locale of the API server. - -Enter the locale code - -## sync - -The sync method syncs your Contentstack data with your app and ensures that the data is always up-to-date by providing delta updates. - -An object that supports ‘locale’, ‘start_date’, ‘content_type_uid’, and ‘type’ queries - -Specifies if the sync should be recursive - -API key of the stack - -Delivery token to retrieve data from the stack - -Environment name where content is published - -The Live preview configuration for the Contentstack API - -Name of the branch to fetch data from - -Sets the host of the API server -(example: "dev.contentstack.com") - -Region of the stack. You can choose from five regions: NA, EU, Azure NA, Azure EU, GCP NA, and GCP EU. - -Lets you specify which language to use as source content if the entry does not exist in the specified language. - -Specifies the caching strategy. Accepts a string value from the Policy enum. - -Defines where the cache is stored. Accepts localStorage or memoryStorage as string values. - -Sets the maximum age (in milliseconds) before the cache expires. - -Function to serialize data before storing it in the cache. - -Function to deserialize data when retrieving it from the cache. - -Set early access headers - -Method to enable custom logging in the SDK - -Add custom plugins to the SDK - -## Asset - -In Contentstack, any files (images, videos, PDFs, audio files, and so on) that you upload get stored in your repository for future use. This repository of uploaded files is called [assets](https://www.contentstack.com/docs/content-managers/author-content/about-assets.md). - -The Asset method by default creates an object for all assets of a stack. To retrieve a single asset, specify its UID. - -**Example:** - -import contentstack from '@contentstack/delivery-sdk'; - -import { BaseAsset } from '@contentstack/delivery-sdk'; - -const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); - -interface BlogAsset extends BaseAsset { - - title: string; - - description: string; - - url: string; - - // Add other custom properties as needed - -} - -async function fetchAssets() { - - try { - - const result = await stack.asset(asset\_uid).fetch(); - - console.log('Assets Fetched:', assets); - -//Add your statements - - } catch (error) { - - console.error('Error fetching asset:', error); - - } - -} - -fetchAssets(); - -## fetch - -The fetch method retrieves the asset data of the specified asset. - -## includeBranch - -The includeBranch method includes the branch details in the response. - -## includeDimension - -The includeDimension method includes the dimensions (height and width) of the image in the result. - -## includeFallback - -The includeFallback method retrieves the entry in its fallback language. - -## locale - -The locale method retrieves the assets published in that locale. - -## relativeUrls - -The relativeUrls method includes the relative URLs of the asset in the result. - -## version - -The version method retrieves the specified version of the asset in the result. - -Version of the required asset - -## includeMetadata - -The includeMetadata method includes the metadata for getting metadata content for the entry. - -## assetFields - -The assetFields method determines the optional asset field groups to include in the response. - -**Note:** The assetFields method is supported only in the North America (NA) region. - -**Response Behavior:** - -- Retrieves only the requested asset metadata, keeping asset payloads smaller. -- Applies to published assets from the asset API. It applies to both single-asset responses and multi-asset responses. -- Does not filter which assets appear in the response or restrict them by file type (MIME). -- Requests optional metadata groups in addition to the core fields on BaseAsset, such as the file MIME type (content_type) and the folder flag (is_dir). It does not replace or modify those fields. - -**Note:** On asset objects, content_type represents the file’s MIME type, not a Contentstack CMS content type. - -**Supported field groups (values):** - -- user_defined_fields: Includes stack-defined custom fields on the asset (author-managed key-value data). -- embedded_metadata: Includes metadata extracted from the file (e.g, EXIF or IPTC). -- ai_generated_metadata: Includes AI-generated data (e.g., tags, descriptions, classifications). -- visual_markups: Includes annotation data (e.g., regions, notes, overlays) - -Keys that specify asset field groups to retrieve. Provide them as arguments before .fetch() or .find(). - -UID of the asset - -## Asset Collection - -The Asset Collection provides methods for filtering and retrieving assets stored in Contentstack. You can retrieve specific assets by UID, tags, or metadata. - -**Example:** - -const result = stack.asset().find() - -.then((assets) => console.log(assets)) - -.catch((error) => console.error("Error fetching assets:", error)); - -## addParams - -The addParam method adds a query parameter to the query. - -Add key-value pairs - -## find - -The find method retrieves all the assets of the stack. - -## includeBranch - -The includeBranch method includes the branch details in the result. - -## includeCount - -The includeCount method retrieves count and data of all the objects in the result. - -## includeDimension - -The includeDimension method includes the dimensions (height and width) of the image in the result - -## includeFallback - -The includeFallback method retrieves the entry in its fallback language. - -## locale - -The locale method retrieves the asset published in the specified locale. - -Locale of the asset - -## orderByAscending - -The orderByAscending method sorts the results in ascending order based on the specified field UID. - -Field UID to sort the results - -## orderByDescending - -The orderByDescending method sorts the results in descending order based on the specified key. - -Field UID to sort the results - -## param - -The param method adds query parameters to the URL. - -Add any param to include in the response - -Add the corresponding value of the param key - -## relativeUrls - -The relativeUrls method includes the relative URLs of all the assets in the result. - -## removeParam - -The removeParam method removes a query parameter from the query. - -Specify the param key you want to remove - -## version - -The version method retrieves a specific version of the asset in the result. - -Version number of the asset - -## where - -The where method filters the results based on the specified criteria. - -Specify the field the comparison is made from - -Specify the comparison criteria - -Specify the field the comparison is made to - -## includeMetadata - -The includeMetadata method includes the metadata for getting metadata content for the entry. - -## skip - -The skip method will skip a specific number of assets in the output. - -Enter the number of assets to be skipped. - -## limit - -The limit method will return a specific number of assets in the output. - -Enter the maximum number of assets to be returned. - -## ContentType - -A [content type](https://www.contentstack.com/docs/developers/create-content-types/about-content-types.md) is the structure or blueprint of a page or a section that your web or mobile property will display. It lets you define the overall schema of this blueprint by adding fields and setting its properties. - -**Example:** - -import { BaseContentType } from '@contentstack/delivery-sdk' - -interface BlogPost extends BaseContentType { - -text: string; - -// other custom props - -} - -async function fetchContentType() { - -try { - -const contentType = await stack.contentType("blog").fetch(); - -console.log(contentType); - -//Add your statements - - } catch (error) { - -console.error("Error fetching content type:", error); - -} - -} - -fetchContentType(); - -## entry - -The entry method creates an entry object for the specified entry. - -UID of the entry - -## fetch - -The fetch method retrieves the details for the specified content type. - -UID of the content type - -## ContentType Collection - -The ContentType Collection method retrieves a list of all content types available within a stack. It provides metadata and structural details for each content type but does not retrieve actual content entries. - -**Example:** - -const contentType = await stack.contentType().find(); - -## find - -The find method retrieves all the content types of the stack. - -## includeGlobalFieldSchema - -The includeGlobalFieldSchema method includes the schema of the global field in the response. - -## Entry - -An [Entry](https://www.contentstack.com/docs/content-managers/author-content/about-entries.md) is the actual piece of content created using one of the defined content types. To work with a single entry, specify its UID. - -**Example:** - -import contentstack from '@contentstack/delivery-sdk' - -import { BaseEntry } from '@contentstack/delivery-sdk' - -const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); - -interface BlogPostEntry extends BaseEntry { - -// custom entry types - -} - -async function fetchEntry() { - - try { - -const result = await stack.contentType(contenttype_uid).entry(entry_uid).fetch(); - - console.log('Entry: ', result); - -//Add your statements - - } catch (error) { - - console.error('Error fetching entry:', error); - -} - -} - -fetchEntry(); - -## fetch - -The fetch method retrieves the details of a specific entry. - -## includeBranch - -The includeBranch method includes the branch details in the result. - -## includeFallback - -The includeFallback method retrieves the entry in its fallback language. - -## locale - -The locale method retrieves the entries published in that locale. - -Locale of the entry - -## addParams - -The addParam method adds a query parameter to the query. - -Add key-value pairs - -## except - -The except method excludes specific field(s) of an entry. - -UID of the field to exclude - -## find - -The find method retrieves the details of the specified entry. - -## skip - -The skip method will skip a specific number of entries in the output. - -Enter the number of entries to be skipped. - -## limit - -The limit method will return a specific number of entries in the output. - -Enter the maximum number of entries to be returned. - -## includeCount - -The includeCount method retrieves the count and data of objects in the result. - -## only - -The only method selects specific field(s) of an entry. - -UID of the field to select - -## orderByAscending - -The orderByAscending sorts the results in ascending order based on the specified field UID. - -Field UID to sort the results - -## orderByDescending - -The orderByDescending sorts the results in descending order based on the specified field UID. - -Field UID to sort the results - -## param - -The param method adds query parameters to the URL. - -Add any param to include in the response - -Add the corresponding value of the param key - -## query - -The query method retrieves the details of the entry on the basis of the queries applied. - -Query in object format - -## removeParam - -The removeParam method removes a query parameter from the query. - -Specify the param key you want to remove - -## where - -The where method filters the results based on the specified criteria. - -Specify the field the comparison is made from - -Specify the comparison criteria - -Specify the field the comparison is made to - -## includeMetadata - -The includeMetadata method includes the metadata for getting metadata content for the entry. - -## includeEmbeddedItems - -The includeEmbeddedItems method includes embedded objects (Entry and Assets) along with entry details - -## includeContentType - -The includeContentType method includes the details of the content type along with the Entry details. - -## includeReference - -The includeReference method retrieves the content of the referred entries in your response. - -UID of the reference field to include - -## Variants - -Variants are different versions of content designed to meet specific needs or target audiences. This feature allows content editors to create multiple variations of a single entry, each customized for a particular variant group or purpose. - -When Personalize creates a variant in the CMS, it assigns a "Variant Alias" to identify that specific variant. When fetching entry variants using the Delivery API, you can pass variant aliases in place of variant UIDs in the x-cs-variant-uid header. - -## assetFields - -The assetFields method specifies the optional asset field groups to include for assets returned with an entry. - -**Note:** The assetFields method is supported only in the North America (NA) region. - -**Response Behavior:** - -- Retrieves only the required asset metadata, keeping the entry payloads smaller when entries reference assets. -- Applies to published assets referenced or embedded on the entry. It applies to both single-entry and multi-entry responses. -- Adds optional metadata fields to each asset in the response. It does not filter assets or control file types. -- Requests optional metadata groups in addition to standard asset fields such as file MIME type (content_type) and folder flag (is_dir). It does not replace or modify core asset fields. - -**Note:** On asset objects, content_type represents the file’s MIME type, not a Contentstack CMS content type. - -**Supported field groups (values):** - -- user_defined_fields: Includes stack-defined custom fields on the asset (author-managed key-value data). -- embedded_metadata: Includes metadata extracted from the file (e.g, EXIF or IPTC). -- ai_generated_metadata: Includes AI-generated data (e.g., tags, descriptions, classifications). -- visual_markups: Includes annotation data (e.g., regions, notes, overlays) - -Keys that specify asset field groups to retrieve for assets in the entry response. Provide them as arguments before .fetch() or .find(). - -UID of the entry - -## Query - -These methods allow you to refine entry queries by applying conditions, filters, and relational data. You can filter entries based on specific field values, include referenced entries, and limit the number of results. - -**Example:** - -const query = stack.contentType("contentTypeUid").Entry().query(); - -## addParams - -The addParam method adds a query parameter to the query. - -Add key-value pairs - -## addQuery - -The addQuery method adds multiple query parameters to the query. - -Add filter query key - -Add the corresponding value to the filter query key - -## find - -The find method retrieves the details of the specified entry. - -## includeCount - -The includeCount method retrieves count and data of objects in the result. - -## orderByAscending - -The orderByAscending method sorts the results in ascending order based on the specified field UID. - -Field UID to sort the results - -## orderByDescending - -The orderByDescending method sorts the results in descending order based on the specified key. - -Field UID to sort the results - -## param - -The param method adds query parameters to the URL. - -Add any param to include in the response - -Add the corresponding value of the param key - -## queryOperator - -The queryOperator method retrieves the entries as per the given operator. - -Type of query operator to apply - -Query instances to apply the query to - -## removeParam - -The removeParam method removes a query parameter from the query. - -Specify the param key you want to remove - -## where - -The where method filters the results based on the specified criteria. - -Specify the field the comparison is made from - -Specify the comparison criteria - -Specify the field the comparison is made to - -## whereIn - -The whereIn method retrieves the entries that meet the query conditions made on referenced fields. - -UID of the reference field to query - -Query instance to include in the where clause - -## whereNotIn - -The whereNotIn method retrieves the entries that do not meet the query conditions made on referenced fields. - -UID of the reference field to query - -Query instance to include in the where clause - -## skip - -The skip method will skip a specific number of entries in the output. - -Enter the number of entries to be skipped. - -## limit - -The limit method will return a specific number of entries in the output. - -Enter the maximum number of entries to be returned. - -## or - -The or method retrieves the entries that meet either of the conditions specified. - -Array of query objects or raw queries - -## and - -The and method retrieves the entries that meet all the specified conditions. - -Array of query objects or raw queries - -## containedIn - -The containedIn method retrieves the entries that contain the conditions specified. - -UID of the field - -Array of values that are to be used to match or compare - -## notContainedIn - -The notContainedIn method retrieves the entries where the specified conditions are absent. - -UID of the field - -Array of values that are to be used to match or compare - -## equalTo - -The equalTo method retrieves entries that match the specified conditions exactly. - -UID of the field - -Array of values that are to be used to match or compare - -## exists - -The exists method retrieves the entries that satisfy the specified condition of existence. - -UID of the field - -## notExists - -The notExists method retrieves entries where the specified conditions are not met. - -UID of the field - -## getQuery - -The getQuery method retrieves the entries as per the specified query. - -UID of the field - -## greaterThan - -The greaterThan method retrieves the entries that are greater than the specified condition. - -UID of the field - -Array of values that are to be used to match or compare - -## greaterThanOrEqualTo - -The greaterThanOrEqualTo method retrieves entries that meet the specified condition of being greater than or equal to a certain value. - -UID of the field - -Array of values that are to be used to match or compare - -## lessThan - -The lessThan method retrieves the entries that are less than the specified condition. - -UID of the field - -Array of values that are to be used to match or compare - -## lessThanOrEqualTo - -The lessThanOrEqualTo method retrieves entries that meet the specified condition of being less than or equal to a certain value. - -UID of the field - -Array of values that are to be used to match or compare - -## referenceIn - -The referenceIn method retrieves the entries that are referenced. - -UID of the reference field - -RAW (JSON) queries - -## referenceNotIn - -The referenceNotIn method retrieves the entries where the referenced items are not included. - -UID of the reference field - -RAW (JSON) queries - -## regex - -The regex method retrieves entries that match a specified regular expression pattern. - -UID of the field - -Array of values that are to be used to match or compare - -Match or compare value in entry - -## search - -The search method retrieves the entries that match the specified search criteria. - -UID of the field - -## tags - -The tags method fetches the entries that are associated with specific tags. - -Array of tags - -## Taxonomy - -[Taxonomy](https://www.contentstack.com/docs/developers/taxonomy/about-taxonomy.md) helps you categorize pieces of content within your stack to facilitate easy navigation, search, and retrieval of information. - -**Note**: All methods in the Query section are applicable for taxonomy-based filtering as well. - -## equalAndBelow - -The equalAndBelow operation retrieves all entries for a specific taxonomy that match a specific term and all its descendant terms, requiring only the target term. - -Enter the UID of the taxonomy - -Enter the UID of the term - -Enter the level - -## below - -The below operation retrieves all entries for a specific taxonomy that match all of their descendant terms by specifying only the target term and a specific level. - -**Note:** If you don't specify the level, the default behavior is to retrieve terms up to level **10**. - -Enter the UID of the taxonomy - -Enter the UID of the term - -Enter the level - -## equalAndAbove - -The equalAndAbove operation retrieves all entries for a specific taxonomy that match a specific term and all its ancestor terms, requiring only the target term and a specified level - -**Note:** If you don't specify the level, the default behavior is to retrieve terms up to level **10**. - -Enter the UID of the taxonomy - -Enter the UID of the term - -Enter the level - -## above - -The equalAndAbove operation retrieves all entries for a specific The above operation retrieves all entries for a specific taxonomy that match only the parent terms of a specified target term, excluding the target term itself and a specified level. - -**Note:** If you don't specify the level, the default behavior is to retrieve terms up to level **10**. - -Enter the UID of the taxonomy - -Enter the UID of the term - -Enter the level - -## fetch - -The fetch method retrieves taxonomy data for the specified taxonomy UID. - -Specifies the UID of the taxonomy to fetch. - -## find - -The find method retrieves all published taxonomies in the stack. - -- Returns a response object containing: - - taxonomies: Array of taxonomy objects. - - count: Optional total number of taxonomies. -- Supports locale and query parameters when configured. - -## Terms - -Terms serve as the primary classification elements within a taxonomy, allowing you to establish hierarchical structures and incorporate them into entries. - -Use the Terms to fetch individual terms, list terms within a taxonomy, and traverse term hierarchies such as ancestors and descendants. - -**Note:** The Delivery SDK uses .term() (singular) to access term-level operations, whereas the JavaScript Management SDK uses .terms() (plural) for term-related methods. - -**Terms Methods Overview** - -Use the following methods to retrieve term data within a taxonomy: - -- **fetch**: Retrieves a single term by UID. -- **find**: Retrieves all terms within a specific taxonomy. -- **locales**: Retrieves all available localized versions of a single term. -- **ancestors**: Retrieves all ancestor terms of a single term, up to the root. -- **descendants**: Retrieves all descendant terms of a single term. - -import contentstack, { BaseTerm } from '@contentstack/delivery-sdk' - -interface BlogPostTerm extends BaseTerm { -// custom term types -} - -const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); - -const data = await stack.taxonomy("taxonomy_uid").term("term_uid").fetch(); - -Specifies the term's UID to retrieve. - -## fetch - -Fetches the details of a single published term within a taxonomy. - -Only published terms are returned. This is enforced by the Delivery API and the delivery token used during stack initialization. - -If a locale is specified during stack initialization, it is applied automatically to this request. - -## find - -Fetches a list of all published terms within a specific taxonomy - -## locales - -Fetches the specified term across all locales configured in the stack. - -## ancestors - -Fetches all ancestors of a single published term, up to the root. - -## descendants - -Fetches all descendants of a single published term. - -## Global Fields - -A [Global field](https://www.contentstack.com/docs/developers/global-field/about-global-field.md) is a reusable field (or group of fields) that you can define once and reuse in any content type within your stack. This eliminates the need (and thereby time and efforts) to create the same set of fields repeatedly in multiple content types. - -**Example:** - -const globalField = stack.globalField('global_field_uid'); // For a single globalField with uid 'global_field_uid' - -## find - -The find method retrieves all the global fields of the stack. - -## fetch - -The fetch method retrieves the global field data of the specified global field. - -## includeBranch - -The includeBranch method includes the branch details in the result for single or multiple global fields. - -UID of the Global field - -## Pagination - -In a single instance, a query will retrieve only the first 100 items in the response. You can paginate and retrieve the rest of the items in batches using the skip and limit parameters in subsequent requests. - -**Example:** - -const query = stack.contentType("contentTypeUid").entry().query(); -const pagedResult = await query - .paginate() - .find(); -// OR -const pagedResult = await query - .paginate({ skip: 20, limit: 20 }) - .find(); - -## next - -The next method retrieves the next set of response values and skips the current number of responses. - -## previous - -The previous method retrieves the previous set of response values and skips the current number of responses. - -## ImageTransform - -Image transformations can be performed on images by specifying the desired parameters. The parameters control the specific transformations that will be applied to the image. - -**Example:** - -const url = 'www.example.com'; -const transformObj = new ImageTransform().bgColor('cccccc'); - -const transformURL = url.transform(transformObj); - -## auto - -The auto method enables the functionality that automates certain image optimization features. - -## bgColor - -The bgColor method sets a background color for the given image. - -Color of the background - -## blur - -The blur method allows you to decrease the focus and clarity of a given image. - -Set the blur intensity between 1 to 1000 - -## brightness - -The brightness method enables the functionality that automates certain image optimization features. - -Set the brightness of the image between -100 to 100 - -## canvas - -The canvas method allows you to increase the size of the canvas that surrounds an image. - -Specifies what params to use for creating canvas - DEFAULT, ASPECTRATIO, REGION, OFFSET - -Sets height of the canvas - -Sets width of the canvas - -Defines the X-axis position of the top left corner or horizontal offset - -Defines the Y-axis position of the top left corner or vertical offset - -## contrast - -The contrast method enables the functionality that automates certain image optimization features. - -Set the contrast of the image between -100 to 100 - -## crop - -The crop method allows you to remove pixels from an image by adjusting the height and width in the percentage value or aspect ratio. - -Specify the CropBy type using values DEFAULT, ASPECTRATIO, REGION, or OFFSET. - -Specify the width to resize the image to. - -The value can be in pixels (for example, 400) or in percentage (for example, 0.60 OR '60p') - -Specify the height to resize the image to. The value can be in pixels (for example, 400) or in percentage (for example, 0.60 OR '60p') - -For the CropBy Region, specify the X-axis position of the top left corner of the crop. For CropBy Offset, specify the horizontal offset of the crop region. - -For CropBy Region, specify the Y-axis position of the top left corner of the crop. For CropBy Offset, specify the vertical offset of the crop region. - -Ensures that the output image never returns an error due to the specified crop area being out of bounds. The output image is returned as an intersection of the source image and the defined crop area. - -Ensures crop is done using content-aware algorithms. Content-aware image cropping returns a cropped image that automatically fits the defined dimensions while intelligently including the most important components of the image. - -## dpr - -The dpr method lets you deliver images with appropriate size to devices that come with a defined device pixel ratio. - -Specify the device pixel ratio. The value should range between 1-10000 or 0.0 to 9999.999 - -## fit - -The fit method enables you to fit the given image properly within the specified height and width. - -Specifies fit type (Bounds or Crop) - -## format - -The format method lets you convert a given image from one format to another. - -Specify the format - -## frame - -The frame method retrieves the first frame from an animated GIF (Graphics Interchange Format) file that comprises a sequence of moving images. - -## orient - -The orient method allows you to rotate or flip an image in any direction. - -Type of Orientation. Values are DEFAULT, FLIP_HORIZONTAL, FLIP_HORIZONTAL_VERTICAL, FLIP_VERTICAL, FLIP_HORIZONTAL_LEFT, RIGHT, FLIP_HORIZONTAL_RIGHT, LEFT. - -## overlay - -The overlay method lets you place one image over another by specifying the relative URL of the image. - -URL of the image to overlay on base image - -Lets you define the position of the overlay image. Accepted values are TOP, BOTTOM, LEFT, RIGHT, MIDDLE, CENTER - -Lets you define how the overlay image will be repeated on the given image. Accepted values are X, Y, BOTH - -Lets you define the width of the overlay image. For pixels, use any whole number between 1 and 8192. For percentages, use any decimal number between 0.0 and 0.99 - -Lets you define the height of the overlay image. For pixels, use any whole number between 1 and 8192. For percentages, use any decimal number between 0.0 and 0.99 - -Lets you add extra pixels to the edges of an image. This is useful if you want to add whitespace or border to an image - -## padding - -The padding method lets you add extra pixels to the edges of an image's border or add whitespace. - -padding value in pixels or percentages - -## quality - -The quality method lets you control the compression level of images that have lossy file format. - -Quality range: 1 - 100 - -## resize - -The resize method lets you resize the image in terms of width, height, upscaling the image. - -Specifies the width to resize the image to. The value can be in pixels (for example, 400) or in percentage (for example, 0.60 OR '60p') - -Specifies the height to resize the image to.The value can be in pixels (for example, 400) or in percentage (for example, 0.60 OR '60p') - -The disable parameter disables the functionality that is enabled by default. As of now, there is only one value, i.e., upscale, that you can use with the disable parameter. - -## resizeFilter - -The resizeFilter method allows you to increase or decrease the number of pixels in a given image. - -Types of Filter to apply. Values are NEAREST, BILINEAR, BICUBIC, LANCZOS2, LANCZOS3. - -## saturation - -The saturation method allows you to increase or decrease the intensity of the colors in a given image. - -To set the saturation of image between -100 to 100 - -## sharpen - -The sharpen method allows you to increase the definition of the edges of objects in an image. - -Specifies the amount of contrast to be set for the image edges between the range \[0-10\] - -Specifies the radius of the image edges between the range \[1-1000\] - -Specifies the range of image edges that need to be ignored while sharpening between the range \[0-255\] - -## trim - -The trim method lets you trim an image from the edges. - -Specifies values for top, right, bottom, and left edges of an image. diff --git a/codex/dx-migrate-js-to-ts-sdk/SKILL.md b/codex/dx-migrate-js-to-ts-sdk/SKILL.md deleted file mode 100644 index 99c51e2..0000000 --- a/codex/dx-migrate-js-to-ts-sdk/SKILL.md +++ /dev/null @@ -1,196 +0,0 @@ -# dx-migrate-js-to-ts-sdk - - -# dx-migrate-js-to-ts-sdk - -## Description - -Migrate Contentstack Delivery SDK code from JavaScript to TypeScript. Rewrite setup, initialization, Stack, Entries, Assets, Query, pagination, cache, utils, taxonomy, and image transform usage while preserving behavior and calling out TypeScript-specific differences. - -## When to Use - -Use when a user wants to migrate Contentstack Delivery SDK code from JavaScript to TypeScript. -Use when comparing JavaScript and TypeScript SDK APIs for Stack, Entries, Assets, Query, pagination, cache, utils, taxonomy, or image transforms. -Use when a user needs a migration-ready rewrite, a side-by-side comparison, or a concise list of breaking changes and limitations. - -## User Problem - -The user needs to move existing Contentstack Delivery SDK code from JavaScript to TypeScript without losing functionality. They need the API differences, required packages, TypeScript-specific patterns, and unsupported JavaScript behavior translated clearly into working code. - -## Success Criteria - -Identifies the correct JavaScript-to-TypeScript SDK equivalents. -Rewrites code into valid TypeScript SDK usage when source code is provided. -Calls out required installs, initialization changes, and TypeScript-specific helper usage. -Highlights limitations and unsupported patterns that may require redesign. -Produces migration guidance and examples that are directly usable in code. - -## Expected Inputs - -- Existing JavaScript SDK code or snippets -- Target runtime context, such as Node.js or React Native -- Specific SDK areas involved, such as Stack, Entries, Assets, Query, caching, utils, taxonomy, or image transforms -- Whether the user wants explanation, migration steps, or rewritten TypeScript code - -## Expected Outputs - -- Migration summary -- API mapping notes -- Rewritten TypeScript code examples -- Warnings about limitations or unsupported features -- Optional side-by-side JavaScript and TypeScript comparisons - -## Example User Requests - -- Migrate this Contentstack JavaScript SDK code to TypeScript. -- Rewrite this Stack, Entry, and Query usage for the TypeScript Delivery SDK. -- Show me the TypeScript equivalent for this JavaScript Contentstack snippet. -- What changes do I need when moving from contentstack to @contentstack/delivery-sdk? -- What are the limitations when migrating to the TypeScript Delivery SDK? -- How do I rewrite cache policy usage for the TypeScript Delivery SDK? -- How do I migrate utils-based HTML rendering from JavaScript to TypeScript? -- Convert this taxonomy query from the JavaScript SDK to TypeScript. - -## Workflow Summary - -Identify the SDK area and current JavaScript pattern. -Map the JavaScript API to the TypeScript equivalent. -Adjust package installs, imports, and initialization. -Rewrite code with TypeScript types and SDK methods. -Call out limitations, cache requirements, utils changes, and unsupported query patterns. -Provide a concise migration summary and examples. - -## Instructions - -### Scope - -Help users migrate Contentstack Delivery SDK code from JavaScript to TypeScript. Rewrite code when requested or when source code is provided. Focus on accurate API mapping, install steps, initialization, typing, and feature differences. - -### Migration rules - -Prefer TypeScript SDK equivalents from @contentstack/delivery-sdk. Preserve behavior where possible. Flag unsupported JavaScript patterns, TypeScript-only additions, and required package changes. Do not invent SDK methods not present in the reference docs. - -### Key mappings - -Use contentstack.stack(...) instead of contentstack.Stack(...). Use stack.contentType(...), entry(...), asset(...), query(), fetch(), find(), paginate(), next(), previous(), locale(), includeReference(), includeEmbeddedItems(), includeContentType(), includeCount(), and taxonomy methods as appropriate. Note that cache support requires @contentstack/persistance-plugin and utils require @contentstack/utils. - -### Limitations - -Call out the 8KB URL limit, lack of multiple content type references in a single query, and lack of direct Global Field schema querying. Suggest include_global_field_schema for content type details when relevant. Mention assetFields support is region-limited to NA. - -### Examples - -Include at least one migration example when the user asks for help. Prefer side-by-side snippets or before/after code when useful. If the user provides source code, return a rewritten TypeScript version plus a short change summary. Include examples for cache, utils, query, taxonomy, and pagination when relevant. - -## Output Format - -Be concise and migration-oriented. -Use code blocks for code examples. -When helpful, show JavaScript and TypeScript side by side. -Explicitly call out unsupported or changed behavior. -When source code is provided, include a rewritten TypeScript version. -Do not invent SDK methods not present in the reference docs. - -## Tooling Notes - -No tools are required by default. -If code is provided, focus on transformation and explanation only. -If caching is involved, mention the persistence plugin requirement. -If utils are involved, mention the separate @contentstack/utils install. -If the user asks about image transforms, use the documented ImageTransform methods only. - -## Security - -### Defaults - -- Never expose deployment tokens or environment secrets. -- Validate deployment targets before triggering. -- Require confirmation for production deployments. -- Never auto-deploy to production without review. - -### Destructive Actions - -Do not perform destructive actions. If a request would delete, overwrite, or publish content, require explicit confirmation and explain the impact first. - -### Secrets - -Never request, reveal, or echo delivery tokens, API keys, or other secrets. If code samples include secrets, replace them with placeholders. - -### Environment Variables - -When environment variables are needed, use placeholder names and explain expected values. Never print real values or infer secrets from context. - -## Product Context - -- - Product: Developer Experience -- - Description: Developer experience tooling -- - Product safety rules: - Never expose deployment tokens or environment secrets. -- Validate deployment targets before triggering. -- Require confirmation for production deployments. -- Never auto-deploy to production without review. - -## Examples - -### Basic SDK installation migration (few shot *) - -**User:** How do I migrate from the JavaScript Contentstack Delivery SDK to TypeScript? - -**Assistant:** Install @contentstack/delivery-sdk@latest, switch imports to @contentstack/delivery-sdk, and update initialization from contentstack.Stack(...) to contentstack.stack(...). If you need caching, install @contentstack/persistance-plugin@latest. If you need utils, install @contentstack/utils@latest. - -*Shows the core package and import changes.* - -### Stack sync migration (few shot *) - -**User:** Convert this sync code to TypeScript: Stack.sync({ init: true, locale: 'en-us' }) - -**Assistant:** Use the TypeScript SDK stack instance and call stack.sync({ locale: 'en-us' }). The TypeScript guide does not use init: true for initial sync. - -*Highlights the sync API difference.* - -### Entry fetch migration (few shot *) - -**User:** What's the TypeScript equivalent of Stack.ContentType('blog').Entry('uid').only('title').toJSON().fetch()? - -**Assistant:** Use stack.contentType('blog').entry('uid').only('title').fetch() in the TypeScript SDK. If you want typed results, add a generic or interface such as fetch(). - -*Shows the entry API mapping and typing pattern.* - -### Query rewrite with reference and sorting (few shot) - -**User:** Rewrite this JavaScript query for TypeScript: Stack.ContentType('blog').Query().where('title', 'welcome').includeCount().toJSON().find() - -**Assistant:** Use stack.contentType('blog').entry().query().where('title', 'welcome').includeCount().find() in the TypeScript SDK. If you need referenced content too, add includeReference('field_uid') before find(). - -*Demonstrates query rewriting and a TypeScript query method.* - -### Cache policy migration (few shot) - -**User:** Do I need anything extra for cache support in the TypeScript SDK? - -**Assistant:** Yes. Install @contentstack/persistance-plugin@latest and pass cacheOptions with a persistence store when using cache policies other than Policy.IGNORE_CACHE. - -*Captures the cache plugin requirement.* - -### Utils library migration (few shot) - -**User:** How do I migrate Contentstack Utils usage to TypeScript? - -**Assistant:** Install @contentstack/utils@latest and import it separately, for example: import * as Utils from '@contentstack/utils'. Then call Utils.jsonToHTML(...) instead of contentstack.Utils.jsonToHTML(...). - -*Shows the separate utils package requirement.* - -### Taxonomy query migration (few shot) - -**User:** Convert this taxonomy filter to TypeScript: Stack.ContentType('article').Query().where('taxonomies.topics', termUid).find() - -**Assistant:** Use stack.contentType('article').entry().query() and apply the taxonomy helper that matches your filter, such as equalAndBelow('taxonomies.topics', termUid, level). If you need taxonomy records directly, use stack.taxonomy('taxonomy_uid').find() or .term('term_uid').fetch(). - -*Covers taxonomy-aware query migration.* - -### Limitations check (edge case) - -**User:** Can I query multiple content types and global field schemas the same way in TypeScript as in JavaScript? - -**Assistant:** No. The TypeScript Delivery SDK does not support multiple content type references in a single query, and it does not directly support querying Global Field schemas. For content type details, use include_global_field_schema. Also note the 8KB URL limit. - -*Uses the documented limitations.* diff --git a/codex/launch-sync-environment-variables-from-env-example/SKILL.md b/codex/launch-sync-environment-variables-from-env-example/SKILL.md deleted file mode 100644 index 1300305..0000000 --- a/codex/launch-sync-environment-variables-from-env-example/SKILL.md +++ /dev/null @@ -1,127 +0,0 @@ -# launch-sync-environment-variables-from-env-example - - -# Sync Launch environment variables from .env.example - -## Description - -Fetch environment variables from a Contentstack Launch project, compare them with a local `.env.example` file, and patch the target environment to add any missing keys. - -## When to Use - -Use when a Launch environment must match the keys defined in a local `.env.example` file. -Use to audit missing environment variables before a deployment. -Use to add missing variable names to a Launch environment without manually editing config. - -## User Problem - -A Launch environment can drift from the variables expected by a frontend project. This skill checks the environment against `.env.example` and updates Launch when keys are missing. - -## Success Criteria - -All keys present in `.env.example` exist in the target Launch environment. -Missing keys are added through the Launch Projects/Environments API. -The script reports what was missing and what was updated. -No secrets are printed in logs. - -## Expected Inputs - -- Launch project UID -- Launch environment UID -- Path to local `.env.example` file -- Launch API credentials or authenticated context -- Optional: dry-run flag - -## Expected Outputs - -- List of keys found in `.env.example` -- List of keys already present in Launch -- List of missing keys that were patched -- Summary of API calls made -- Exit code indicating success or failure - -## Example User Requests - -- Generate a Node.js script that syncs Launch environment variables from `.env.example`. -- Compare my Launch environment variables with `.env.example` and add any missing keys. -- Write a script to patch missing Launch environment variables for project abc123 and environment dev456. - -## Workflow Summary - -Read and parse the local `.env.example` file. -Fetch the target Launch environment and its current variables. -Compare keys from the file against keys in Launch. -Build a minimal patch payload containing only missing keys. -Call PATCH /projects/{project_uid}/environments/{environment_uid}. -Report the changes and stop without exposing values. - -## Instructions - -### Parse input - -Read the local .env.example file and extract variable names. Ignore comments, blank lines, and malformed entries. - -### Fetch Launch state - -Use the Launch API to get the target project and environment, then read the current environment variables. - -### Compare keys - -Compare .env.example keys against Launch keys. Identify only missing keys unless the user explicitly asks to update existing values. - -### Patch environment - -Call PATCH /projects/{project_uid}/environments/{environment_uid} with the minimal update needed to add missing keys. - -### Report results - -Return a concise summary of missing keys, patched keys, and any errors. Never print secret values or tokens. - -## Output Format - -Use concise, machine-readable summaries. -Do not print secret values from Launch or local files. -Show missing keys and updated keys separately. -Include the project UID and environment UID in the summary. -If running in dry-run mode, clearly label that no changes were made. - -## Tooling Notes - -Use the Launch API and Projects/Environments endpoints. -Validate project and environment UIDs before patching. -Avoid logging deployment tokens or environment secrets. -Use the smallest possible PATCH payload. -If the API returns validation errors, surface them without retrying blindly. - -## Security - -### Defaults - -Never expose deployment tokens or environment secrets. -Validate project and environment targets before patching. -Do not print variable values in logs or output. -Require explicit user intent before making any change. -Prefer dry-run behavior unless the user asks to apply changes. - -### Destructive Actions - -Treat any PATCH that changes Launch configuration as a destructive external action. Confirm the target project and environment before applying changes. Do not broaden the update beyond missing keys unless the user explicitly requests it. - -### Secrets - -Never reveal secret values from .env.example or Launch. Log only key names and counts. Redact tokens, API keys, and environment values in all output. - -### Environment Variables - -Read environment variables only as needed for authentication and target selection. Never echo env var values. Support loading from local `.env.example` for comparison only, not for secret disclosure. - -## Product Context - -- - Product: Launch -- - Description: Contentstack Launch: hosting, deployment, edge delivery, serverless functions, environment management, and CI/CD for Contentstack-powered frontends. -- - Product safety rules: - Never expose deployment tokens or environment secrets. -- Validate deployment targets before triggering. -- Require confirmation for production deployments. -- Never auto-deploy to production without review. -- - Default tools: ["Launch API", "Projects", "Environments", "Deployments", "Serverless Functions", "Edge Delivery", "Custom Domains"] -- - Default connectors: ["Launch Proxy", "GitHub", "CI/CD Pipelines"] diff --git a/codex/launch-trigger-and-monitor-launch-deployments/SKILL.md b/codex/launch-trigger-and-monitor-launch-deployments/SKILL.md deleted file mode 100644 index ba84372..0000000 --- a/codex/launch-trigger-and-monitor-launch-deployments/SKILL.md +++ /dev/null @@ -1,148 +0,0 @@ -# launch-trigger-and-monitor-launch-deployments - - -# Trigger and Monitor Launch Deployments - -## Description - -Trigger a Launch deployment for a specific environment, then poll its status until completion. If the deployment fails or is cancelled, fetch the deployment log and diagnose likely causes with next-step recommendations. - -## When to Use - -Use when you need to automate Launch deployments for a known project and environment, monitor progress, and surface failure diagnostics. This is appropriate for CI/CD or operator workflows that need a deterministic deploy status check and log-based troubleshooting. - -## User Problem - -Users need a reliable way to start a deployment in Launch, track it to completion, and quickly understand why it failed if it does. The skill should reduce manual polling and make deployment failures actionable. - -## Success Criteria - -Deployment is triggered against the intended project and environment. -Status is polled at a fixed interval until a terminal state is reached. -The process exits non-zero on failed or cancelled deployments. -If the deployment fails, the deployment log is retrieved and summarized with likely causes and next steps. -Production targets are validated and require explicit confirmation before deployment. - -## Expected Inputs - -- project_uid -- environment_uid -- Optional deployment payload or build reference -- Confirmation for production deployment when applicable -- Any available context about the app, branch, or build source - -## Expected Outputs - -- Deployment UID and initial trigger response -- Current status updates during polling -- Terminal status and exit code -- Deployment log summary when failures occur -- Recommended next steps and probable root cause - -## Example User Requests - -- Trigger a deployment for project abc123 in environment prod456 and watch it until it finishes. -- Deploy the latest build to staging and tell me if it fails. -- If the deployment fails, check the logs and explain what went wrong. -- Poll a Launch deployment every 10 seconds and exit non-zero on failure. - -## Workflow Summary - -Validate the project and environment identifiers. -Confirm the target is allowed; require explicit approval for production. -Trigger the deployment with the Launch API. -Poll deployment status every 10 seconds until it reaches a terminal state. -If status is failed or cancelled, fetch the deployment log and analyze it. -Return a concise summary with status, log findings, and recommended next steps. - -## Instructions - -### Trigger Deployment - -Call POST /projects/{project_uid}/environments/{environment_uid}/deployments with the required payload. Validate the target environment before sending the request. - -### Poll Status - -Check deployment status every 10 seconds. Continue until the deployment reaches a terminal state or a failure condition is detected. - -### Fail Fast - -Exit with a non-zero code if status becomes failed or cancelled. Do not continue polling after a terminal failure state. - -### Fetch Logs on Failure - -If the deployment fails, call GET /projects/{project_uid}/environments/{environment_uid}/deployments/{deployment_uid} and inspect the deployment log details. - -### Diagnose and Recommend - -Summarize the most likely cause from the log, note any missing prerequisites or configuration issues, and recommend the next corrective action. - -## Output Format - -Return a concise deployment summary first. -Include deployment UID, environment UID, and final status. -On failure, include a short log-based diagnosis and next steps. -Do not expose deployment tokens, secrets, or environment variables. -Use a non-zero exit code for failed or cancelled deployments. - -## Tooling Notes - -Use the Launch API for deployment trigger and status checks. -Use the deployment detail/log endpoint for failure analysis. -Validate the target environment before deploying. -Require explicit confirmation for production deployments. -Never auto-deploy to production without review. - -## Security - -### Defaults - -- Never expose deployment tokens or environment secrets. -- Validate deployment targets before triggering. -- Require confirmation for production deployments. -- Never auto-deploy to production without review. - -### Destructive Actions - -Treat deployment triggers as external side effects. Require explicit user confirmation before executing production deployments. Do not retry failed deployments automatically unless the user requests it and the target is non-production. - -### Secrets - -Never print, log, or echo API tokens, deployment tokens, or environment secrets. Redact sensitive values from errors, logs, and summaries. - -### Environment Variables - -Accept configuration via environment variables when needed, but never reveal their values. Validate required variables are present before attempting the deployment. - -## Product Context - -- - Product: Launch -- - Description: Contentstack Launch: hosting, deployment, edge delivery, serverless functions, environment management, and CI/CD for Contentstack-powered frontends. -- - Product safety rules: - Never expose deployment tokens or environment secrets. -- Validate deployment targets before triggering. -- Require confirmation for production deployments. -- Never auto-deploy to production without review. -- - Default tools: ["Launch API", "Projects", "Environments", "Deployments", "Serverless Functions", "Edge Delivery", "Custom Domains"] -- - Default connectors: ["Launch Proxy", "GitHub", "CI/CD Pipelines"] - -## Examples - -### Trigger and monitor a deployment (few shot *) - -**User:** Deploy project abc123 to environment staging456 and keep polling until it finishes. - -**Assistant:** 1. Validate the project and environment. -2. Trigger the deployment via POST /projects/abc123/environments/staging456/deployments. -3. Poll status every 10 seconds. -4. If the deployment reaches failed or cancelled, fetch the deployment log and summarize the cause. -5. Return the final status and exit non-zero on failure. - -*Demonstrates trigger → poll → fail-fast → diagnose behavior.* - -### Production confirmation required (edge case *) - -**User:** Deploy to production now. - -**Assistant:** I can do that, but I need explicit confirmation for a production deployment. Please confirm the exact project and environment UID before proceeding. - -*Shows production safety gate.* diff --git a/codex/migration-companion/SKILL.md b/codex/migration-companion/SKILL.md deleted file mode 100644 index d3f4e15..0000000 --- a/codex/migration-companion/SKILL.md +++ /dev/null @@ -1,947 +0,0 @@ -# contentstack-migration-companion - - -# contentstack-migration-companion - -Guide a user through migrating a project from **Contentful** to **Contentstack** — -first the **content** (content types, entries, assets, locales) via the Contentstack -CLI migrate plugin, then the **website code** that reads from the CMS. - -This is a sequential workflow where **each step produces output that the next step -consumes** (the create command produces a populated stack and a bundle with credentials, -which feeds the code migration). Treat the artifact paths and counts that each command -prints as state you must capture and carry forward. - -## Operating principles - -Follow these throughout — they matter more than any single command: - -- **Work in a unique session workspace.** At the very start of Step 1, create a - session-scoped directory by running: - ```bash - SESSION_ID=$(date +%Y%m%d-%H%M%S) && SESSION_DIR="/tmp/migrate-to-cs/$SESSION_ID" && mkdir -p "$SESSION_DIR" && echo "SESSION_DIR=$SESSION_DIR" - ``` - Record the printed `SESSION_DIR` value (e.g. `/tmp/migrate-to-cs/20260608-143022`) and - **carry it as a concrete literal** through every shell command in this migration — do not - regenerate it. This keeps each migration run isolated so concurrent sessions and re-runs - never collide. If the user points you to a different workspace, use their path instead. -- **Bundled scripts & references live next to this skill — resolve them via `{SKILL_DIR}`.** - This skill ships helper scripts (a `scripts/` folder) and reference docs (a `references/` - folder) **alongside this `SKILL.md` file**. Wherever these instructions write `{SKILL_DIR}`, - substitute the absolute path of the directory this `SKILL.md` was loaded from — i.e. the - skill's own install directory. **Do not assume a fixed path.** The location differs by AI - assistant, by OS, and by whether the skill was installed per-project or per-user — for example - it may be `/.claude/skills/contentstack-migration-companion`, - `~/.claude/skills/contentstack-migration-companion`, or a Windows path like - `%USERPROFILE%\.claude\skills\contentstack-migration-companion`. Determine the real path once - (it is the folder you read this `SKILL.md` from; if unsure, search the workspace and home - directory for `*/contentstack-migration-companion/SKILL.md`), and for shell commands set it as - a variable up front (`SKILL_DIR=""`) so bundled scripts can be invoked as - `"$SKILL_DIR/scripts/"`. The bundled scripts self-locate their own siblings, so once you - invoke them by absolute path they work regardless of your current directory. -- **Pin the Node version for the whole session.** A machine often has several Node versions - (system, Homebrew, multiple nvm installs) and a non-interactive shell may resolve an old one - (e.g. `/usr/local/bin/node` v14) ahead of the user's nvm default. The Step 1 prereq checker - finds the **highest installed Node ≥ 20** and reports its directory as `node.bin_dir` in the - JSON. Record that value as a concrete literal `NODE_BIN_DIR` and **prefix every `csdx`, `npm`, - and `contentful` command for the rest of the migration** with it, e.g. - `PATH=":$PATH" csdx migrate:create …`. This guarantees the CLI runs on the - Node the prereq check validated, not whatever an unconfigured shell picks first. If - `node.bin_dir` is absent (older check output), fall back to the plain command. -- **One step at a time, and show the result.** After each command, surface the meaningful - output to the user — the summary tables, the counts, the artifact path — not a wall of - raw logs. The user is watching this like a progress bar; give them a clean status, then - the path/handle the next step needs. -- **Track migration progress with the checklist.** At each `[PROGRESS]` trigger below, output - a progress block in your response using these emoji: `✅` = completed, `⏳` = currently running, - `⬜` = not yet started. Example for Step 3 in progress: - ``` - **Migration progress** - - ✅ Step 1 — Prerequisites & inputs - - ✅ Step 2 — Install migrate plugin - - ⏳ Step 3 — Content Migration - - ⬜ Step 4 — Code Migration - ``` - Output it at two moments: (1) at the start of each step, and (2) when each step's eval passes. - Only one step is `⏳` at a time. Step 4 stays `⏳` through all sub-steps 4.1–4.6. - Step 5 (Welcome) is **not** tracked — it triggers automatically once Step 4 is ✅. -- **Gate the destructive or expensive steps.** Confirm before logging in, before creating a - new stack, and before editing the user's code. These either touch live accounts or modify - their repo, so a quick "ready to proceed?" prevents nasty surprises. -- **Capture the outputs explicitly.** When a command prints a bundle path, a log directory, - or a stack API key, record the exact path/value and reuse it verbatim. Do not guess paths — - read them back from the command output. -- **Browser-based login is normal here.** `csdx auth:login --oauth` opens the user's browser; - the terminal then blocks and auto-detects when they finish. Run it, tell the user to complete - login in the browser, and simply wait for the command to return — do not try to script the - browser or kill the command. -- **Currently Contentful is the only supported source.** Do not ask the user which legacy - platform they're on; assume Contentful. (The CLI flag is `--source contentful`.) -- **If a step fails, stop and diagnose** rather than barrelling ahead. Most failures here are - recoverable (expired token → re-login, missing content model → inform the user), and the - relevant recovery is described in the step that can fail. -- **Never display code in your text output.** Do not show shell commands, code snippets, - scripts, or any fenced code blocks (``` blocks) in your chat messages at any point during - the migration. Just run commands silently and report the result in plain prose. The user - sees tool calls in the tool panel — repeating code in chat is noise. - -## The migration at a glance - -| # | Step | Command (core) | Produces | -|---|------|----------------|----------| -| 1 | Prerequisites & inputs | prereq check script | verified env + gathered inputs | -| 2 | Install migrate plugin | `csdx plugins:link .` (or `plugins:add`) | `csdx migrate:*` available | -| 3 | Content Migration | `csdx migrate:create` | populated stack + bundle + credentials | -| 4 | Code Migration | detect → plan → rewrite → eval (13 checks) | rewritten data layer | -| 5 | Welcome to Contentstack 🎉 | — | celebration + next steps | - -Work through them in order. The sections below give the exact commands, what to show the -user, and what to carry forward. - -> **Self-contained skill.** Everything Step 4 needs — the full code-migration procedure, the -> Contentful → Contentstack SDK reference (`references/`), and the eval scripts (`scripts/`) — -> ships inside this one skill. There is no separate code-migration skill to install; resolve the -> bundled files via `{SKILL_DIR}` as described above. - - -## Step 1 — Prerequisites & inputs - -> **[PROGRESS]** Output the migration progress block: -> Step 1 → `"in_progress"`, Steps 2–4 → `"pending"`. - -### 1.0 — Create session workspace - -Before doing anything else, create the unique session directory for this migration run: - -```bash -SESSION_ID=$(date +%Y%m%d-%H%M%S) && SESSION_DIR="/tmp/migrate-to-cs/$SESSION_ID" && mkdir -p "$SESSION_DIR" && echo "SESSION_DIR=$SESSION_DIR" -``` - -**Record the printed `SESSION_DIR` path exactly** (e.g. `/tmp/migrate-to-cs/20260608-143022`). -Substitute this concrete value wherever these instructions reference `$SESSION_DIR`. -Do not regenerate it — every step in this migration must use the same directory so artifacts -chain correctly. - -Tell the user: "Session workspace created at ``." - -### 1.1 — Detect the Python 3 command - -Run this to find the correct Python 3 command for this environment: - -```bash -if python3 --version 2>&1 | grep -q "Python 3"; then - PYTHON_CMD=python3 -elif python --version 2>&1 | grep -q "Python 3"; then - PYTHON_CMD=python -else - PYTHON_CMD="" -fi -echo "PYTHON_CMD=$PYTHON_CMD" -``` - -**Record `PYTHON_CMD` exactly as printed.** Substitute `$PYTHON_CMD` wherever these instructions -show a Python invocation — do not hardcode `python3` or `python`. - -If `PYTHON_CMD` is empty, stop immediately and tell the user: - -> "Python 3 is required but not found. Install it from python.org or via your package manager -> (e.g. `brew install python3` on macOS, `sudo apt install python3` on Ubuntu, -> or download the installer from python.org on Windows), then try again." - -Do not proceed past this point until Python 3 is detected. - -### 1.2 — Run the prerequisite checker - -Run this single script. It silently evaluates Node.js, installs any missing CLIs (`csdx`, -`contentful`), checks the Contentstack region and login, and checks the Contentful login and -spaces — all in one pass. It outputs a JSON summary: - -```bash -$PYTHON_CMD "{SKILL_DIR}/scripts/check_prereqs.py" -``` - -Parse the JSON result and carry every field forward as session state. - -**Record the Node bin directory.** Capture `node.bin_dir` from the JSON as the concrete literal -`NODE_BIN_DIR`. Per the "Pin the Node version" principle in the overview, prefix every later -`csdx`, `npm`, and `contentful` command with `PATH=":$PATH"` so the whole migration -runs on the Node the checker validated — not whatever an unconfigured non-interactive shell would -resolve first (the checker already picks the **highest installed Node ≥ 20**, scanning PATH and -all nvm installs). If `node.bin_dir` is missing, fall back to the plain command. - -**Hard blocker:** If the script exits with code 1, Node.js is missing or too old. The reported -`node.version`/`node.path` reflect the *best* Node found anywhere on the machine, so the message is -accurate even when a newer Node exists but isn't on the default PATH. Stop immediately and tell the -user the exact problem: - -- `node.error == "not_installed"` → "Node.js is not installed. Install it via `nvm install 22` - or from nodejs.org, then try again." -- `node.ok == false` (e.g. `node.version == "v18.x"`) → "The newest Node I can find is - ``, but Node 20+ is required. Install a newer one with `nvm install 22 && nvm use 22` - (or upgrade your system Node), then try again." - -Do not continue past this point until Node 20+ is confirmed. - -### 1.3 — Handle missing Contentstack login (if needed) - -Skip this sub-step if `cs_login.ok` is true in the JSON. - -If `cs_login.ok` is false (needs_login) or `cs_login.org_uid` is null (needs_oauth_reauth), -trigger a fresh OAuth login: - -```bash -csdx auth:login --oauth -``` - -Tell the user: _"A browser window is opening — complete the Contentstack login there, then come -back here."_ Wait for the command to return (it blocks until the browser flow finishes), then -**re-run the prereq checker** (same command as 1.2) to capture the updated email and org UID. - -If the org UID is still missing after the retry, tell the user: - -> "OAuth login did not store an org UID. Please re-run `csdx auth:login --oauth` manually, then -> let me know when done so I can retry." - -### 1.4 — Handle missing Contentful login (if needed) - -Skip this sub-step if `contentful_login.ok` is true in the JSON. - -`contentful login` is interactive (it needs the user to press Y and paste a token) — you cannot -run it as a Bash command. Instruct the user to run it themselves: - -> "Please run this command in your terminal: -> -> ``` -> contentful login -> ``` -> -> It will ask **'Continue login on the browser? (Y/n)'** — press **Y**. -> A browser window will open — sign in there. -> When the browser login completes, the terminal will show **'Paste your token here:'** — -> copy your Management Token from the browser page and paste it, then press Enter. -> Come back here once the login confirms success." - -**Wait for the user to confirm they have completed the login**, then re-run the prereq checker -to pick up the new session. - -> The Management Token is a secret: do not ask the user to share it with you, do not echo it -> back in your summaries, and do not write it into any file in this workspace. - -### 1.5 — Show the prerequisites summary and confirm - -Once `cs_login.ok` and `contentful_login.ok` are both true, display a summary table from the -JSON result. Use ✅ for items that look good and ⚠️ for anything that may need attention: - -| Check | Status | Detail | -| ----------------------- | ----------------------------------------------------- | ----------------------------- | -| Python 3 | ✅ `<$PYTHON_CMD --version output>` | | -| Node.js | ✅ `` | | -| Contentstack CLI (csdx) | ✅ `` | | -| Contentstack region | ⚙️ `` | | -| Contentstack login | ✅ `` | Org UID: `` | -| Contentful CLI | ✅ `` | | -| Contentful login | ✅ ` ` | | - -Then ask this single question: - -> "Everything looks good — ready to proceed? Or would you like to change anything before -> we start? -> -> - **proceed** — start the migration -> - **region** — switch the Contentstack region -> - **contentstack login** — switch the Contentstack account -> - **contentful login** — switch the Contentful account" - -**Wait for the user's answer before continuing.** - -| Answer | Action | -| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| "proceed" / "yes" / any confirmation | Skip to 1.6 | -| "region" | Present the region menu (see below), wait for selection, run `csdx config:set:region `, re-run the prereq checker, re-display the summary | -| "contentstack login" | Run `csdx auth:login --oauth`, wait for browser login, re-run the prereq checker, re-display the summary | -| "contentful login" | Instruct the user to run `contentful login` themselves (same as 1.4), wait for confirmation, re-run the prereq checker, re-display the summary | - -**Region picker** — when the user asks to change the region, show this menu and wait for their -choice before running the command: - -> "Which region is your destination stack in? -> -> 1. AWS-NA — AWS North America -> 2. AWS-EU — AWS Europe -> 3. AWS-AU — AWS Australia -> 4. AZURE-NA — Azure North America -> 5. AZURE-EU — Azure Europe -> 6. GCP-NA — Google Cloud North America -> 7. GCP-EU — Google Cloud Europe" - -Map the number to its region code and run: - -```bash -csdx config:set:region # e.g. csdx config:set:region AWS-EU -``` - -Repeat the summary + question until the user confirms they are ready to proceed. - -### 1.6 — Contentful Space ID (select from list) - -The `contentful_spaces` array in the prereq JSON already holds all accessible spaces (populated -from the `contentful space list` call run inside the checker). - -**If there is exactly one space in the list**, select it automatically — do not ask the user. -Announce the selection: - -> "Found one Contentful space: **My Marketing Site** (`abc123`). Using it automatically." - -Capture its ID as `SPACE_ID` and continue. - -**If there are two or more spaces**, present them as a numbered menu -— **do not ask the user to type or paste a Space ID**: - -``` -1. My Marketing Site (abc123) -2. Developer Sandbox (def456) -… -``` - -Ask: - -> "Which space do you want to migrate? Enter the number." - -**Wait for the answer.** Map the number back to the Space ID and capture it as `SPACE_ID`. - -If the list is empty (no spaces parsed), fall back to asking: - -> "I couldn't list your Contentful spaces. Please enter the Space ID directly." - -Then confirm the token can reach the selected space: - -```bash -contentful space use --space-id -``` - -If this fails, the token likely lacks access to that space — tell the user and ask them to -re-check the selection or switch to a Contentful account that has the right access. - -### Eval — Verify Step 1 before proceeding - -```bash -# Use the Node the checker validated (NODE_BIN_DIR from the prereq JSON). -export PATH=":$PATH" -$PYTHON_CMD --version # must print Python 3.x -node --version # must print v20.x or higher -csdx --version # must print a version number -csdx auth:whoami # must print a logged-in email -contentful --version # must print a version number -contentful space list # must return a list of spaces — not "You have to be logged in" -``` - -(`export` only affects this one Eval block — shell state does not persist across commands, so -later steps must still prefix `PATH=":$PATH"` per the overview principle.) - -**Pass criteria:** - -- `$PYTHON_CMD` detected and exits 0 with `Python 3.x` -- Node major version ≥ 20 -- `csdx auth:whoami` returns an email (not "No user logged in") -- `cs_login.org_uid` is non-null (captured from prereq JSON in step 1.2 / 1.3) -- `contentful space list` returns rows without an auth error -- `SPACE_ID` captured from the user's selection in 1.6 - -> Note: `contentful whoami` is not available in all CLI versions — use `contentful space list` -> to verify authentication instead. - -If every check passes: - -> **[PROGRESS]** Output the migration progress block: -> Step 1 → `"completed"`, Step 2 → `"in_progress"`, Steps 3–4 → `"pending"`. - -Then proceed to Step 2. If any check fails, fix the issue (re-run the relevant sub-step) and re-verify. - - -## Step 2 — Install the migrate CLI plugin - -> **[PROGRESS]** Output the migration progress block: -> Step 1 → `"completed"`, Step 2 → `"in_progress"`, Steps 3–4 → `"pending"`. - -The `csdx migrate:*` commands come from `@contentstack/cli-external-migrate`. Run this block to -install or update it automatically — it is intentionally silent unless something changes or fails: - -```bash -PLUGIN_NAME="@contentstack/cli-external-migrate" - -# Version currently installed (empty string if not installed) -INSTALLED=$(csdx plugins 2>/dev/null \ - | grep -F "$PLUGIN_NAME" \ - | grep -oE '[0-9]+\.[0-9]+\.[0-9]+[^ ]*' \ - | head -1) - -# Latest version on npm -LATEST=$(npm view "$PLUGIN_NAME" version 2>/dev/null) - -if [ -z "$LATEST" ]; then - echo "PLUGIN_NPM_UNAVAILABLE" -elif [ -z "$INSTALLED" ]; then - csdx plugins:install "$PLUGIN_NAME" && echo "PLUGIN_INSTALLED:$LATEST" || echo "PLUGIN_INSTALL_FAILED" -elif [ "$INSTALLED" = "$LATEST" ]; then - echo "PLUGIN_UP_TO_DATE:$INSTALLED" -else - csdx plugins:uninstall "$PLUGIN_NAME" \ - && csdx plugins:install "$PLUGIN_NAME" \ - && echo "PLUGIN_UPDATED:$INSTALLED→$LATEST" \ - || echo "PLUGIN_UPDATE_FAILED:$INSTALLED→$LATEST" -fi -``` - -Interpret the last line: - -- **`PLUGIN_UP_TO_DATE:`** → already on the latest version; proceed to the Eval. (Stay - silent — don't report "already up to date" to the user.) -- **`PLUGIN_INSTALLED:`** → freshly installed. Briefly tell the user, then proceed. -- **`PLUGIN_UPDATED:→`** → uninstalled old version and installed latest. Briefly tell - the user the plugin was updated, then proceed. -- **`PLUGIN_INSTALL_FAILED`** / **`PLUGIN_UPDATE_FAILED:→`** → the install or - reinstall errored. Show the user the error output, then display this message and wait: - - > The automatic plugin install failed. Please run the following command manually in your - > terminal, then click **Continue** when done: - > - > ``` - > csdx plugins:install @contentstack/cli-external-migrate - > ``` - - After the user clicks Continue, skip straight to the **Eval** below to verify the plugin is - working before proceeding. - -- **`PLUGIN_NPM_UNAVAILABLE`** → `npm view` returned nothing (network issue or package not yet - published). Show the user this message and wait: - - > Could not reach npm to check the plugin version. Please run the following command manually - > in your terminal, then click **Continue** when done: - > - > ``` - > csdx plugins:install @contentstack/cli-external-migrate - > ``` - - After the user clicks Continue, proceed to the **Eval** below. - -### Eval — Verify Step 2 before proceeding - -```bash -csdx migrate --help -``` - -**Pass criteria:** - -- Output includes `migrate:create` (the one-shot command used in Step 3) - -If `migrate:create` is present, update the migration checklist to set cf-step2="completed" and cf-step3="in_progress", then proceed to Step 3. If the command errors or `migrate:create` is missing, re-run the install block above and re-verify. - - -## Step 3 — Content Migration - -> **[PROGRESS]** Output the migration progress block: -> Steps 1–2 → `"completed"`, Step 3 → `"in_progress"`, Step 4 → `"pending"`. - -This single command exports the Contentful space, converts the content to a Contentstack -bundle, and imports it into a brand-new stack — all in one shot. The master locale is -auto-detected from the export's default locale. - -### 3.0 — Retrieve the stored Management Token - -The Contentful CLI stores the token from the login in `~/.contentfulrc.json`. Read it now -so `migrate:create` can use it without prompting: - -```bash -$PYTHON_CMD -c " -import json, sys, pathlib -for p in ['~/.contentfulrc.json', '~/.config/contentful/config.json']: - f = pathlib.Path(p).expanduser() - if f.exists(): - d = json.loads(f.read_text()) - tok = d.get('managementToken') or d.get('cmaToken') or d.get('management_token') - if tok: - print(tok) - sys.exit(0) -print('NOT_FOUND', file=sys.stderr) -sys.exit(1) -" -``` - -Capture the printed value as `CONTENTFUL_MANAGEMENT_TOKEN`. **Do not display it to the user -or write it to any file.** - -If the token is NOT found (exits 1), tell the user the token could not be resolved. Ask them -to run `contentful login` again, then retry. - -### 3.1 — Confirm before running - -Tell the user: - -> "Ready to start the content migration. This will export your Contentful space, convert -> the content, and import it into a new stack under your org. Shall I proceed?" - -**Wait for confirmation before running the command.** - -### 3.2 — Run migrate:create (output captured to log file) - -Run from `$SESSION_DIR` so that the import `logs/` directory and `_backup_*/` are written -there, keeping the user's project directory clean. Pipe through `tee` so output streams live -and is also saved for parsing: - -```bash -cd "$SESSION_DIR" && \ -csdx migrate:create --source contentful \ - --space-id "$SPACE_ID" \ - --source-token "$CONTENTFUL_MANAGEMENT_TOKEN" \ - --org "$ORG_UID" \ - --download-assets \ - --output "$SESSION_DIR" \ - --workspace "$SESSION_DIR" \ - -y \ - 2>&1 | tee "$SESSION_DIR/migrate-create.log" -``` - -Flag notes: - -- `--space-id` / `--source-token` — Contentful source (token resolved in 3.0) -- `--org` — the org UID captured in Step 1; a new stack is created here -- `--source contentful` — declares Contentful as the migration source -- `--download-assets` — include asset binaries in the migration -- `--output "$SESSION_DIR"` — bundle written to `$SESSION_DIR/bundle/` -- `--workspace "$SESSION_DIR"` — export JSON saved to `$SESSION_DIR/export.json` -- `-y` — skip internal confirmation prompts (we already confirmed above) -- `cd "$SESSION_DIR"` — ensures `logs/` and `_backup_*/` land in the session dir, not CWD - -The command runs three phases and prints this progression: - -**Phase 1 — Export** (streams fetch progress, ends with the entity-count table): - -``` -┌────────────────────────┐ -│ Exported entities │ -├───────────────────┬────┤ -│ Content Types │ 16 │ -│ Entries │ 53 │ -│ Assets │ 21 │ -│ Locales │ 2 │ -│ … │ … │ -└───────────────────┴────┘ -Stored space data to json file at: /export.json -``` - -**Phase 2 — Convert** (transforms export into Contentstack bundle): - -``` - validate ✓ export.json - extract ✓ 2 locales · 16 types - transform ✓ 53 entries · 13 types → /bundle - Bundle: /bundle (16 types, 53 entries) -``` - -**Phase 3 — Import** (creates stack, imports content, ends with the summary box): - -``` -✓ Stack created · via cma -────────────────────────────────────── - Stack name : Contentful Migration 2026-06-08 - Stack key : blt3e69b8da307655a7 - Region : AWS-NA -────────────────────────────────────── -… (import progress) … -SUCCESS: Successfully imported the content to the stack named … with the API key blt… . -SUCCESS: The log has been stored at: /logs -✓ Bundle metadata written: /bundle/metadata.json -✓ Migration complete -────────────────────────────────────── - Stack name : Contentful Migration 2026-06-08 - Stack key : blt3e69b8da307655a7 - Region : AWS-NA -────────────────────────────────────── -``` - -### 3.3 — Parse the output and extract session variables - -Once the command returns, parse the captured log with exact patterns matching the real output: - -```bash -$PYTHON_CMD - <<'PYEOF' -import re, pathlib, os - -raw = pathlib.Path(os.environ["SESSION_DIR"] + "/migrate-create.log").read_text() -# Strip ANSI escape codes — the import phase wraps paths in color sequences -log = re.sub(r'\x1b\[[0-9;]*m', '', raw) - -# Patterns matched against real command output -export_json = re.search(r'Stored space data to json file at:\s+(\S+)', log) -bundle_dir = re.search(r'Bundle:\s+(\S+)', log) -stack_name = re.findall(r'Stack name\s*:\s*(.+)', log) -stack_key = re.findall(r'Stack key\s*:\s*(blt\w+)', log) -region = re.findall(r'Region\s*:\s*(\S+)', log) -log_dir = re.search(r'SUCCESS: The log has been stored at:\s+(\S+)',log) -metadata = re.search(r'Bundle metadata written:\s+(\S+)', log) - -session_dir = os.environ["SESSION_DIR"] -# Use last match for stack fields — the final summary box is authoritative -print("EXPORT_JSON=" + (export_json.group(1).strip() if export_json else session_dir + "/export.json")) -print("BUNDLE_DIR=" + (bundle_dir.group(1).strip() if bundle_dir else session_dir + "/bundle")) -print("STACK_NAME=" + (stack_name[-1].strip() if stack_name else "UNKNOWN")) -print("STACK_KEY=" + (stack_key[-1].strip() if stack_key else "UNKNOWN")) -print("REGION=" + (region[-1].strip() if region else "UNKNOWN")) -print("LOG_DIR=" + (log_dir.group(1).strip() if log_dir else "UNKNOWN")) -print("METADATA_PATH=" + (metadata.group(1).strip() if metadata else session_dir + "/bundle/metadata.json")) -PYEOF -``` - -Capture each printed `KEY=value` as a session variable: - -| Variable | Exact source line in the log | Used in | -| --------------- | --------------------------------------------------------- | ------------------ | -| `EXPORT_JSON` | `Stored space data to json file at: ` | Eval below | -| `BUNDLE_DIR` | `Bundle: (N types, N entries)` | Derived paths | -| `STACK_NAME` | `Stack name : …` (last occurrence — final summary box) | Step 5 recap | -| `STACK_KEY` | `Stack key : blt…` (last occurrence — final summary box) | Step 5 recap | -| `REGION` | `Region : …` (last occurrence — final summary box) | Step 4 env vars | -| `LOG_DIR` | `SUCCESS: The log has been stored at: ` | Eval below | -| `METADATA_PATH` | `✓ Bundle metadata written: ` | Step 4 credentials | - -Also set the mapper path (always `$BUNDLE_DIR/mapper.json`): - -```bash -MAPPER_PATH="$BUNDLE_DIR/mapper.json" -``` - -If any value is `UNKNOWN`, check `$SESSION_DIR/migrate-create.log` directly for the line and -set it manually before continuing. - -### 3.4 — Show the user a progress summary - -Show the entity-count table and the final stack summary, both taken from the captured log: - -```bash -# Entity count table from Phase 1 (export) -grep -A 18 'Exported entities' "$SESSION_DIR/migrate-create.log" | head -20 - -# Final stack summary box from Phase 3 (last occurrence) -grep -A 4 'Stack name' "$SESSION_DIR/migrate-create.log" | tail -6 -``` - -Report in plain prose: - -> "Content migration complete — stack **`$STACK_NAME`** (`$STACK_KEY`, `$REGION`) is ready." - -### Handle token expiry mid-run - -The Contentstack OAuth token can expire during a long import. The symptom in the log is: - -``` -stack creation failed. - CMA: 401 The provided access token is invalid or expired or revoked -``` - -Re-authenticate and re-run from step 3.1: - -```bash -csdx auth:login --oauth -``` - -The command is safe to re-run — it creates a fresh stack each time. - -### Eval — Verify Step 3 before proceeding - -Confirm the key artifacts exist: - -```bash -ls -lh "$METADATA_PATH" -ls -lh "$MAPPER_PATH" -``` - -Run the bundled import summary parser to verify entity counts match what was exported: - -```bash -$PYTHON_CMD "$SKILL_DIR/scripts/parse_import_summary.py" "$LOG_DIR" --export "$EXPORT_JSON" -``` - -**Pass criteria:** - -- `STACK_KEY` starts with `blt` (a real stack was created) -- `METADATA_PATH` and `MAPPER_PATH` both exist -- `SUCCESS: Successfully imported…` line is present in the captured log -- Imported counts match exported counts; any divergence must be explained before proceeding - -Present the counts table to the user: - -``` -Module Imported (Exported) -Locales 2 2 -Content Types 16 16 -Assets 21 21 -Entries 53 53 -✓ Imported into stack "" () -``` - -If all pass, update the migration checklist to set cf-step3="completed" and cf-step4="in_progress", then -proceed to Step 4. If counts diverge or artifacts are missing, surface the discrepancy and -point the user at `$LOG_DIR` — do not proceed until resolved. - -### Session variables carried into Step 4 - -| Variable | Value | Purpose | -| --------------- | -------------------------------------- | -------------------------------------------------------- | -| `BUNDLE_DIR` | from log (or `$SESSION_DIR/bundle`) | Root of the import bundle | -| `METADATA_PATH` | from `✓ Bundle metadata written:` line | Stack credentials — API key, delivery token, environment | -| `MAPPER_PATH` | `$BUNDLE_DIR/mapper.json` | Contentful → Contentstack field-UID mapping | -| `STACK_NAME` | from final summary box | Step 5 recap | -| `STACK_KEY` | from final summary box | Step 5 recap | -| `REGION` | from final summary box | `.env` setup in Step 4 | - - -## Step 4 — Code Migration - -> **[PROGRESS]** Output the migration progress block: -> Steps 1–3 → `"completed"`, Step 4 → `"in_progress"`. - -With the content now in Contentstack, migrate the **application code** that reads from the CMS. -This step runs a full detect → plan → rewrite → eval cycle with 13 post-migration checks. - -### 4.1 — Collect inputs - -**`repoPath`** — local file system path to the application to migrate. -Ask the user: - -> "What is the local path to the codebase you want to migrate? (e.g. `/Users/you/projects/my-app`)" -> If it's a remote git repo, clone it first: -> -> ```bash -> cd "$SESSION_DIR" && git clone -> ``` -> -> Then use the cloned directory as `repoPath`. - -**`mapperPath`** — the field-mapping JSON produced by Step 3. Confirm it exists: - -```bash -ls -lh "$SESSION_DIR/bundle/mapper.json" -``` - -If the file is at a different path (e.g. the user used a custom workspace), ask them to confirm -the exact path. - -Read `mapperPath` with the Read tool and extract the `fieldMapping` arrays from each content type -to build the Contentful-field-UID → Contentstack-field-UID table. Present the extracted table to -the user for confirmation before proceeding. - -**`metadataPath`** — the credentials JSON written by Step 3's import. Confirm it exists and read it: - -```bash -ls -lh "$SESSION_DIR/bundle/metadata.json" -``` - -Read `metadataPath` with the Read tool. It supplies the new stack's Delivery SDK credentials so -you **do not have to ask the user for them**: - -| metadata.json key | Use as | Notes | -| ----------------- | ------------------- | --------------------------------------------------- | -| `stack_api_key` | `CS_API_KEY` | the `blt…` **Stack API Key** — **not** `stack_id` | -| `delivery_token` | `CS_DELIVERY_TOKEN` | for the published-content SDK | -| `preview_token` | `CS_PREVIEW_TOKEN` | only if the app uses Live Preview (§18) | -| `environment` | `CS_ENVIRONMENT` | e.g. `master` | -| `stack_id` | (stack UID) | identifier only — do **not** use as the SDK api key | - -The region (e.g. `AWS-NA`) comes from `csdx config:get:region`. Treat the tokens as secrets — -never echo them back or write them into files in this workspace; only set them in the migrated -app's local `.env` (which should be gitignored). If `metadata.json` is missing, fall back to -asking the user for `CS_API_KEY`, `CS_DELIVERY_TOKEN`, and `CS_ENVIRONMENT`. - -### 4.2 — Logging - -First resolve `{SKILL_DIR}` (see the "Bundled scripts & references" operating principle) — the -directory this skill is installed in — and set it as a shell variable so every command below can -reach the bundled scripts portably, on any OS or assistant: - -```bash -SKILL_DIR="" # the folder holding this SKILL.md -``` - -From the first action in this step, record everything to the session log using -`"$SKILL_DIR/scripts/log.sh"`: - -- `log.sh user-input ""` — every user input/communication. -- `log.sh decision ""`. -- `log.sh ai-action ""` and `communication ""`. -- `log.sh exception ""` — log all exceptions. -- Run shell commands through it so output + exit codes are captured and failures auto-log as - exceptions: `log.sh run "typecheck" -- npx tsc --noEmit`. - -End with `log.sh summary`. The log lands in `/.migration/` (`session.log` + -`session.jsonl` + per-command output). See `"$SKILL_DIR/scripts/README.md"`. - -### 4.3 — Reference (read first) - -The complete, source-verified mapping for every API, response shape, query operator, rich-text -renderer, asset transform, GraphQL query, and Live Preview API lives in: - -**`{SKILL_DIR}/references/CONTENTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md`** (read it with the -Read tool from this skill's install dir — see the `{SKILL_DIR}` operating principle) - -Read it in full before doing anything. It is the single source of truth — follow it; do not rely -on prior knowledge where the doc is specific. Key map: - -- §0.1 — detect the data-access approach (decision table) -- §1–§16 — REST Delivery SDK (`@contentstack/delivery-sdk`) mapping -- §17 — GraphQL Content API migration -- §18 — Live Preview / draft mode migration -- §19 — raw REST / `fetch` and framework source plugins -- §13 gotchas, §15 checklist - -### 4.4 — Procedure - -1. **DETECT (doc §0.1).** Determine the app's language, framework, and which data-access - approach(es) it uses, plus whether it implements Live Preview / draft mode. Migrate in the SAME - language and framework, preserving the SAME approach (REST→REST, GraphQL→GraphQL, preview→preview). - Report findings and PAUSE for confirmation. - -2. **PREREQUISITES.** Confirm the target Contentstack stack already has the matching content model - and published content, and confirm the Contentful-field-ID → Contentstack-field-UID map from - step 4.1. If any UIDs are unknown, infer from a sample Contentstack entry and FLAG every guess. - Confirm env vars (`CS_API_KEY`, `CS_DELIVERY_TOKEN`, `CS_ENVIRONMENT`, + region/branch, + - preview token if Live Preview) — these come from `metadataPath` (step 4.1), not the user - (use `stack_api_key`, NOT `stack_id`, for `CS_API_KEY`). If the content model or entries do - not yet exist in Contentstack, - STOP — code migration requires content to be imported first (Steps 1–3). - -3. **PLAN.** Produce a table: file:line → source call → Contentstack equivalent (cite the doc - section) → field-UID dependencies → risk notes. Show it and PAUSE before editing any file. - -4. **MIGRATE** per the doc, following the section matching each detected approach: - - - REST Delivery SDK: §1–§16. GraphQL: §17. Raw REST / framework plugins: §19. - - Rich text / assets / locales / pagination: §9–§12. - Make minimal, mechanical edits that match surrounding code style and the framework's existing - data-fetching idioms. Preserve function/component contracts. - -5. **LIVE PREVIEW.** If step 1 found preview/draft-mode, reimplement it per §18, matching the - source's scope (routes, components, SSR vs client, click-to-edit vs read-only). Keep preview - tokens server-side and preserve existing preview gating/routing. - -6. **VERIFY — run the eval suite (this is mandatory, not optional).** - Install deps first so the build eval is meaningful, then run the bundled evals in parallel: - ```bash - bash "$SKILL_DIR/scripts/run-all.sh" - ``` - For maximum parallelism you may instead spawn one agent per `"$SKILL_DIR/scripts/"`NN\_\*.sh. - See `"$SKILL_DIR/scripts/README.md"` for what each check catches and exit-code semantics. - - **Hard-gate FAIL/ERROR (residue, field-access, sdk-init, build, secrets) ⇒ the migration is NOT - done.** Fix and re-run until they pass. - - **Triage every review-eval finding** at its `file:line` — static greps flag _suspects_, not - proven bugs. Fix the true positives; state explicitly why any remaining ones are safe. Never - dismiss findings silently. - - A green build is necessary but **not sufficient** — it cannot catch reference-array bugs, wrong - field UIDs, or RTE output. Still smoke-test live queries against the real Contentstack stack. - - For anything the doc marks "verify against current docs" (GraphQL hosts/headers, Live Preview - front-end API), confirm before finalizing rather than guessing. - -### 4.5 — Guardrails - -- Do NOT modify content modeling or move/import entries — out of scope for this step. -- Convert every reference dereference to safe array access (`?.[0]`) and audit null safety - (Contentstack resolves references to arrays, not single objects). -- When a UID or behavior is uncertain, leave a `// TODO(migration):` comment and list it — never - guess silently. - -### 4.6 — Wrap up - -> **[PROGRESS]** Output the migration progress block: -> Steps 1–4 all → `"completed"`. Then immediately proceed to Step 5. - -Give the user a final summary of the whole migration journey: - -- **Content:** counts imported into the stack (from Step 3). -- **Code:** files changed, the rich-text rendering strategy chosen, guessed UIDs to verify, and - any `TODO(migration)` call sites still needing attention. -- **Eval results:** whether all hard gates passed and which review findings remain to triage. -- **Detection summary:** language/framework/approach(es) detected; whether Live Preview was - present and how it was reimplemented; every guessed UID; every TODO; and any call site not - fully migrated (geo queries, `locale: '*'`, cross-space ResourceLinks, GraphQL features without - an equivalent). -- **Next steps:** set the `CS_*` env vars in the app's local `.env` from `metadata.json` - (`CS_API_KEY` = `stack_api_key`, `CS_DELIVERY_TOKEN` = `delivery_token`, `CS_ENVIRONMENT` = - `environment`, plus `CS_PREVIEW_TOKEN` = `preview_token` if Live Preview, and the region from - `csdx config:get:region`), run the app against Contentstack, and verify pages render. - - -## Step 5 — Welcome to Contentstack 🎉 - -The migration is complete. Display the following message to the user — render it exactly as shown, preserving the section headings, icons, and line breaks: - - -![Contentstack](https://images.contentstack.io/v3/assets/blt77d44a06c81b1730/blt2e24a315fedaeaf7/68bc10f25f14881bc908b6c2/CS_OnlyLogo.webp) - -``` -╔══════════════════════════════════════════════════════════════════╗ -║ ║ -║ 🚀 Welcome to Contentstack! ║ -║ ║ -║ The Agentic Experience Platform ║ -║ ║ -╚══════════════════════════════════════════════════════════════════╝ -``` - -> *"The world's best digital experiences run on Contentstack."* - -**🎊 Your migration is complete.** - -Your content, content types, assets, and website code have all successfully moved from Contentful to Contentstack. Here's a quick recap of what just happened: - -| ✅ | What was migrated | -|---|---| -| 📦 | Content types & field definitions | -| 🖼️ | Assets & media | -| 📝 | Entries & localized content | -| 💻 | Website data-layer code | - -### 📂 Where to find your migrated files - -Using the exact paths captured during this session, fill in and display this table: - -| Artifact | Location | -|---|---| -| 🗂️ **Contentful export** | The `export.json` path in `$SESSION_DIR` (from Step 3) | -| 📦 **Contentstack import bundle** | `$SESSION_DIR/bundle/` (from Step 3) | -| 🔑 **Stack credentials** | `$SESSION_DIR/bundle/metadata.json` (from Step 3) | -| 📋 **Import logs** | The log directory printed by `migrate:create` (Step 3) | -| 💻 **Migrated website code** | The `repoPath` the user provided in Step 4 | -| 🔍 **Code migration log** | `/.migration/session.log` | - -Do not use default or guessed paths — substitute only the real paths you captured from each step's command output. - - -### 🌟 You're now on the platform trusted by the world's top brands - -Contentstack powers digital experiences for enterprises across retail, media, finance, and beyond — delivering content at scale, across every channel, without compromise. - -Here's what you've unlocked: - -| Capability | What it means for you | -|---|---| -| ⚡ **Composable architecture** | Mix and match best-of-breed tools — your stack, your way | -| 🌍 **Multi-region delivery** | Content served fast, anywhere on the globe | -| 🔄 **Omnichannel publishing** | Web, mobile, IoT, voice — one content hub for all | -| 🛡️ **Enterprise-grade security** | SOC 2 Type II, GDPR, HIPAA-ready | -| 🤝 **Dedicated support** | Real humans, not just docs — onboarding, migrations, and beyond | -| 🧩 **Marketplace & integrations** | 100+ pre-built connectors — plug in what you already use | - - -### 🚦 Recommended next steps - -1. **Verify your live site** — start your app with the new `CS_*` env vars and confirm pages render against Contentstack. -2. **Explore the Contentstack dashboard** — invite your team, set up roles, and configure publishing workflows. -3. **Set up webhooks & automation** — trigger deploys, Slack alerts, or custom workflows on publish events. -4. **Review the Contentstack Docs** — [contentstack.com/docs](https://www.contentstack.com/docs) is your go-to for Delivery SDK, GraphQL, and Live Preview guides. -5. **Talk to your account team** — let them know you're live; they can unlock additional features and walk you through advanced capabilities. - - -> 💡 **Tip:** Bookmark the [Contentstack Developer Hub](https://www.contentstack.com/developers) — it has SDK references, starter apps, and video tutorials to help you get the most out of your new platform. - - -*Congratulations on completing your migration. -You've made the right call — the world's best digital experiences are built on Contentstack, and now yours will be too.* 🚀 diff --git a/codex/migration-companion/references/CONTENTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md b/codex/migration-companion/references/CONTENTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md deleted file mode 100644 index d19ab85..0000000 --- a/codex/migration-companion/references/CONTENTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md +++ /dev/null @@ -1,907 +0,0 @@ -# Contentful → Contentstack Migration Context (for AI Agents) - -> **Purpose of this file.** This is a reference context document for AI coding models tasked -> with migrating a **web application that consumes Contentful** so that it consumes -> **Contentstack** instead. It maps concepts, SDK APIs, query operators, field types, -> rich-text rendering, assets, locales and pagination from the Contentful JS SDKs to the -> Contentstack TypeScript Delivery SDK (`@contentstack/delivery-sdk`) and its helper -> library (`@contentstack/utils`). -> -> **It covers all the common ways a web app consumes Contentful, not just one SDK:** -> the REST Delivery SDK (`contentful`), the **GraphQL** Content API (§17), **Live Preview / -> draft mode** (§18), raw REST / `fetch` access and framework source plugins (§19). Always -> begin by detecting which approach(es) the target app uses (§0.1) and migrate **like-for-like** -> — REST→REST, GraphQL→GraphQL, preview→preview — preserving the app's language and framework. -> -> **Scope:** _application / SDK code migration_ — i.e. rewriting the data-fetching and -> rendering layer of a website. It is **not** a content/data ETL guide (moving entries -> between stacks is a separate task done via the Contentstack Management API / CLI / import -> tooling). Where content-modeling concepts are mentioned, they exist only to help the agent -> map the response shapes correctly. - ---- - -## 0. How an AI agent should use this document - -0. **Detect language, framework, and data-access approach first (§0.1).** Migrate in the - *same* language and framework, and preserve the *same* data-access style (REST SDK → - Delivery SDK; GraphQL → Contentstack GraphQL; raw fetch → raw fetch). Do not change paradigms. -1. **Identify the Contentful surface in the target app.** Search the codebase for - `from 'contentful'`, `from 'contentful-management'`, `createClient`, `getEntries`, - `getEntry`, `getAssets`, `.fields.`, `.sys.`, `@contentful/rich-text-*`, and image URLs - on `fields.file.url`. Also search for GraphQL (`graphql.contentful.com`, `gql`, - `@apollo/client`, `urql`, `graphql-request`, `*.graphql`) and Live Preview - (`preview.contentful.com`, CPA token, `@contentful/live-preview`, `draftMode`). -2. **Classify each call site** using the mapping tables below (client init, read, query, - reference resolution, rich text, asset/image, locale, pagination) — and the approach-specific - sections (§17 GraphQL, §18 Live Preview, §19 raw REST / frameworks). -3. **Rewrite each call site** to the Contentstack equivalent, paying special attention to - the **response-shape differences** (Section 6) — this is the single largest source of - migration bugs. Contentful nests content under `sys`/`fields`; Contentstack flattens it. -4. **Migrate rendering** (rich text, images) using `@contentstack/utils` (Section 9–10). -5. **Migrate Live Preview / draft mode** (§18) if the source app implements it. -6. **Verify** against the gotchas (Section 13) and the checklist (Section 15). - -### 0.1 Detect the data-access approach (decide the migration path) - -| Signal found in the source app | Contentful approach | Migrate to | See | -|---|---|---|---| -| `import { createClient } from 'contentful'`, `getEntry(s)`, `getAsset(s)` | REST Delivery SDK (CDA) | `@contentstack/delivery-sdk` builder | §1–§16 | -| `graphql.contentful.com`, `gql`/`*.graphql`, Apollo/urql/graphql-request | GraphQL Content API | Contentstack GraphQL Content Delivery API (same GraphQL client) | §17 | -| `host: 'preview.contentful.com'`, CPA token, `@contentful/live-preview`, `useContentfulLiveUpdates`, Next `draftMode` | Live Preview / draft mode | Contentstack Live Preview (`live_preview` config + `@contentstack/live-preview-utils`) | §18 | -| Raw `fetch`/`axios` to `cdn.contentful.com/...`, or `gatsby-source-contentful` | Direct REST / build-time source plugin | Contentstack REST endpoints / `@contentstack/gatsby-source-contentstack` | §19 | -| `import 'contentful-management'` | Management API (editorial tooling) | `@contentstack/management` (out of scope here; note it) | §1 | - -A single app may use **several** of these at once (e.g. GraphQL for reads + Live Preview for -the editor). Migrate each surface in kind. - -**Golden rule:** Contentful and Contentstack are both API-first headless CMSs with a similar -mental model (a *space/stack* contains *content types*, *entries*, and *assets*, published to -*environments*). The migration is mostly mechanical *if* the response-shape and -field-addressing differences are handled rigorously. - ---- - -## 1. Package & import mapping - -| Concern | Contentful | Contentstack | -|---|---|---| -| Content **delivery** (read) SDK | `contentful` (CDA/CPA) | `@contentstack/delivery-sdk` | -| Content **management** (write) SDK | `contentful-management` (CMA) | `@contentstack/management` (out of scope here) | -| Shared HTTP/core layer (internal) | `contentful-sdk-core` | `@contentstack/core` | -| Rich-text / utility rendering | `@contentful/rich-text-html-renderer`, `@contentful/rich-text-react-renderer`, `@contentful/rich-text-types` | `@contentstack/utils` | - -```bash -# remove -npm uninstall contentful contentful-management \ - @contentful/rich-text-html-renderer @contentful/rich-text-react-renderer @contentful/rich-text-types - -# add -npm install @contentstack/delivery-sdk @contentstack/utils -# optional, only if cache policies are used: -npm install @contentstack/persistence-plugin -``` - -```ts -// Contentful -import { createClient } from 'contentful' - -// Contentstack -import contentstack from '@contentstack/delivery-sdk' -import * as Utils from '@contentstack/utils' // rich text, embedded items -``` - -> A web app that *reads* content uses the Contentful **CDA** SDK (`contentful`). Some apps -> also use `contentful-management` (CMA) for previews or editorial tooling. This document -> focuses on the read path (CDA → Contentstack Delivery). The CMA query/entity model -> (`client.entry.getMany({ spaceId, environmentId, query })`) shares the same query-operator -> and data-model semantics described below. - ---- - -## 2. Terminology mapping - -| Contentful | Contentstack | Notes | -|---|---|---| -| Space | Stack | Top-level content container. | -| Space ID | API Key | Identifies the container in client init. | -| Content Delivery API token (CDA) | Delivery Token | Read token. | -| Content Preview API token (CPA) | Delivery Token of a *preview* / Live Preview token | Preview handled via `live_preview` config. | -| Environment (`master`, …) | Environment | Both publish to named environments. Required in Contentstack init. | -| Content Type | Content Type | Same concept. UID identifies it. | -| Entry | Entry | Same concept. | -| Asset | Asset | Media file. | -| Field | Field | Addressed differently (see §6). | -| `sys.id` | `uid` | Stable identifier of an entry/asset/content type. | -| Locale (`en-US`) | Locale (`en-us`) | Contentstack locale codes are lower-cased (`en-us`, `fr-fr`). | -| Tag | Tag | Contentstack also has Taxonomies (richer). | -| Rich Text (RichText document) | JSON RTE / Supercharged RTE | Different JSON shape & renderer (see §9). | -| Reference (Link) | Reference field | Resolved via `includeReference` instead of `include` depth. | -| Modular content (Array of links) | Modular Blocks / Reference | — | -| Region/host | Region/host | Contentstack uses an explicit `Region` enum (US/EU/AU/Azure/GCP). | - ---- - -## 3. Client initialization - -### Contentful (CDA) -```ts -import { createClient } from 'contentful' - -const client = createClient({ - space: 'SPACE_ID', - accessToken: 'CDA_TOKEN', - environment: 'master', // optional, defaults to 'master' - host: 'cdn.contentful.com', // 'preview.contentful.com' for CPA -}) -``` - -### Contentstack (Delivery) -```ts -import contentstack, { Region } from '@contentstack/delivery-sdk' - -const stack = contentstack.stack({ - apiKey: 'API_KEY', // was: space - deliveryToken: 'DELIVERY_TOKEN',// was: accessToken - environment: 'production', // REQUIRED (no default) - region: Region.US, // US (default) | EU | AU | AZURE_NA | AZURE_EU | GCP_NA | GCP_EU - locale: 'en-us', // optional default locale - // host: 'custom-cdn.example.com', // optional; overrides region host - // branch: 'main', // optional branch -}) -``` - -**Key init differences (verified against `src/stack/contentstack.ts`):** -- `apiKey`, `deliveryToken`, **and `environment` are all required**; the SDK throws on init if - any is missing. Contentful only requires `space` + `accessToken`. -- Region is a first-class enum. Don't hardcode hostnames unless you need a custom host. - Region → host: `US → cdn.contentstack.io`, `EU → eu-cdn.contentstack.com`, - `AU → au-cdn.contentstack.com`, `AZURE_NA → azure-na-cdn.contentstack.com`, - `AZURE_EU → azure-eu-cdn.contentstack.com`, `GCP_NA → gcp-na-cdn.contentstack.com`, - `GCP_EU → gcp-eu-cdn.contentstack.com`. -- Preview: Contentful switches `host` to `preview.contentful.com` with a CPA token. - Contentstack uses a `live_preview` config object + `stack.livePreviewQuery(...)` instead. -- The Contentstack client is a builder: you start from `stack.contentType(uid)` / - `stack.asset(uid)` and chain. There is no flat `client.getEntries(...)`. - ---- - -## 4. Reading content — method mapping - -Contentstack uses a **fluent builder** rooted at the `stack`. Calls terminate in -`.fetch()` (single object) or `.find()` (collection/query). - -| Operation | Contentful (CDA) | Contentstack | -|---|---|---| -| Single entry by id | `client.getEntry(entryId)` | `stack.contentType(ctUid).entry(entryUid).fetch()` | -| Entries of a content type | `client.getEntries({ content_type: 'blog' })` | `stack.contentType('blog').entry().query().find()` | -| All entries (filter on `content_type`) | `client.getEntries({ content_type })` | `stack.contentType(ctUid).entry().query()...find()` | -| Single asset | `client.getAsset(assetId)` | `stack.asset(assetUid).fetch()` | -| All assets | `client.getAssets(query)` | `stack.asset().query()...find()` (or `stack.asset().find()`) | -| Single content type (schema) | `client.getContentType(id)` | `stack.contentType(uid).fetch()` | -| All content types | `client.getContentTypes()` | `stack.contentType().find()` | -| Sync API | `client.sync({ initial: true })` | `stack.sync({ ... })` | -| Global field (Contentstack-only) | — | `stack.globalField(uid).fetch()` / `stack.globalField().find()` | -| Taxonomy query (Contentstack-only) | — | `stack.taxonomy()` | - -> **Important:** In Contentful, `content_type` is just a query parameter. In Contentstack, -> the content type UID is **part of the path** (`stack.contentType(uid)…`). A single -> Contentful `getEntries` call that mixed multiple content types must be split per content -> type in Contentstack, **or** use the asset/entry query without a content type only for assets. - -### Canonical examples - -```ts -// --- Single entry --- -// Contentful -const entry = await client.getEntry('blog123') -// Contentstack -const entry = await stack.contentType('blog_post').entry('blog123').fetch() - -// --- Collection --- -// Contentful -const res = await client.getEntries({ content_type: 'blog_post', limit: 10 }) -res.items.forEach(...) -// Contentstack -const res = await stack.contentType('blog_post').entry().query().limit(10).find() -res.entries?.forEach(...) -``` - ---- - -## 5. Query operator & modifier mapping - -Contentful expresses queries as a flat params object with bracketed operators -(`'fields.price[gte]': 10`). Contentstack uses a `Query` builder obtained via -`stack.contentType(uid).entry().query()`, with explicit methods **or** the generic -`.where(fieldUid, QueryOperation.X, value)`. - -Import the operator enums: -```ts -import { QueryOperation, QueryOperator } from '@contentstack/delivery-sdk' -``` - -### 5.1 Field comparison operators - -| Meaning | Contentful param | Contentstack builder method | Contentstack `.where(...)` | Raw operator | -|---|---|---|---|---| -| Equals | `'fields.x': v` | `.equalTo('x', v)` | `.where('x', QueryOperation.EQUALS, v)` | (bare value) | -| Not equals | `'fields.x[ne]': v` | `.notEqualTo('x', v)` | `.where('x', QueryOperation.NOT_EQUALS, v)` | `$ne` | -| In set | `'fields.x[in]': 'a,b'` | `.containedIn('x', ['a','b'])` | `.where('x', QueryOperation.INCLUDES, ['a','b'])` | `$in` | -| Not in set | `'fields.x[nin]': 'a,b'` | `.notContainedIn('x', ['a','b'])` | `.where('x', QueryOperation.EXCLUDES, ['a','b'])` | `$nin` | -| Greater than | `'fields.x[gt]': v` | `.greaterThan('x', v)` | `.where('x', QueryOperation.IS_GREATER_THAN, v)` | `$gt` | -| Greater or equal | `'fields.x[gte]': v` | `.greaterThanOrEqualTo('x', v)` | `.where('x', QueryOperation.IS_GREATER_THAN_OR_EQUAL, v)` | `$gte` | -| Less than | `'fields.x[lt]': v` | `.lessThan('x', v)` | `.where('x', QueryOperation.IS_LESS_THAN, v)` | `$lt` | -| Less or equal | `'fields.x[lte]': v` | `.lessThanOrEqualTo('x', v)` | `.where('x', QueryOperation.IS_LESS_THAN_OR_EQUAL, v)` | `$lte` | -| Field exists | `'fields.x[exists]': true` | `.exists('x')` / `.notExists('x')` | `.where('x', QueryOperation.EXISTS, true)` | `$exists` | -| Regex / match | `'fields.x[match]': 'foo'` | `.regex('x', '^foo', 'i')` | `.where('x', QueryOperation.MATCHES, 'foo')` | `$regex` (+ `$options`) | -| Tags | `'metadata.tags.sys.id[in]': '...'` | `.tags(['t1','t2'])` | — | `tags` | -| Full-text search | `query: 'term'` | `.search('term')` | — | `typeahead` param | - -> Notes: -> - Contentstack `.where(field, QueryOperation.EQUALS, v)` stores the bare value (no operator -> wrapper), matching Contentful's bare `'fields.x': v`. -> - Contentstack has no direct equivalent to Contentful geo operators `[near]` / `[within]` -> in the delivery builder; use `.where()`/`.addParams()` with the appropriate raw param if -> geo querying is required. -> - Contentful `[all]` (array contains all) has no first-class builder method; model with -> `$and` of `containedIn`/`equalTo` or `.addParams()`. - -### 5.2 Logical combination - -| Meaning | Contentful | Contentstack | -|---|---|---| -| AND of sub-queries | Multiple params are ANDed implicitly | `.and(q1, q2)` or `.queryOperator(QueryOperator.AND, q1, q2)` | -| OR of sub-queries | Not natively supported in a single CDA call (often multiple calls) | `.or(q1, q2)` or `.queryOperator(QueryOperator.OR, q1, q2)` | - -```ts -// Contentstack OR example -const q1 = stack.contentType('blog').entry().query().equalTo('category', 'news') -const q2 = stack.contentType('blog').entry().query().greaterThan('views', 1000) -const res = await stack.contentType('blog').entry().query().or(q1, q2).find() -``` - -### 5.3 Sorting, pagination, field selection - -| Meaning | Contentful | Contentstack | -|---|---|---| -| Sort ascending | `order: 'fields.title'` | `.orderByAscending('title')` | -| Sort descending | `order: '-fields.title'` | `.orderByDescending('title')` | -| Limit | `limit: 10` | `.limit(10)` | -| Skip / offset | `skip: 20` | `.skip(20)` | -| Total count in result | `res.total` (always present) | `.includeCount()` → `res.count` | -| Select only fields | `select: 'fields.title,fields.slug'` | `.only(['title','slug'])` | -| Exclude fields | (no direct CDA param) | `.except(['body'])` | -| Arbitrary raw param | add key to query object | `.param(key, value)` / `.addParams({...})` | - -> Contentstack `only`/`except` use a `BASE` scope under the hood -> (`only[BASE][]=title`); just pass field UIDs to the builder methods. -> -> **Placement (verified against source):** `.only()` / `.except()` live on `.entry()` / -> `.entries()` (and `.asset()`), **not** on the `.query()` object. Call them *before* `.query()`: -> `stack.contentType(ct).entry().only(['title','slug']).query().find()`. Chaining -> `.query().only(...)` will fail. - ---- - -## 6. Response shape mapping (MOST IMPORTANT) - -This is where most migration bugs originate. **Contentful wraps content in `sys` + `fields`; -Contentstack returns a flat entry object.** - -### 6.1 Single entry - -**Contentful:** -```jsonc -{ - "sys": { "id": "blog123", "contentType": { "sys": { "id": "blogPost" } }, - "createdAt": "...", "updatedAt": "...", "locale": "en-US" }, - "fields": { // keyed by field id; flattened to one locale by default - "title": "Hello", - "slug": "hello", - "author": { "sys": { "type": "Link", "linkType": "Entry", "id": "auth1" } } - }, - "metadata": { "tags": [] } -} -// access: entry.fields.title, entry.sys.id, entry.sys.contentType.sys.id -``` - -**Contentstack (verified against `BaseEntry` in `src/common/types.ts`):** -```jsonc -{ - "uid": "blt...", // was sys.id - "title": "Hello", // fields are TOP-LEVEL, not under .fields - "slug": "hello", - "locale": "en-us", // was sys.locale - "created_at": "...", // was sys.createdAt - "updated_at": "...", // was sys.updatedAt - "_version": 3, - "tags": [], - "publish_details": { "environment": "...", "locale": "en-us", "time": "...", "user": "..." }, - "author": [ { /* resolved referenced entry */ } ] // references are ARRAYS -} -// access: entry.title, entry.uid, entry.locale -``` - -### 6.2 Field address translation cheatsheet - -| Contentful access | Contentstack access | -|---|---| -| `entry.fields.title` | `entry.title` | -| `entry.fields.` | `entry.` (drop the `.fields.` prefix) | -| `entry.sys.id` | `entry.uid` | -| `entry.sys.contentType.sys.id` | known from the path (`contentType(uid)`); or `_content_type_uid` on resolved references | -| `entry.sys.createdAt` / `updatedAt` | `entry.created_at` / `entry.updated_at` | -| `entry.sys.locale` | `entry.locale` | -| `entry.sys.revision` / `version` | `entry._version` | -| `entry.metadata.tags` | `entry.tags` (+ richer Taxonomy support) | - -### 6.3 Collection result - -| Contentful | Contentstack | -|---|---| -| `res.items` (array) | `res.entries` (array; `res.assets` for asset queries) | -| `res.total` | `res.count` (only when `.includeCount()` was called) | -| `res.skip` / `res.limit` | echoed in request; not returned the same way | -| `res.includes.Entry` / `.Asset` | resolved inline into entry fields via `includeReference` | - -Contentstack `find()` returns `FindResponse`: -`{ entries?: T[]; assets?: T[]; content_types?: TContentType[]; count?: number }`. -`fetch()` returns the single object directly (the SDK unwraps `response.entry` / -`response.asset` / `response.content_type` for you). - ---- - -## 7. References / linked entries - -**Contentful** auto-resolves links up to a depth using `include` (0–10, default 1) and -returns unresolved links plus an `includes` sidecar that the SDK stitches into `fields`. - -**Contentstack** does **not** resolve references by default. You must explicitly request each -reference field by UID via `includeReference`. Resolved references appear **inline as arrays** -on the entry. - -| Contentful | Contentstack | -|---|---| -| `getEntries({ content_type, include: 2 })` | `.includeReference('author', 'author.company')` (dot-path for nested) | -| automatic link resolution | explicit per-field `includeReference(...)` | -| `res.includes.Entry/Asset` | inline arrays on the resolved field | -| `links_to_entry` (reverse lookup) | `.whereIn(refUid, subQuery)` / `.referenceIn(field, subQuery)` | -| reference NOT matching | `.whereNotIn(...)` / `.referenceNotIn(...)` | -| include content type uid of refs | `.includeReferenceContentTypeUID()` | - -```ts -// Contentful: depth-based -const res = await client.getEntries({ content_type: 'blog', include: 2 }) -const authorName = res.items[0].fields.author.fields.name - -// Contentstack: explicit, references resolve to arrays -const res = await stack.contentType('blog').entry().query() - .includeReference('author', 'author.company') - .find() -const authorName = res.entries?.[0].author?.[0]?.name // note the [0] — references are arrays -``` - -> **Migration pitfall:** A single Contentful reference becomes a **single-element array** in -> Contentstack. Code that did `entry.fields.author.fields.name` becomes -> `entry.author?.[0]?.name`. Audit every dereference. - -Related include modifiers (verified in `entries.ts` / `entry.ts`): -`includeContentType()`, `includeEmbeddedItems()` (RTE embedded entries/assets), -`includeFallback()` (locale fallback), `includeMetadata()`, `includeBranch()`, -`includeSchema()`. - ---- - -## 8. Field-type mapping (for response handling) - -Contentful field `type` values (verified in `lib/entities/content-type-fields.ts`) map to -Contentstack `data_type` equivalents. Content modeling itself happens in the Contentstack UI / -Management API; this table helps the agent reason about **what a field will look like in the -response** and how to render it. - -| Contentful field `type` | Contentstack equivalent (`data_type`) | Response/handling notes | -|---|---|---| -| `Symbol` (short text) | `text` (single line) | plain string | -| `Text` (long text) | `text` (multiline) | plain string | -| `RichText` | `json` (JSON RTE) | different JSON shape → render with `@contentstack/utils` (§9) | -| `Integer` | `number` | number | -| `Number` (decimal) | `number` | number | -| `Date` | `isodate` | ISO date string | -| `Boolean` | `boolean` | boolean | -| `Location` (lat/lon) | `group` (lat/lng) | object shape differs | -| `Object` (JSON) | `json` | arbitrary JSON | -| `Link` → `Entry` | `reference` | array of resolved entries (with `includeReference`) | -| `Link` → `Asset` | `file` | asset object (see §10) | -| `Array` of `Symbol` | `text` (multiple) | array of strings | -| `Array` of `Link` | `reference` (multiple) | array of entries | -| `Array` of `Link` | `file` (multiple) | array of assets | -| (component/embedded) | `group` / `global_field` / `blocks` (Modular Blocks) | nested object/array | -| `ResourceLink` (cross-space) | reference / external | re-model as needed | -| `metadata.tags` | `tags` / Taxonomy | — | - ---- - -## 9. Rich text rendering - -This is a substantial change. **The JSON document shapes are different and the renderers are -different.** Contentful RichText is a `@contentful/rich-text-types` document; Contentstack -uses JSON RTE (Supercharged RTE) rendered via `@contentstack/utils`. - -| Concern | Contentful | Contentstack (`@contentstack/utils`) | -|---|---|---| -| Field type | `RichText` (document JSON) | JSON RTE (`json` data_type) | -| HTML string render | `documentToHtmlString(doc, options)` from `@contentful/rich-text-html-renderer` | `Utils.jsonToHTML({ entry, paths, renderOption })` | -| React / component render | `documentToReactComponents(doc, options)` from `@contentful/rich-text-react-renderer` (returns a **component tree**) | `@contentstack/utils` emits **HTML strings only** — there is no React/Vue/Angular component renderer. Inject the HTML (`dangerouslySetInnerHTML` / `v-html` / `[innerHTML]`), or use a dedicated JSON-RTE→component serializer for the framework. `Utils.render` does **not** return JSX. | -| Embedded entries/assets | `BLOCKS.EMBEDDED_ENTRY`, `INLINES.EMBEDDED_ENTRY`, `BLOCKS.EMBEDDED_ASSET` handled in `renderNode` | request with `.includeEmbeddedItems()`, then `Utils.render({ entry, renderOption })` | -| Node/mark customization | `options.renderNode` / `options.renderMark` keyed by `BLOCKS`/`INLINES`/`MARKS` | `renderOption` object keyed by node tag (`p`, `h1`, `a`, …), marks (`bold`), `block`, `inline`, `reference`, `display`, `default` | - -```ts -// Contentful -import { documentToHtmlString } from '@contentful/rich-text-html-renderer' -const html = documentToHtmlString(entry.fields.body) - -// Contentstack -import * as Utils from '@contentstack/utils' -const renderOption = { - p: (node, next) => `

${next(node.children)}

`, - h1: (node, next) => `

${next(node.children)}

`, - bold:(text) => `${text}`, - a: (node) => { - const txt = node.children.map((c) => c.text || '').join('') - return `${txt}` - }, -} -// For Supercharged/JSON RTE fields (MUTATES `entry` in place; returns void): -Utils.jsonToHTML({ entry, paths: ['body', 'group.rte_field'], renderOption }) -// For HTML-RTE embedded items (fetch with .includeEmbeddedItems() first): -// NOTE: the option key is `paths` (plural string[]), NOT `path`. Also mutates `entry` in place. -Utils.render({ entry, paths: ['body'], renderOption }) -// To render a raw RTE string/array and RECEIVE the HTML back (no mutation): Utils.renderContent(content, option) -``` - -> Steps for the agent: -> 1. Add `.includeEmbeddedItems()` to any entry/entries fetch that renders RTE with embeds. -> 2. Replace `documentToHtmlString(entry.fields.body)` with -> `Utils.jsonToHTML({ entry, paths: ['body'], renderOption })` (note: it mutates/returns -> HTML keyed onto the field path; pass the whole `entry`, not just the field value). -> 3. Translate `renderNode`/`renderMark` handlers into the `renderOption` shape. - ---- - -## 10. Assets & image transformations - -### 10.1 Asset shape - -| Contentful | Contentstack | -|---|---| -| `asset.fields.file.url` (often protocol-relative `//...`) | `asset.url` (absolute) | -| `asset.fields.file.fileName` | `asset.filename` | -| `asset.fields.file.contentType` | `asset.content_type` | -| `asset.fields.file.details.size` | `asset.file_size` | -| `asset.fields.file.details.image.{width,height}` | use `.includeDimension()` on asset fetch → `asset.dimension` | -| `asset.fields.title` | `asset.title` | -| `asset.sys.id` | `asset.uid` | - -```ts -// Contentful -const url = 'https:' + asset.fields.file.url -// Contentstack -const url = asset.url -``` - -### 10.2 Image API / transforms - -Both support URL-based image manipulation, but param names differ. Contentstack provides an -`ImageTransform` builder (`@contentstack/delivery-sdk`) and a `String.prototype.transform` -helper. - -| Transform | Contentful query param | Contentstack `ImageTransform` method | -|---|---|---| -| Width / height / resize | `?w=300&h=200` | `.resize({ width: 300, height: 200 })` | -| Format | `?fm=webp` | `.format(Format.WEBP)` | -| Quality | `?q=80` | `.quality(80)` | -| Fit / crop | `?fit=fill` / `?f=crop` | `.fit(FitBy.CROP)` / `.crop({...})` | -| Auto optimize | `?fm=webp` (manual) | `.auto()` | -| Background | `?bg=...` | `.bgColor('cccccc')` | -| DPR | `?dpr=2` | `.dpr(2)` | -| Blur / sharpen | `?blur=` / — | `.blur(n)` / `.sharpen(a,r,t)` | -| Orientation | `?or=` | `.orient(Orientation.RIGHT)` | -| Trim / pad / overlay / canvas | `?trim=` etc. | `.trim()`, `.padding()`, `.overlay({...})`, `.canvas({...})` | - -```ts -import { ImageTransform, Format } from '@contentstack/delivery-sdk' -const t = new ImageTransform().resize({ width: 300, height: 200 }).format(Format.WEBP).quality(80) -const optimized = asset.url.transform(t) // String.prototype.transform helper (loaded by the SDK) -``` - -> **Caveat (verified in source):** `Format` is a runtime value export, but at the package root -> `ImageTransform` is currently re-exported **type-only** (`export type { ImageTransform }` in -> `index.ts`). If `new ImageTransform()` from the package root fails at runtime, import the -> value class from the assets module (the SDK's own tests use -> `import { ImageTransform } from '@contentstack/delivery-sdk/dist/.../assets'`), or build the -> transform URL by appending the documented image-delivery query params directly -> (`?width=300&height=200&format=webp&quality=80`). The `String.prototype.transform` helper is -> installed when the SDK is imported (`import './common/string-extensions'`). - ---- - -## 11. Locales / localization - -| Concern | Contentful | Contentstack | -|---|---|---| -| Locale code style | `en-US`, `fr-FR` | `en-us`, `fr-fr` (lower-cased) | -| Per-request locale | `getEntries({ locale: 'fr-FR' })` | `.locale('fr-fr')` on entry/entries/asset | -| Default locale | `environment` default / init | `locale` in `stack({...})` or `stack.setLocale('fr-fr')` | -| All locales at once | `locale: '*'` → fields become `{ 'en-US': v }` maps | not the same; query per locale, or use fallback | -| Fallback when unpublished | (CDA returns default-locale content per settings) | explicit `.includeFallback()` | - -> **Pitfall:** With Contentful `locale: '*'`, `entry.fields.title` becomes an object keyed by -> locale. Apps relying on this multi-locale shape must be re-architected to query per locale -> in Contentstack (Contentstack returns single-locale flat entries). - ---- - -## 12. Pagination - -| Concern | Contentful | Contentstack | -|---|---|---| -| Offset pagination | `skip` + `limit`, read `res.total` | `.skip(n).limit(m)`, `.includeCount()` → `res.count` | -| Cursor pagination | `getEntriesWithCursor` (CMA) / `res.pages.next` | use sync API / offset; cursor not in delivery builder | -| Delta sync | `client.sync({ initial, nextSyncToken })` | `stack.sync({ ... })`; **TS keys are camelCase** (`paginationToken` / `syncToken`); `init: true` is auto-added when neither is present. Response uses snake_case (`sync_token`, `pagination_token`). | - -```ts -// Contentstack offset pagination with total -const page = await stack.contentType('blog').entry().query() - .includeCount().skip(20).limit(20).find() -const total = page.count -``` - ---- - -## 13. Common gotchas / migration pitfalls - -1. **`.fields.` removal.** Every `entry.fields.X` → `entry.X`. This is the most frequent edit. -2. **`sys` → flat metadata.** `entry.sys.id` → `entry.uid`; `sys.createdAt` → `created_at`; etc. -3. **References become arrays.** `entry.fields.ref.fields.x` → `entry.ref?.[0]?.x`. Even a - single reference resolves to a one-element array. -4. **References are not auto-resolved.** Replace `include: N` with explicit - `.includeReference('field', 'field.nested')`. Forgetting this leaves you with unresolved - reference stubs (`{ uid, _content_type_uid }`). -5. **Content type is in the path.** No `content_type` query param; use - `stack.contentType(uid)`. Multi-type Contentful queries must be split per type. -6. **`environment` is mandatory** in Contentstack init (Contentful defaults to `master`). -7. **Collection key rename.** `res.items` → `res.entries` (or `res.assets`). `res.total` → - `res.count` and only when `.includeCount()` is set. -8. **`.find()` vs `.fetch()`.** Collections/queries end in `.find()`; single objects end in - `.fetch()`. Mixing them up is a common error. -9. **Rich text is a different JSON dialect.** You cannot pass a Contentful RichText document to - `@contentstack/utils`; the underlying content must live in a Contentstack JSON RTE field. - The renderer API also differs (tag-keyed `renderOption` vs `BLOCKS`/`INLINES` `renderNode`). -10. **Locale casing.** Lower-case all locale codes (`en-US` → `en-us`). -11. **Asset URLs.** Contentful URLs are often protocol-relative (`//images.ctfassets.net/...`) - and need an added scheme; Contentstack URLs are absolute. -12. **Image transform params differ.** Don't carry over `?w=&h=&fit=` query strings verbatim; - rebuild with `ImageTransform` or the correct Contentstack image param names. -13. **OR queries.** Contentstack supports `.or(...)` natively; Contentful CDA often required - multiple requests — you can consolidate during migration. -14. **Typed responses.** Pass an interface to `fetch()` / `find()`. Extend `BaseEntry` - (from `@contentstack/delivery-sdk`) for entry types so `uid`, `locale`, `created_at`, etc. - are typed. -15. **`Utils.render` uses `paths` (plural array), not `path`.** And `jsonToHTML`/`render` - **mutate the entry in place** (return `void`) — pass the whole entry and read the field - afterward; use `Utils.renderContent(content, option)` if you need a returned HTML string. -16. **`@contentstack/utils` produces HTML strings, never components.** Code using - `documentToReactComponents` (a component tree) needs an HTML-injection strategy or a - JSON-RTE→component serializer — not a 1:1 swap. -17. **`ImageTransform` is type-only at the package root.** `new ImageTransform()` from - `@contentstack/delivery-sdk` may fail at runtime; build the image query string manually - (`?width=300&height=200&format=webp&quality=80`) or deep-import the value class. -18. **`stack.sync` keys are camelCase in TypeScript** (`paginationToken`, `syncToken`), even - though the response and some JSDoc examples use snake_case. -19. **Match the data-access approach.** Don't rewrite a GraphQL app to the REST SDK (or vice - versa). GraphQL → Contentstack GraphQL (§17); preview → Contentstack Live Preview (§18). - ---- - -## 14. Worked before/after example - -### Contentful (e.g. a Next.js / React data layer) -```ts -import { createClient } from 'contentful' -import { documentToHtmlString } from '@contentful/rich-text-html-renderer' - -const client = createClient({ - space: process.env.CF_SPACE!, - accessToken: process.env.CF_CDA_TOKEN!, - environment: 'master', -}) - -export async function getPost(slug: string) { - const res = await client.getEntries({ - content_type: 'blogPost', - 'fields.slug': slug, - include: 2, - limit: 1, - }) - const post = res.items[0] - return { - title: post.fields.title, - author: post.fields.author.fields.name, - coverUrl: 'https:' + post.fields.coverImage.fields.file.url, - bodyHtml: documentToHtmlString(post.fields.body), - } -} -``` - -### Contentstack (migrated) -```ts -import contentstack, { Region, BaseEntry } from '@contentstack/delivery-sdk' -import * as Utils from '@contentstack/utils' - -const stack = contentstack.stack({ - apiKey: process.env.CS_API_KEY!, - deliveryToken: process.env.CS_DELIVERY_TOKEN!, - environment: process.env.CS_ENVIRONMENT!, // required - region: Region.US, -}) - -interface BlogPost extends BaseEntry { - slug: string - author: Array<{ name: string }> // references resolve to arrays - cover_image: { url: string } // asset (file) field - body: any // JSON RTE -} - -const renderOption = { - p: (node, next) => `

${next(node.children)}

`, - bold: (text) => `${text}`, -} - -export async function getPost(slug: string) { - const res = await stack - .contentType('blog_post') - .entry() - .query() - .equalTo('slug', slug) - .includeReference('author') // explicit reference resolution - .includeEmbeddedItems() // needed for RTE embeds - .limit(1) - .find() - - const post = res.entries?.[0] - if (!post) return null - - Utils.jsonToHTML({ entry: post, paths: ['body'], renderOption }) // mutates post.body → HTML - - return { - title: post.title, // no .fields - author: post.author?.[0]?.name, // reference is an array - coverUrl: post.cover_image?.url, // absolute URL - bodyHtml: post.body, // rendered by jsonToHTML - } -} -``` - ---- - -## 15. Migration checklist (agent run order) - -0. **Detect** language, framework, and data-access approach(es) (§0.1). Confirm prerequisites: - the target stack already has the matching content model + published content, and you have a - Contentful-field-ID → Contentstack-field-UID map. If reads are GraphQL, follow §17; if the app - has Live Preview / draft mode, also follow §18. -1. **Dependencies:** remove `contentful*` + `@contentful/rich-text-*`; add - `@contentstack/delivery-sdk` + `@contentstack/utils` (+ `@contentstack/persistence-plugin` - only if cache policies are used). -2. **Env vars:** `CF_SPACE`/`CF_CDA_TOKEN` → `CS_API_KEY`/`CS_DELIVERY_TOKEN`/`CS_ENVIRONMENT` - (+ region/branch as needed). -3. **Client init:** `createClient(...)` → `contentstack.stack({...})`. -4. **Reads:** rewrite each `getEntry`/`getEntries`/`getAsset`/`getAssets`/`getContentType(s)` - to the builder form ending in `.fetch()`/`.find()` (§4). -5. **Queries:** translate every operator/sort/pagination/select param (§5). -6. **References:** replace `include: N` with explicit `includeReference(...)`; convert single - references to `?.[0]` access (§7). -7. **Field access:** strip `.fields.`; map `sys.*` → flat metadata (`uid`, `created_at`, …) (§6). -8. **Collections:** `res.items` → `res.entries`/`res.assets`; `res.total` → - `.includeCount()` + `res.count`. -9. **Rich text:** move RTE rendering to `@contentstack/utils` (`jsonToHTML`/`render`) with a - `renderOption`; add `.includeEmbeddedItems()` where embeds are rendered (§9). -10. **Assets/images:** `fields.file.url` → `url`; rebuild image transforms with - `ImageTransform` (§10). -11. **Locales:** lower-case codes; `locale` param → `.locale(...)`; add `.includeFallback()` - where Contentful relied on default-locale fallback (§11). -12. **Types:** introduce interfaces extending `BaseEntry` for `fetch()`/`find()`. -13. **Verify:** typecheck/build; smoke-test each migrated query against a real Contentstack - stack; confirm reference arrays, RTE HTML output, and image URLs render correctly. - ---- - -## 16. Quick API equivalence (condensed) - -``` -Contentful (contentful / CDA) Contentstack (@contentstack/delivery-sdk) ------------------------------------------- --------------------------------------------------- -createClient({ space, accessToken, env }) -> contentstack.stack({ apiKey, deliveryToken, environment, region }) -client.getEntry(id) -> stack.contentType(ct).entry(id).fetch() -client.getEntries({ content_type: ct }) -> stack.contentType(ct).entry().query().find() -client.getAsset(id) -> stack.asset(id).fetch() -client.getAssets(q) -> stack.asset().query()...find() -client.getContentType(id) -> stack.contentType(id).fetch() -client.getContentTypes() -> stack.contentType().find() -client.sync({ initial: true }) -> stack.sync({ ... }) -'fields.x': v -> .equalTo('x', v) | .where('x', QueryOperation.EQUALS, v) -'fields.x[gte]': v -> .greaterThanOrEqualTo('x', v) -order: '-fields.x' -> .orderByDescending('x') -skip / limit -> .skip(n) / .limit(m) -select: 'fields.a,fields.b' -> .only(['a','b']) -include: N -> .includeReference('a','a.b') -res.items / res.total -> res.entries / (res.count via .includeCount()) -entry.fields.x / entry.sys.id -> entry.x / entry.uid -documentToHtmlString(entry.fields.body) -> Utils.jsonToHTML({ entry, paths:['body'], renderOption }) -asset.fields.file.url -> asset.url -``` - ---- - -## 17. GraphQL migration (Contentful GraphQL → Contentstack GraphQL) - -If the app reads via the **Contentful GraphQL Content API** (signals: `graphql.contentful.com`, -`gql` tagged templates, `*.graphql` files, `@apollo/client` / `urql` / `graphql-request`, -GraphQL Code Generator), migrate to the **Contentstack GraphQL Content Delivery API** — do **not** -rewrite it to the REST Delivery SDK. **Keep the same GraphQL client library**; only the endpoint, -auth, schema, and query/fragment text change. The response-shape principles in §6 still apply -(flattened fields, `uid`/`created_at` metadata, references as nested objects). - -> The Contentstack GraphQL API is a separate service and is **not** part of `@contentstack/delivery-sdk`. -> The endpoint hosts, header names, and pagination/filter argument names below should be **verified -> against current Contentstack GraphQL documentation** for the target region before finalizing. - -### 17.1 Endpoint & auth - -| Concern | Contentful GraphQL | Contentstack GraphQL | -|---|---|---| -| Endpoint | `https://graphql.contentful.com/content/v1/spaces/{SPACE}/environments/{ENV}` | `https://graphql.contentstack.com/stacks/{API_KEY}?environment={ENV}` (regional hosts: `eu-graphql…`, `azure-na-graphql…`, `azure-eu-graphql…`, `gcp-na-graphql…`, `gcp-eu-graphql…`) | -| Auth | `Authorization: Bearer {CDA_or_CPA_TOKEN}` | header `access_token: {DELIVERY_TOKEN}` (API key is in the path; `environment` is a query param) | -| Preview | `graphql.contentful.com` + CPA Bearer token | preview host + `live_preview` hash / `preview_token` header (see §18) | - -### 17.2 Query shape - -Field/type names follow the **Contentstack content-type & field UIDs** (snake_case, e.g. -`blog_post`, `cover_image`), not Contentful's camelCase ids. - -```graphql -# Contentful -query { - blogPostCollection(limit: 10, where: { slug: "hello" }) { - total - items { title slug author { name } } - } -} - -# Contentstack (verify exact arg/field names against the stack's GraphQL schema) -query { - all_blog_post(limit: 10, where: { slug: "hello" }) { - total - items { - title - slug - author { ... on SysAssetOrEntry { /* reference: nest the referenced type's fields */ } } - } - } -} -``` - -| Concept | Contentful GraphQL | Contentstack GraphQL | -|---|---|---| -| Collection query | `xxxCollection` → `{ items, total }` | `all_` → `{ items, total }` | -| Single entry | `xxx(id: "...")` | `(uid: "...")` | -| References | nested `linkedFrom` / inline link selections | **nest the referenced type's fields** in the selection (the GraphQL analog of `includeReference`) | -| Filtering | `where: { field: value, field_gt: n }` | `where: { ... }` (operator/arg names differ — verify) | -| Pagination | `limit` + `skip` (`total`) | `limit` + `skip` (`total`) | -| Localization | `locale: "en-US"` arg | `locale: "en-us"` arg (lower-cased) | -| RTE field | `json` in response | `json` in response → render with `@contentstack/utils` (§9) | - -### 17.3 Steps for the agent -1. Repoint the GraphQL client (Apollo/urql/graphql-request) at the Contentstack endpoint and swap - `Authorization: Bearer` → `access_token` header + `environment` query param. -2. Rewrite every query/fragment to the Contentstack schema (collection names, field UIDs, reference - nesting, filter args, lower-cased locales). -3. Update response handling for the new shape (`items` arrays, flat fields, `uid`/`created_at`). -4. If **GraphQL Code Generator** is used, repoint it at the Contentstack schema/introspection and - regenerate types; fix call sites against the new generated types. -5. Render RTE/JSON fields with `@contentstack/utils` (§9), same as the REST path. - ---- - -## 18. Live Preview / draft mode migration - -If the source app implements **Contentful Preview** or **Live Preview**, reimplement equivalent -behavior with **Contentstack Live Preview**, matching the source's scope (which routes/components, -SSR vs client, click-to-edit vs. read-only preview). - -**Detect in the source:** `host: 'preview.contentful.com'`, a CPA / Content Preview token, a second -"preview" client, `@contentful/live-preview` (`ContentfulLivePreview.init`, `useContentfulLiveUpdates`, -`useContentfulInspectorMode`), Next.js `draftMode()` / preview API routes, or a `?preview=` route gate. - -### 18.1 SDK config & per-request hash (verified against `@contentstack/delivery-sdk` source) - -`live_preview` is a first-class field on `StackConfig` (`src/common/types.ts`), and the stack exposes -`livePreviewQuery(...)`: - -```ts -const stack = contentstack.stack({ - apiKey: process.env.CS_API_KEY!, - deliveryToken: process.env.CS_DELIVERY_TOKEN!, - environment: process.env.CS_ENVIRONMENT!, - live_preview: { - enable: true, // REQUIRED on the LivePreview type - preview_token: process.env.CS_PREVIEW_TOKEN!, // preferred (management_token is legacy) - host: 'rest-preview.contentstack.com',// regional preview host (verify per region) - }, -}) - -// Per request, apply the preview hash (from the URL / live-preview-utils) before fetching: -stack.livePreviewQuery({ - live_preview: hash, // the live_preview hash for the edited entry - contentTypeUid: 'blog_post', // also accepts content_type_uid - entryUid: 'blt...', // also accepts entry_uid - // preview_timestamp, release_id, include_applied_variants are also supported -}) -``` - -`LivePreview` type fields (verified): `enable: boolean` (required), `preview_token?`, -`management_token?` (legacy), `host?`, `live_preview?`, `contentTypeUid?`, `entryUid?`, -`include_applied_variants?`. In the **browser**, the SDK auto-reads `live_preview`, `release_id`, -and `preview_timestamp` from the page URL's query string during `stack(...)` init. - -### 18.2 Front-end real-time updates & click-to-edit (`@contentstack/live-preview-utils`) - -> Not part of the Delivery SDK and **not vendored in this workspace** — verify the exact API against -> current `@contentstack/live-preview-utils` docs. Add it as a dependency. - -| Contentful | Contentstack | -|---|---| -| `ContentfulLivePreview.init({...})` | `ContentstackLivePreview.init({ stackDetails: { apiKey, environment }, enable: true, ssr: false /* or true */ })` | -| `useContentfulLiveUpdates(entry)` (real-time merge) | `ContentstackLivePreview.onEntryChange(cb)` → re-run the fetch in `cb` | -| live-update hash plumbing | `ContentstackLivePreview.hash` (REST) / GraphQL hash helper → pass to `stack.livePreviewQuery({ live_preview: hash, ... })` | -| `useContentfulInspectorMode()` / `data-contentful-*` field tags (click-to-edit) | `Utils.addEditableTags(entry, contentTypeUid, true, locale)` from `@contentstack/utils` → emits `data-cslp` attributes the Live Preview UI uses for click-to-edit | -| CPA token | `preview_token` (+ `live_preview` host) | - -### 18.3 Steps for the agent -1. Add `live_preview` to the stack init (`enable: true` + `preview_token` + regional preview host). -2. Add `@contentstack/live-preview-utils`; call `ContentstackLivePreview.init(...)` where the source - called `ContentfulLivePreview.init(...)`. -3. Replace the source's live-update hook with `onEntryChange(...)` re-fetching, calling - `stack.livePreviewQuery({ live_preview, contentTypeUid, entryUid })` before each preview fetch. -4. If the source had click-to-edit (inspector mode), add `Utils.addEditableTags(...)` and render the - resulting `data-cslp` attributes on the same elements. -5. Preserve the existing preview gating/routing (e.g. Next.js `draftMode`, `?preview=` guard); only - swap the backend. Keep preview tokens server-side. - ---- - -## 19. Raw REST / `fetch` and framework source plugins - -Not every app uses an SDK. Migrate these in kind: - -- **Raw `fetch`/`axios` to `cdn.contentful.com`.** Repoint to the Contentstack Content Delivery - REST API: base `https://{region-cdn-host}/v3` (US `cdn.contentstack.io`; see §3 for regional hosts), - headers `api_key`, `access_token`, and `environment` as a query param. Endpoints: - `/v3/content_types/{ct_uid}/entries` (list), `/v3/content_types/{ct_uid}/entries/{uid}` (single), - `/v3/assets`. Query params map per §5 (`include[]=author`, `only[BASE][]=title`, `limit`, `skip`, - `include_count=true`, `locale`, `include_fallback=true`). Response keys per §6 (`entries`/`entry`, - `assets`/`asset`, `count`). Prefer adopting `@contentstack/delivery-sdk` if it doesn't fight the - app's architecture, but a like-for-like raw-fetch migration is valid. -- **Gatsby (`gatsby-source-contentful`).** Migrate to `@contentstack/gatsby-source-contentstack`: - swap the plugin + its options (`api_key`, `delivery_token`, `environment`, `regions`) in - `gatsby-config`, and rewrite GraphQL queries from `allContentfulXxx` to the Contentstack source - plugin's node types (verify node-type naming against the plugin docs). -- **Framework data-fetching idioms — keep them.** Migrate the data-layer call *inside* the app's - existing pattern; don't change where/how data is fetched: - - Next.js: `getStaticProps`/`getServerSideProps`/`generateStaticParams`/RSC `fetch` — keep the - same function, swap the client call. Keep ISR/caching tags. - - Remix `loader`, SvelteKit `load`, Nuxt `useAsyncData`/`asyncData`, Vue composables, Angular - services/resolvers — same: swap only the CMS call body. - - Module-singleton vs per-request client: instantiate the Contentstack stack the same way the - Contentful client was instantiated (one shared client module is the common case). diff --git a/codex/migration-companion/scripts/01_contentful_residue.sh b/codex/migration-companion/scripts/01_contentful_residue.sh deleted file mode 100755 index b62f5f7..0000000 --- a/codex/migration-companion/scripts/01_contentful_residue.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# HARD GATE. No Contentful SDK/host/dependency may remain after migration. -. "$(dirname "$0")/_lib.sh" -begin "residue" "No leftover Contentful surface" - -# Source imports / requires -check "Contentful SDK import" "from[[:space:]]+['\"]contentful['\"]" -check "contentful-management import" "from[[:space:]]+['\"]contentful-management['\"]" -check "@contentful/* import" "from[[:space:]]+['\"]@contentful/" -check "contentful require()" "require\(['\"]contentful" -check "@contentful/rich-text import" "@contentful/rich-text" -check "Contentful rich-text renderers" "documentTo(HtmlString|ReactComponents)" - -# Hosts / asset domains -check "Contentful CDA host" "cdn\.contentful\.com" -check "Contentful preview host" "preview\.contentful\.com" -check "Contentful GraphQL host" "graphql\.contentful\.com" -check "Contentful asset domain" "ctfassets\.net" - -# Env var names -check "Contentful env vars" "(CONTENTFUL_[A-Z_]+|CF_SPACE|CF_CDA[A-Z_]*|CF_CPA[A-Z_]*|CTFL_[A-Z_]+)" "js,jsx,ts,tsx,mjs,cjs,vue,svelte,astro,env,example,local,sample,yml,yaml" - -# package.json must not depend on contentful, must depend on contentstack -check "contentful dependency in package.json" "\"(contentful|contentful-management|@contentful/[^\"]+)\"[[:space:]]*:" "json" -require_present "@contentstack/delivery-sdk (or @contentstack/* read SDK) dependency" "@contentstack/(delivery-sdk|management)" "json" - -finish diff --git a/codex/migration-companion/scripts/02_field_access.sh b/codex/migration-companion/scripts/02_field_access.sh deleted file mode 100755 index eabf8b4..0000000 --- a/codex/migration-companion/scripts/02_field_access.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# HARD GATE. Contentful nests under sys/fields; Contentstack is flat. (doc §6, gotchas #1-2,7) -. "$(dirname "$0")/_lib.sh" -begin "field-access" "Flattened field & metadata access (no .fields./.sys.)" - -# Strong residue: Contentful field/metadata addressing -check ".fields. field access (drop the prefix)" "\.fields\." -check ".sys. access (map to flat uid/created_at/...)" "\.sys\.(id|createdAt|updatedAt|revision|version|locale|contentType)" -check "Contentful nested reference access (.fields.x.fields.y)" "\.fields\.[A-Za-z0-9_]+\.fields\." -check "metadata.tags (use entry.tags)" "\.metadata\.tags" - -# Collection-shape residue — softer (could be unrelated arrays); flagged for verification -check "'.items' collection key (Contentstack uses .entries/.assets)" "\.items\b" -check "'.total' count key (Contentstack uses .count via includeCount())" "\.total\b" -check "Contentful includes sidecar (.includes.Entry/.Asset)" "\.includes\.(Entry|Asset)" - -finish diff --git a/codex/migration-companion/scripts/03_sdk_init.sh b/codex/migration-companion/scripts/03_sdk_init.sh deleted file mode 100755 index 0f92311..0000000 --- a/codex/migration-companion/scripts/03_sdk_init.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# HARD GATE for REST SDK apps. Stack init must be correct & required fields present. (doc §3, gotcha #6) -. "$(dirname "$0")/_lib.sh" -begin "sdk-init" "Contentstack stack() initialization" - -uses_sdk="$(search "@contentstack/delivery-sdk")" -inits="$(files_with "contentstack\.stack\(")" - -if [ -z "$uses_sdk" ] && [ -z "$inits" ]; then - na "app does not use @contentstack/delivery-sdk (GraphQL/raw-REST app — see evals 09/build)" -fi - -if [ -z "$inits" ]; then - add_finding "@contentstack/delivery-sdk is imported but no 'contentstack.stack({...})' init found" -else - for f in $inits; do - grep -q 'environment' "$f" || add_finding "stack() init may be missing required 'environment': $f" - grep -Eq 'apiKey' "$f" || add_finding "stack() init missing 'apiKey' (Contentful used 'space'): $f" - grep -Eq 'deliveryToken' "$f"|| add_finding "stack() init missing 'deliveryToken' (Contentful used 'accessToken'): $f" - grep -Eq 'space:|accessToken:' "$f" && add_finding "Contentful init keys (space/accessToken) still present: $f" - done -fi - -# Credentials must come from env, not be hardcoded literals -check "Hardcoded apiKey literal (use process.env)" "apiKey[[:space:]]*:[[:space:]]*['\"][A-Za-z0-9]{6,}['\"]" -check "Hardcoded deliveryToken literal (use process.env)" "deliveryToken[[:space:]]*:[[:space:]]*['\"][A-Za-z0-9]{6,}['\"]" - -finish diff --git a/codex/migration-companion/scripts/04_query_builder.sh b/codex/migration-companion/scripts/04_query_builder.sh deleted file mode 100755 index a3ee90f..0000000 --- a/codex/migration-companion/scripts/04_query_builder.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -# Query builder correctness. (doc §4, §5, gotchas #5,8 + verified .only/.except placement) -. "$(dirname "$0")/_lib.sh" -begin "query-builder" "Query/operator/pagination translation" - -# Contentful query syntax that must be gone -check "Contentful bracket operator (e.g. fields.x[gte])" "\[(gte|lte|gt|lt|ne|nin|in|exists|match|all|near|within)\]" -check "Contentful 'content_type' query param (use stack.contentType(uid))" "content_type[[:space:]]*:" -check "Contentful reference depth 'include: N' (use includeReference)" "include[[:space:]]*:[[:space:]]*[0-9]" -check "Contentful 'order:' sort (use orderByAscending/Descending)" "order[[:space:]]*:[[:space:]]*['\"]" -check "Contentful 'select:' (use .only([...]))" "select[[:space:]]*:[[:space:]]*['\"]" - -# VERIFIED bug: .only()/.except() are NOT on .query() — they live on .entry()/.entries() -check ".only()/.except() chained after .query() (invalid — call before .query())" "\.query\([^)]*\)\.(only|except)\(" - -# Count must be requested explicitly -if [ -n "$(search "\.count\b")" ]; then - require_present ".includeCount() — code reads res.count but never calls includeCount()" "includeCount\(" -fi - -finish diff --git a/codex/migration-companion/scripts/05_references.sh b/codex/migration-companion/scripts/05_references.sh deleted file mode 100755 index ca287c3..0000000 --- a/codex/migration-companion/scripts/05_references.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# References: not auto-resolved + resolve to ARRAYS. (doc §7, gotchas #3,4) -. "$(dirname "$0")/_lib.sh" -begin "references" "Reference resolution & array access" - -# Contentful link residue -check "Contentful Link stub (sys.linkType / linkType: 'Entry')" "(sys\.linkType|linkType[[:space:]]*:[[:space:]]*['\"](Entry|Asset))" -check "Contentful nested ref access (.fields.x.fields.y)" "\.fields\.[A-Za-z0-9_]+\.fields\." - -# If references are requested, surface the field UIDs so each dereference can be checked for [0]/array handling. -refs="$(search "includeReference\(")" -if [ -n "$refs" ]; then - echo " (info) includeReference() call sites — verify each resolved field is accessed as an ARRAY (entry.field?.[0]?.x, or .map(...)):" 1>&2 - # Pull referenced field names and flag object-style dereference (.field. not followed by [ , ?.[ , .map, .length, .forEach) - while IFS= read -r line; do - # crude extraction of the first quoted arg - fld="$(printf '%s' "$line" | grep -oE "includeReference\(['\"][A-Za-z0-9_]+" | head -1 | sed -E "s/.*['\"]//")" - [ -z "$fld" ] && continue - bad="$(search "\.${fld}\.[A-Za-z_]" )" - if [ -n "$bad" ]; then - add_finding "reference '${fld}' may be dereferenced as an object instead of an array (expected ${fld}?.[0]?.x):" - printf '%s\n' "$bad" | sed 's/^/ /' >> "$_TMP" - fi - done <<< "$(printf '%s\n' "$refs" | sort -u)" -fi - -finish diff --git a/codex/migration-companion/scripts/06_richtext.sh b/codex/migration-companion/scripts/06_richtext.sh deleted file mode 100755 index 8789c45..0000000 --- a/codex/migration-companion/scripts/06_richtext.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -# Rich text rendering. (doc §9, gotchas #9,15,16) -. "$(dirname "$0")/_lib.sh" -begin "richtext" "RTE rendering via @contentstack/utils" - -uses_rte="$(search "(jsonToHTML|renderContent|@contentstack/utils|documentTo(HtmlString|ReactComponents)|@contentful/rich-text)" )" -[ -z "$uses_rte" ] && na "no rich-text rendering detected" - -# Residue -check "Contentful rich-text renderer call" "documentTo(HtmlString|ReactComponents)" -check "@contentful/rich-text import" "@contentful/rich-text" - -# VERIFIED bug: Utils.render / jsonToHTML option key is `paths` (plural), not `path` -check "RTE render uses 'path:' (must be 'paths:' plural array)" "(jsonToHTML|[^A-Za-z]render)\([^)]*\bpath[[:space:]]*:" - -# Embeds require includeEmbeddedItems() -if [ -n "$(search "(jsonToHTML|[^A-Za-z]render)\(")" ]; then - require_present ".includeEmbeddedItems() — needed when RTE renders embedded entries/assets" "includeEmbeddedItems\(" -fi - -# utils emits HTML strings -> need an injection sink in component code -if [ -n "$(search "(jsonToHTML|renderContent|[^A-Za-z]render)\(")" ]; then - require_present "HTML injection sink (dangerouslySetInnerHTML / v-html / [innerHTML]) for rendered RTE HTML" "(dangerouslySetInnerHTML|v-html|\[innerHTML\]|innerHTML[[:space:]]*=)" -fi - -finish diff --git a/codex/migration-companion/scripts/07_assets.sh b/codex/migration-companion/scripts/07_assets.sh deleted file mode 100755 index 36b5a6b..0000000 --- a/codex/migration-companion/scripts/07_assets.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# Assets & image transforms. (doc §10, gotchas #11,12,17) -. "$(dirname "$0")/_lib.sh" -begin "assets" "Asset URL & image-transform translation" - -# Contentful asset shape residue -check "asset.fields.file.url (use asset.url)" "\.fields\.file\." -check "protocol-relative URL fix ('https:' + url)" "['\"]https?:['\"][[:space:]]*\+" -check "asset.fields.title/fileName (use asset.title/filename)" "\.fields\.(title|fileName|file)\b" - -# Contentful image API params carried over verbatim -check "Contentful image params (?w=/&h=/fm=/fit=) in URL strings" "[?&](w|h|fm|fit|q|bg|dpr|or)=" - -# Verified caveat: ImageTransform is exported TYPE-ONLY at the package root. -if [ -n "$(search "new[[:space:]]+ImageTransform\(")" ]; then - check "ImageTransform imported from package root (type-only — 'new ImageTransform()' may fail at runtime)" \ - "import[^;]*ImageTransform[^;]*@contentstack/delivery-sdk['\"]" -fi - -finish diff --git a/codex/migration-companion/scripts/08_locales.sh b/codex/migration-companion/scripts/08_locales.sh deleted file mode 100755 index cf2958e..0000000 --- a/codex/migration-companion/scripts/08_locales.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# Locales / localization. (doc §11, gotcha #10) -. "$(dirname "$0")/_lib.sh" -begin "locales" "Locale casing & fallback" - -# Applicability includes stray uppercase locale codes so they are never silently skipped. -uses_locale="$(search "(\.locale\(|locale[[:space:]]*:|setLocale\(|includeFallback\(|['\"][a-z]{2}-[A-Z]{2}['\"])")" -[ -z "$uses_locale" ] && na "no locale usage detected" - -# Contentstack locale codes are lower-cased; flag Contentful-style 'en-US'/'fr-FR' -check "Uppercase locale code (Contentstack uses lower-case, e.g. 'en-us')" "['\"][a-z]{2}-[A-Z]{2}['\"]" -# Multi-locale shape not supported the same way -check "locale: '*' (re-architect to per-locale queries)" "locale[[:space:]]*:[[:space:]]*['\"]\*['\"]" -# Prefer the builder method over a query param -check "Contentful 'locale:' param (use .locale(...))" "[^.]locale[[:space:]]*:[[:space:]]*['\"][a-zA-Z]" - -finish diff --git a/codex/migration-companion/scripts/09_graphql.sh b/codex/migration-companion/scripts/09_graphql.sh deleted file mode 100755 index d9ad191..0000000 --- a/codex/migration-companion/scripts/09_graphql.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -# CONDITIONAL. GraphQL Content API migration. (doc §17) -. "$(dirname "$0")/_lib.sh" -begin "graphql" "GraphQL endpoint/auth/schema migration" - -signal="$(search "(graphql\.contentful\.com|graphql\.contentstack\.com|@apollo/client|urql|graphql-request|gql\`)" "js,jsx,ts,tsx,mjs,cjs,vue,svelte,astro,graphql,gql")" -[ -z "$signal" ] && na "no GraphQL data-access detected" - -# Residue -check "Contentful GraphQL endpoint" "graphql\.contentful\.com" "js,jsx,ts,tsx,mjs,cjs,vue,svelte,astro,graphql,gql,json,env,example" -check "Contentful 'xxxCollection' query naming (Contentstack uses all_)" "[A-Za-z0-9_]+Collection[[:space:]]*\(" "js,jsx,ts,tsx,mjs,cjs,graphql,gql" -check "Authorization: Bearer header (Contentstack uses access_token header)" "Authorization['\"]?[[:space:]]*:[[:space:]]*[\`'\"]?Bearer" - -# Positive: must point at Contentstack GraphQL with the right auth -require_present "Contentstack GraphQL endpoint (graphql.contentstack.com)" "graphql\.contentstack\.com" "js,jsx,ts,tsx,mjs,cjs,vue,svelte,astro,graphql,gql,json,env,example" -require_present "access_token header for Contentstack GraphQL" "access_token" - -finish diff --git a/codex/migration-companion/scripts/10_livepreview.sh b/codex/migration-companion/scripts/10_livepreview.sh deleted file mode 100755 index 7bc4a2f..0000000 --- a/codex/migration-companion/scripts/10_livepreview.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -# CONDITIONAL. Live Preview / draft mode migration. (doc §18) -. "$(dirname "$0")/_lib.sh" -begin "live-preview" "Live Preview / draft mode reimplementation" - -cf_preview="$(search "(@contentful/live-preview|ContentfulLivePreview|useContentfulLiveUpdates|useContentfulInspectorMode|preview\.contentful\.com)")" -cs_preview="$(search "(@contentstack/live-preview-utils|ContentstackLivePreview|livePreviewQuery|live_preview)")" - -if [ -z "$cf_preview" ] && [ -z "$cs_preview" ]; then - na "no Live Preview / draft mode usage detected" -fi - -# Residue: Contentful preview must be gone -check "@contentful/live-preview import" "@contentful/live-preview" -check "ContentfulLivePreview usage" "ContentfulLivePreview" -check "useContentfulLiveUpdates hook" "useContentfulLiveUpdates" -check "useContentfulInspectorMode hook" "useContentfulInspectorMode" -check "Contentful preview host" "preview\.contentful\.com" - -# Positive: Contentstack Live Preview must be wired -require_present "@contentstack/live-preview-utils dependency/usage" "@contentstack/live-preview-utils" -require_present "ContentstackLivePreview.init(...)" "ContentstackLivePreview\.init" -require_present "live_preview config on stack init" "live_preview" -require_present "real-time updates via onEntryChange(...)" "onEntryChange\(" - -# If source had click-to-edit, expect edit tags -if [ -n "$(search "useContentfulInspectorMode")" ]; then - require_present "edit tags (addEditableTags / data-cslp) for click-to-edit parity" "(addEditableTags|data-cslp)" -fi - -# Preview tokens must not be hardcoded in client code -check "Hardcoded preview/management token literal" "(preview_token|management_token)[[:space:]]*:[[:space:]]*['\"][A-Za-z0-9]{6,}['\"]" - -finish diff --git a/codex/migration-companion/scripts/11_build_typecheck.sh b/codex/migration-companion/scripts/11_build_typecheck.sh deleted file mode 100755 index c43bca7..0000000 --- a/codex/migration-companion/scripts/11_build_typecheck.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -# HARD GATE & AUTHORITATIVE. Typecheck / lint / build must pass. (doc §15 step 13) -# Runs in the TARGET dir. Assumes deps are installed (run `npm ci` / `pnpm i` first if needed). -. "$(dirname "$0")/_lib.sh" -begin "build" "Typecheck / lint / build" - -[ -f "$TARGET/package.json" ] || na "no package.json (not a JS/TS app, or wrong target dir)" - -# Pick a package manager -PM="npm" -[ -f "$TARGET/pnpm-lock.yaml" ] && command -v pnpm >/dev/null 2>&1 && PM="pnpm" -[ -f "$TARGET/yarn.lock" ] && command -v yarn >/dev/null 2>&1 && PM="yarn" -[ -f "$TARGET/bun.lockb" ] && command -v bun >/dev/null 2>&1 && PM="bun" - -has_script() { grep -Eq "\"$1\"[[:space:]]*:" "$TARGET/package.json"; } -run() { # run LABEL CMD... - local label="$1"; shift - echo " --- $label: $* ---" >> "$_TMP" - if ( cd "$TARGET" && "$@" ) >>"$_TMP" 2>&1; then - echo " ✓ $label passed" ; return 0 - else - add_finding "$label FAILED (see output below)"; return 1 - fi -} - -ran_any=0 - -# Typecheck (preferred signal) -if [ -f "$TARGET/tsconfig.json" ]; then - ran_any=1 - if has_script "typecheck"; then run "typecheck" $PM run typecheck - elif command -v npx >/dev/null 2>&1; then run "tsc --noEmit" npx -y tsc --noEmit - fi -fi - -# Lint (non-fatal signal, but reported) -if has_script "lint"; then ran_any=1; run "lint" $PM run lint || true; fi - -# Build (authoritative) -if has_script "build"; then ran_any=1; run "build" $PM run build; fi - -[ "$ran_any" -eq 0 ] && na "no tsconfig/typecheck/lint/build script found to run" - -# Emit captured command output for triage -echo "### [$EVAL_NAME] $EVAL_TITLE" -if [ "$FINDINGS" -eq 0 ]; then - echo "STATUS: PASS (pkg manager: $PM)" - echo "SUMMARY_JSON: {\"eval\":\"build\",\"status\":\"PASS\",\"findings\":0}" - rm -f "$_TMP"; exit 0 -fi -echo "STATUS: FAIL (pkg manager: $PM) — $FINDINGS step(s) failed" -cat "$_TMP" -echo "SUMMARY_JSON: {\"eval\":\"build\",\"status\":\"FAIL\",\"findings\":$FINDINGS}" -rm -f "$_TMP"; exit 1 diff --git a/codex/migration-companion/scripts/12_secrets.sh b/codex/migration-companion/scripts/12_secrets.sh deleted file mode 100755 index 401ca50..0000000 --- a/codex/migration-companion/scripts/12_secrets.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# HARD GATE. No hardcoded credentials; tokens via env; example env updated. (doc §15 step 2) -. "$(dirname "$0")/_lib.sh" -begin "secrets" "No hardcoded credentials / env hygiene" - -# Hardcoded Contentstack credential literals in source -check "Hardcoded delivery/preview/management token literal" \ - "(deliveryToken|preview_token|management_token|access_token)[[:space:]]*[:=][[:space:]]*['\"][A-Za-z0-9_-]{8,}['\"]" -check "Hardcoded apiKey literal" "apiKey[[:space:]]*[:=][[:space:]]*['\"][A-Za-z0-9]{8,}['\"]" -# Contentstack token/key shapes appearing as literals -check "Contentstack-shaped token literal (cs.../blt...) in source" "['\"](cs[a-f0-9]{12,}|blt[a-z0-9]{12,})['\"]" - -# A committed .env with real values is a leak risk -if [ -f "$TARGET/.env" ]; then - if [ -f "$TARGET/.gitignore" ] && grep -Eq '(^|/)\.env($|[^.])' "$TARGET/.gitignore"; then :; else - add_finding ".env present but not clearly git-ignored — verify it is not committed" - fi -fi - -# Example env should advertise the new Contentstack vars -if ls "$TARGET"/.env.example "$TARGET"/.env.sample "$TARGET"/.env.local.example >/dev/null 2>&1; then - if ! grep -Eqr 'CS_(API_KEY|DELIVERY_TOKEN|ENVIRONMENT)|CONTENTSTACK_' "$TARGET"/.env.* 2>/dev/null; then - add_finding "example env file exists but lists no Contentstack (CS_*/CONTENTSTACK_*) variables" - fi -fi - -finish diff --git a/codex/migration-companion/scripts/13_todos_report.sh b/codex/migration-companion/scripts/13_todos_report.sh deleted file mode 100755 index ca7c18e..0000000 --- a/codex/migration-companion/scripts/13_todos_report.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -# INFORMATIONAL. Surface migration TODOs and guessed UIDs for mandatory human review. -. "$(dirname "$0")/_lib.sh" -begin "todos" "Migration TODOs & guessed-UID review list" - -check "TODO(migration) markers" "TODO\(migration\)" -check "Generic migration FIXMEs" "FIXME|XXX|@migration" -check "Guessed/placeholder UIDs" "(GUESS|PLACEHOLDER|REPLACE_ME||your_[a-z_]*_uid)" - -report diff --git a/codex/migration-companion/scripts/README.md b/codex/migration-companion/scripts/README.md deleted file mode 100644 index ece6a48..0000000 --- a/codex/migration-companion/scripts/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# Migration evals — Contentful → Contentstack - -Independent, parallel-runnable checks that confirm a migration was done correctly. Each script -targets one class of mistake from the migration mapping (`reference/CONTENTFUL_TO_CONTENTSTACK_MIGRATION_CONTEXT.md`) -and is **runnable on its own**, so an AI can fan them out (one agent per eval) or use the runner. - -## Run - -```bash -# all evals, in parallel, against the migrated app -bash run-all.sh /path/to/migrated-app - -# a subset (by number prefix) -bash run-all.sh /path/to/app 01 02 04 06 - -# skip the slow build eval (e.g. before deps are installed) -SKIP_BUILD=1 bash run-all.sh /path/to/app - -# one eval directly -bash 02_field_access.sh /path/to/app -``` - -Install deps in the target first (`npm ci` / `pnpm i`) so eval 11 (build/typecheck) is meaningful. -Uses `ripgrep` if present, else falls back to `grep`. - -## The evals - -| # | eval | Gate | Catches (doc ref) | -|---|------|------|-------| -| 01 | `residue` | **HARD** | Any leftover Contentful import/host/dep; missing Contentstack dep (§1, gotcha 1) | -| 02 | `field-access` | **HARD** | `.fields.` / `.sys.*` / `.items` / `.total` not flattened (§6, gotchas 1-2,7) | -| 03 | `sdk-init` | **HARD** | `stack()` missing required `environment`/`apiKey`/`deliveryToken`; old keys; hardcoded creds (§3, gotcha 6) | -| 04 | `query-builder` | review | Contentful `[gte]`/`content_type:`/`include:N`/`order:`/`select:`; `.only`/`.except` after `.query()` (§4-5, gotchas 5,8) | -| 05 | `references` | review | Link stubs; references dereferenced as objects not arrays (§7, gotchas 3-4) | -| 06 | `richtext` | review | `@contentful/rich-text`; `path:` vs `paths:`; missing `includeEmbeddedItems()`/HTML sink (§9, gotchas 9,15,16) | -| 07 | `assets` | review | `fields.file.url`; protocol-relative fix; Contentful image params; `ImageTransform` root import (§10, gotchas 11,12,17) | -| 08 | `locales` | review | Uppercase locale codes; `locale:'*'`; query-param locale (§11, gotcha 10) | -| 09 | `graphql` | review* | Contentful GraphQL endpoint/auth/`xxxCollection`; missing Contentstack endpoint/`access_token` (§17) | -| 10 | `live-preview` | review* | Leftover `@contentful/live-preview`; missing `live_preview`/`onEntryChange`/edit tags (§18) | -| 11 | `build` | **HARD** | Typecheck / lint / build failures (authoritative) (§15.13) | -| 12 | `secrets` | **HARD** | Hardcoded tokens/keys; un-ignored `.env`; example env not updated (§15.2) | -| 13 | `todos` | report | Lists `TODO(migration)` and guessed UIDs for mandatory human review | - -\* evals 09/10 return **N/A** (exit 3) when the app doesn't use that approach. - -## Session logger (`log.sh`) — verbose audit trail - -`log.sh` is **not** a pass/fail eval (the runner ignores it). It is an append-only audit log of the -whole migration — user inputs, AI actions & communications, decisions, eval results, commands, and -**every exception** — written to `/.migration/` as both `session.log` (human-readable) and -`session.jsonl` (machine-readable), with full per-command output under `commands/`. - -```bash -L=/evals/log.sh - -bash "$L" user-input "User asked: migrate Next.js app, GraphQL + live preview" -bash "$L" decision "Detected TS/Next.js/GraphQL(urql)+contentful live-preview" -bash "$L" ai-action "Rewrote lib/cms.ts queries to all_blog_post" -bash "$L" communication "Asked user to confirm field-UID map" -bash "$L" exception "coverImage UID unknown -> guessed cover_image (TODO)" - -# Run a command through the logger: captures stdout+stderr, preserves exit code, -# and auto-records a FAILED command as an exception: -bash "$L" run "install" -- npm ci -bash "$L" run "typecheck" -- npx tsc --noEmit - -bash "$L" summary # counts by type + exception list + recent entries -bash "$L" path # print the log directory -``` - -`run-all.sh` automatically records its verdict to this log when present. Recommended type values: -`user-input | ai-action | communication | decision | exception | command | eval | note`. - -## Exit codes - -`0` PASS · `1` FAIL (findings) · `2` ERROR (eval crashed) · `3` N/A (approach not used). -`run-all.sh` verdict: `0` PASS, `1` REVIEW (non-gate findings), `2` BLOCK (a hard gate failed). - -## How an AI should use these - -1. After migrating, run `run-all.sh ` (or spawn one agent per `NN_*.sh` for max parallelism). -2. **Hard-gate FAIL/ERROR (01,02,03,11,12) ⇒ the migration is not done.** Fix and re-run. -3. For review evals, **triage every finding** — static greps flag *suspects*, not proven bugs. - Open each `file:line`, decide true-positive vs false-positive, fix the real ones, and state why - the rest are safe. Do not dismiss findings silently. -4. The build eval is authoritative: a green typecheck/build is necessary but **not sufficient** — - it can't catch reference-array bugs, wrong field UIDs, or RTE output. Still smoke-test live - queries against the real Contentstack stack (doc §15.13). -5. Report results in the migration summary: per-eval status, triaged findings, and remaining TODOs. - -These checks are **necessary, not sufficient**. They guard against the known, mechanical mistakes; -they do not prove semantic correctness against your content model. diff --git a/codex/migration-companion/scripts/_lib.sh b/codex/migration-companion/scripts/_lib.sh deleted file mode 100755 index 4c9edc8..0000000 --- a/codex/migration-companion/scripts/_lib.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env bash -# Shared helpers for Contentful -> Contentstack migration evals. -# Each eval script sources this, then calls: begin / check / add_finding / require_present / finish | na -# -# Contract / exit codes (consumed by run-all.sh and by AI orchestrators): -# PASS -> exit 0 (no issues found) -# FAIL -> exit 1 (findings to review; for hard-gate evals this BLOCKS) -# ERROR -> exit 2 (the eval itself failed to run) -# N/A -> exit 3 (this approach is not used by the app; skip) -# REPORT -> exit 0 (informational only, e.g. TODO listing) -# -# Findings are signals for a human/AI to triage, not proof of a bug. Static greps -# can produce false positives — every FAIL must be reasoned about. The build and -# secrets evals are authoritative. - -set -uo pipefail - -TARGET="${TARGET:-${1:-.}}" -TARGET="${TARGET%/}" - -# Source-code file extensions to scan (language-agnostic across JS/TS frameworks). -CODE_EXT='js,jsx,ts,tsx,mjs,cjs,vue,svelte,astro' -EXCLUDE_DIRS='node_modules dist build .next .nuxt .svelte-kit out coverage .git .turbo .cache .vercel .output public/build' - -if command -v rg >/dev/null 2>&1; then HAVE_RG=1; else HAVE_RG=0; fi - -# search REGEX [GLOBS] -> prints "file:line:match" -search() { - local regex="$1"; local globs="${2:-$CODE_EXT}" - if [ "$HAVE_RG" -eq 1 ]; then - local exargs=(); local d - for d in $EXCLUDE_DIRS; do exargs+=(-g "!$d/**"); done - rg --no-heading --line-number --color never "${exargs[@]}" -g "*.{$globs}" -e "$regex" "$TARGET" 2>/dev/null - else - local inc=() exc=() e d - IFS=',' read -ra _exts <<< "$globs" - for e in "${_exts[@]}"; do inc+=(--include="*.$e"); done - for d in $EXCLUDE_DIRS; do exc+=(--exclude-dir="$d"); done - grep -rEn "${inc[@]}" "${exc[@]}" -e "$regex" "$TARGET" 2>/dev/null - fi -} - -# files_with REGEX [GLOBS] -> unique file list -files_with() { search "$1" "${2:-$CODE_EXT}" | cut -d: -f1 | sort -u; } - -# ---- reporting state ---- -EVAL_NAME=""; EVAL_TITLE=""; FINDINGS=0; _TMP="" -begin() { - EVAL_NAME="$1"; EVAL_TITLE="$2"; FINDINGS=0 - _TMP="$(mktemp)" || { echo "ERROR: mktemp failed"; exit 2; } -} - -# add_finding "message" — record one issue -add_finding() { printf ' ▸ %s\n' "$1" >> "$_TMP"; FINDINGS=$((FINDINGS+1)); } - -# check "description" REGEX [GLOBS] — flag every match of a pattern that should NOT exist -check() { - local desc="$1" regex="$2" globs="${3:-$CODE_EXT}" out n - out="$(search "$regex" "$globs")" - if [ -n "$out" ]; then - n="$(printf '%s\n' "$out" | grep -c .)" - { printf ' ▸ %s [%s hit(s)]\n' "$desc" "$n"; printf '%s\n' "$out" | sed 's/^/ /'; } >> "$_TMP" - FINDINGS=$((FINDINGS+n)) - fi -} - -# require_present "description" REGEX [GLOBS] — flag if a REQUIRED pattern is MISSING -require_present() { - local desc="$1" regex="$2" globs="${3:-$CODE_EXT}" - if [ -z "$(search "$regex" "$globs")" ]; then - add_finding "MISSING (expected to be present): $desc" - fi -} - -# na "reason" — mark eval not-applicable and exit -na() { - echo "### [$EVAL_NAME] $EVAL_TITLE" - echo "STATUS: N/A — $1" - echo "SUMMARY_JSON: {\"eval\":\"$EVAL_NAME\",\"status\":\"NA\",\"findings\":0}" - [ -n "$_TMP" ] && rm -f "$_TMP" - exit 3 -} - -# finish — print result and exit with PASS/FAIL code -finish() { - echo "### [$EVAL_NAME] $EVAL_TITLE" - if [ "$FINDINGS" -eq 0 ]; then - echo "STATUS: PASS" - echo "SUMMARY_JSON: {\"eval\":\"$EVAL_NAME\",\"status\":\"PASS\",\"findings\":0}" - rm -f "$_TMP"; exit 0 - fi - echo "STATUS: FAIL — $FINDINGS finding(s) to triage" - cat "$_TMP" - echo "SUMMARY_JSON: {\"eval\":\"$EVAL_NAME\",\"status\":\"FAIL\",\"findings\":$FINDINGS}" - rm -f "$_TMP"; exit 1 -} - -# report — informational eval; always exits 0 -report() { - echo "### [$EVAL_NAME] $EVAL_TITLE" - if [ "$FINDINGS" -eq 0 ]; then - echo "STATUS: REPORT — nothing to list" - else - echo "STATUS: REPORT — $FINDINGS item(s) for human review" - cat "$_TMP" - fi - echo "SUMMARY_JSON: {\"eval\":\"$EVAL_NAME\",\"status\":\"REPORT\",\"findings\":$FINDINGS}" - rm -f "$_TMP"; exit 0 -} diff --git a/codex/migration-companion/scripts/check_prereqs.py b/codex/migration-companion/scripts/check_prereqs.py deleted file mode 100644 index 17589e6..0000000 --- a/codex/migration-companion/scripts/check_prereqs.py +++ /dev/null @@ -1,307 +0,0 @@ -#!/usr/bin/env python3 -""" -check_prereqs.py — silent prerequisite evaluator for the CF→CS migration. - -Runs all checks in one pass, auto-installs missing CLIs (csdx, contentful), -and emits a single JSON summary to stdout. - -Exit codes: - 0 — all hard requirements met (some items may still need auth, flagged in JSON) - 1 — Node.js missing or too old (migration cannot proceed at all) -""" -import glob -import json -import os -import pathlib -import re -import subprocess -import sys -import urllib.request - -# --------------------------------------------------------------------------- -# Environment -# --------------------------------------------------------------------------- -# -# All CLI subprocesses (node, npm, csdx, contentful) run under CLI_ENV. It -# starts as the inherited environment, but once we resolve the best available -# Node (see "Node.js" below) we prepend that Node's bin dir to PATH so every -# downstream tool uses it — even when an older /usr/local/bin/node would -# otherwise win in a non-interactive shell. -CLI_ENV = dict(os.environ) - -# --------------------------------------------------------------------------- -# Helpers -# --------------------------------------------------------------------------- - -def run(cmd, env=None): - try: - r = subprocess.run( - cmd, - capture_output=True, - text=True, - env=env if env is not None else CLI_ENV, - ) - return r.returncode, r.stdout.strip(), r.stderr.strip() - except FileNotFoundError: - return 1, "", f"{cmd[0]}: command not found" - - -def npm_install(pkg): - """Silently install a global npm package. Errors surfaced via the JSON result.""" - subprocess.run( - ["npm", "install", "-g", pkg], - capture_output=True, - env=CLI_ENV, - ) - - -def extract_version(s): - """Pull the first semver-looking token out of a `--version` output.""" - m = re.search(r"(\d+\.\d+\.\d+[^\s]*)", s or "") - return m.group(1) if m else None - - -def npm_latest(pkg): - """Latest published version of a package on npm (None if npm is unreachable).""" - rc, ver, _ = run(["npm", "view", pkg, "version"]) - return ver.strip() if rc == 0 and ver.strip() else None - - -def node_version_tuple(node_bin): - """(major, minor, patch) version tuple for a node binary, or None if it won't run.""" - rc, ver, _ = run([node_bin, "--version"]) - if rc != 0: - return None, None - m = re.match(r"v?(\d+)\.(\d+)\.(\d+)", ver) - if not m: - return None, ver - return tuple(int(x) for x in m.groups()), ver - - -def discover_node_bins(): - """Every node binary we can find: PATH entries, nvm-installed versions, and - common system/homebrew locations. De-duplicated by real path.""" - candidates = [] - - # All `node` on PATH (handles shims and multiple managers). - rc, paths, _ = run(["which", "-a", "node"]) - if rc == 0: - candidates += [p for p in paths.splitlines() if p.strip()] - - # Every nvm-installed version (the default shell may not expose these). - nvm_dir = os.environ.get("NVM_DIR", os.path.expanduser("~/.nvm")) - candidates += glob.glob(os.path.join(nvm_dir, "versions", "node", "*", "bin", "node")) - - # Common fixed locations. - candidates += [ - "/opt/homebrew/bin/node", - "/usr/local/bin/node", - "/usr/bin/node", - ] - - seen, uniq = set(), [] - for c in candidates: - if not c or not os.path.exists(c): - continue - rp = os.path.realpath(c) - if rp in seen: - continue - seen.add(rp) - uniq.append(c) - return uniq - - -def pick_best_node(): - """Highest-version node binary available. Returns (version_tuple, version_str, - bin_path) or None if no node is found at all.""" - best = None - for b in discover_node_bins(): - tup, ver = node_version_tuple(b) - if tup is None: - continue - if best is None or tup > best[0]: - best = (tup, ver, b) - return best - - -def ensure_latest_cli(cmd_name, pkg): - """Ensure a global CLI is installed AND on the latest npm version. - - Installs when missing, upgrades when an older version is present. Returns a - dict suitable for the JSON summary: {ok, version, installed, latest, updated}. - """ - rc, raw, _ = run([cmd_name, "--version"]) - installed = extract_version(raw) if rc == 0 else None - latest = npm_latest(pkg) - updated = False - - if rc != 0: - # Not installed — install latest. - print(f"Installing {pkg} …", file=sys.stderr) - npm_install(f"{pkg}@latest") - rc, raw, _ = run([cmd_name, "--version"]) - installed = extract_version(raw) if rc == 0 else None - updated = rc == 0 - elif latest and installed and installed != latest: - # Installed but outdated — upgrade to latest. - print(f"Updating {pkg} {installed} → {latest} …", file=sys.stderr) - npm_install(f"{pkg}@latest") - rc, raw, _ = run([cmd_name, "--version"]) - installed = extract_version(raw) if rc == 0 else None - updated = rc == 0 - # else: latest is unknown (offline) or already current — leave as-is. - - return { - "ok": rc == 0, - "version": raw if rc == 0 else None, - "installed": installed, - "latest": latest, - "updated": updated, - } - - -# --------------------------------------------------------------------------- -# Checks -# --------------------------------------------------------------------------- - -out = {} - -# ── Node.js ───────────────────────────────────────────────────────────────── -# Pick the highest node available across PATH + nvm, not just whatever the -# non-interactive shell resolves first (which may be an old /usr/local/bin/node). -best = pick_best_node() -if best is None: - out["node"] = {"ok": False, "error": "not_installed"} - print(json.dumps(out, indent=2)) - sys.exit(1) - -node_tuple, ver, node_bin = best -major = node_tuple[0] -node_dir = os.path.dirname(node_bin) -out["node"] = { - "ok": major >= 20, - "version": ver, - "major": major, - "path": node_bin, - "bin_dir": node_dir, -} - -if major < 20: - # Hard blocker — emit result and exit 1 so the step file can surface the error. - # `path`/`version` reflect the BEST node we found, so the message is accurate. - print(json.dumps(out, indent=2)) - sys.exit(1) - -# Pin every downstream CLI (npm, csdx, contentful, node -e) to this node's bin -# dir so they don't fall back to an older node earlier on PATH. -CLI_ENV["PATH"] = node_dir + os.pathsep + CLI_ENV.get("PATH", "") - -# ── Contentstack CLI (csdx) — install if missing, upgrade if outdated ───────── -out["csdx"] = ensure_latest_cli("csdx", "@contentstack/cli") - -# ── Contentstack region ────────────────────────────────────────────────────── -rc, region_raw, _ = run(["csdx", "config:get:region"]) -region = region_raw.strip() if rc == 0 else "UNKNOWN" -out["cs_region"] = {"region": region} - -# ── Contentstack login + org UID ───────────────────────────────────────────── -rc, whoami, _ = run(["csdx", "auth:whoami"]) -logged_in_cs = rc == 0 and whoami and "No user" not in whoami and "not logged" not in whoami.lower() - -if logged_in_cs: - # Ensure cli-utilities is available, then read the oauth org UID - npm_install("@contentstack/cli-utilities") - rc2, npm_root, _ = run(["npm", "root", "-g"]) - node_env = {**CLI_ENV, "NODE_PATH": npm_root.strip()} - uid_script = ( - "const {configHandler}=require('@contentstack/cli-utilities');" - "const t=configHandler.get('authorisationType');" - "const o=configHandler.get('oauthOrgUid');" - "const e=configHandler.get('email')||'';" - "if(t!=='OAUTH'||!o){process.exit(1);}" - "console.log(JSON.stringify({orgUid:o,email:e}));" - ) - rc3, uid_out, _ = run([node_bin, "-e", uid_script], env=node_env) - if rc3 == 0: - try: - uid_data = json.loads(uid_out) - out["cs_login"] = { - "ok": True, - "email": uid_data.get("email") or whoami, - "org_uid": uid_data.get("orgUid"), - } - except Exception: - out["cs_login"] = {"ok": True, "email": whoami, "org_uid": None} - else: - # Logged in but not via OAuth (or UID missing) — flag for re-auth - out["cs_login"] = { - "ok": True, - "email": whoami, - "org_uid": None, - "needs_oauth_reauth": True, - } -else: - out["cs_login"] = {"ok": False, "needs_login": True} - -# ── Contentful CLI — install if missing, upgrade if outdated ────────────────── -out["contentful_cli"] = ensure_latest_cli("contentful", "contentful-cli") - -# ── Contentful login + spaces ──────────────────────────────────────────────── -rc, spaces_raw, spaces_err = run(["contentful", "space", "list"]) -auth_error = "You have to be logged in" in spaces_raw or "You have to be logged in" in spaces_err -logged_in_cf = rc == 0 and not auth_error - -if logged_in_cf: - identity = {"ok": True} - - # Resolve account identity from the stored management token - for p in ["~/.contentfulrc.json", "~/.config/contentful/config.json"]: - f = pathlib.Path(p).expanduser() - if not f.exists(): - continue - try: - d = json.loads(f.read_text()) - tok = ( - d.get("managementToken") - or d.get("cmaToken") - or d.get("management_token") - ) - if not tok: - continue - req = urllib.request.Request( - "https://api.contentful.com/users/me", - headers={ - "Authorization": f"Bearer {tok}", - "Content-Type": "application/json", - }, - ) - with urllib.request.urlopen(req, timeout=8) as resp: - user = json.loads(resp.read()) - identity["name"] = ( - f"{user.get('firstName', '')} {user.get('lastName', '')}".strip() - ) - identity["email"] = user.get("email", "") - break - except Exception: - pass - - out["contentful_login"] = identity - - # Parse spaces from the table output - spaces = [] - for line in spaces_raw.split("\n"): - if "│" in line: - cols = [c.strip() for c in re.split(r"│", line) if c.strip()] - if len(cols) >= 2 and cols[0] not in ("Space name", ""): - name = re.sub(r"\s*\[.*?\]", "", cols[0]).strip() - sid = cols[1] - if name and sid: - spaces.append({"name": name, "id": sid}) - out["contentful_spaces"] = spaces -else: - out["contentful_login"] = {"ok": False, "needs_login": True} - out["contentful_spaces"] = [] - -# ── Done ───────────────────────────────────────────────────────────────────── -print(json.dumps(out, indent=2)) -sys.exit(0) diff --git a/codex/migration-companion/scripts/log.sh b/codex/migration-companion/scripts/log.sh deleted file mode 100755 index 9232fd3..0000000 --- a/codex/migration-companion/scripts/log.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash -# Verbose session logger for the Contentful -> Contentstack migration. -# -# NOT a pass/fail eval — an append-only AUDIT TRAIL of everything the migration touched: -# user inputs, AI actions & communications, decisions, eval results, commands, and exceptions. -# Writes both a human-readable log and a machine-readable JSONL stream, plus per-command output. -# -# Usage: -# log.sh # append one entry -# log.sh run "