diff --git a/.claude/skills/create-alpha-packages/SKILL.md b/.claude/skills/create-alpha-packages/SKILL.md new file mode 100644 index 00000000..2b72accc --- /dev/null +++ b/.claude/skills/create-alpha-packages/SKILL.md @@ -0,0 +1,133 @@ +--- +name: create-alpha-packages +description: Cut an alpha release of this monorepo by appending `-alpha.1` to the `version` field in every workspace package.json (root + apps/* + packages/*), removing `package-lock.json`, and running `npm run reinstall` from the repo root. Triggered by "create alpha packages", "bump alpha", or `/create-alpha-packages`. +--- + +# create-alpha-packages + +Bumps the `version` field in every workspace `package.json` from the current shared release like `6.1.84` to `6.1.84-alpha.1`, then refreshes the lockfile and `node_modules`. Mirrors the historical pattern from commits like `1727748c` ("chore: bump monorepo packages to 6.1.79-alpha.1"). + +This is **not** a dependency bump. For bumping external `@uniformdev/*` deps, use the separate `update-uniform-packages` skill. + +## When to invoke + +- "create alpha packages" +- "bump alpha" / "alpha bump" / "alpha release" +- `/create-alpha-packages` + +## Conventions enforced + +- All workspace `version` fields stay in **lockstep** (enforced by `manypkg check` via the root `workspace:check` script). If drift is detected, stop and surface it — do not silently fix. +- Postfix is **always `-alpha.1`**. Never increment to `-alpha.2`. If you need a new alpha after one was already cut, the base version itself should be bumped first (separate operation). +- **All** workspaces are touched, including private ones under the `@repo/*` scope. + +## Workspace package.json files (reference snapshot — discover at runtime) + +At authoring time the workspaces were: + +``` +package.json (root, name: csk-packages) +apps/csk/package.json (@uniformdev/component-starter-kit) +apps/csk-marketing-site/package.json (@uniformdev/csk-marketing-site) +apps/csk-storybook/package.json (@uniformdev/csk-storybook) +packages/csk-cli/package.json (@uniformdev/csk-cli) +packages/csk-components/package.json (@uniformdev/csk-components) +packages/csk-recipes/package.json (@uniformdev/csk-recipes) +packages/design-extensions-tools/package.json (@uniformdev/design-extensions-tools) +packages/eslint-config/package.json (@repo/eslint-config) +packages/internal-scripts/package.json (@repo/internal-scripts) +packages/typescript-config/package.json (@repo/typescript-config) +``` + +Always re-discover from the filesystem; do not hard-code. + +## Steps + +### 1. Read current version from root + every workspace + +```bash +node -e "const fs=require('fs'),p=require('path');const files=['package.json'];for(const r of ['apps','packages']){if(!fs.existsSync(r))continue;for(const d of fs.readdirSync(r)){const f=p.join(r,d,'package.json');if(fs.existsSync(f))files.push(f);}}for(const f of files){const j=JSON.parse(fs.readFileSync(f,'utf8'));console.log(j.version+'\\t'+f);}" +``` + +### 2. Verify lockstep + +Every printed line must share the same `version`. If any differs, **stop** and report: + +``` +Workspace version drift detected: + 6.1.84 package.json + 6.1.84 apps/csk/package.json + 6.1.83 packages/csk-components/package.json <-- mismatch +Run `npm run workspace:fix` (manypkg fix) to resolve drift before re-running this skill. +``` + +Do not proceed. + +### 3. Compute target version + +Let `current` be the root's current `version`. Strip any prerelease tag (everything from the first `-` onward), then append `-alpha.1`. + +| Current | Target | +|---|---| +| `6.1.84` | `6.1.84-alpha.1` | +| `6.1.84-alpha.1` | `6.1.84-alpha.1` (no-op, files won't change) | +| `6.1.84-rc.2` | `6.1.84-alpha.1` | + +If `current === target` for every file, tell the user "Already at — nothing to do" and stop (do not delete the lockfile or reinstall). + +### 4. Edit each package.json + +For every file from step 1, use the `Edit` tool to replace exactly: + +- `old_string`: `"version": "",` +- `new_string`: `"version": "",` + +The top-level `version` line is unique near the top of each `package.json` (lines 2–3), so the match is unambiguous. Do **not** use `replace_all`. Do **not** touch `dependencies`, `devDependencies`, or `peerDependencies`, even if a workspace name appears there. + +### 5. Print summary + +``` +Bumped 11 files: 6.1.84 → 6.1.84-alpha.1 + package.json + apps/csk/package.json + apps/csk-marketing-site/package.json + apps/csk-storybook/package.json + packages/csk-cli/package.json + packages/csk-components/package.json + packages/csk-recipes/package.json + packages/design-extensions-tools/package.json + packages/eslint-config/package.json + packages/internal-scripts/package.json + packages/typescript-config/package.json +``` + +### 6. Remove the lockfile + +```bash +rm -f package-lock.json +``` + +The root `reinstall` script does not delete the lockfile itself; we remove it explicitly so npm re-resolves from scratch. + +### 7. Run reinstall from the repo root + +```bash +npm run reinstall +``` + +This is the existing root script — it wipes all `node_modules` plus build artifacts (`.turbo`, `.next`, `dist`, `storybook-static`) and runs `npm install`. Stream output; do not background. Expect a couple of minutes. + +### 8. Report final state + +One-line confirmation: "Alpha cut: 6.1.84 → 6.1.84-alpha.1. Lockfile regenerated. Reinstall OK." Surface any reinstall failure verbatim and stop — do not attempt to "fix" it. + +## Do NOT + +- Do not increment past `-alpha.1` (use `-alpha.1` every time; the base version is what differs across runs). +- Do not modify any field other than the top-level `version` in each package.json. +- Do not touch `dependencies` / `devDependencies` / `peerDependencies`, even when a workspace name like `@uniformdev/csk-components` appears there with a `workspace:*` or version range. +- Do not "fix" workspace version drift silently — surface it and let the user resolve via `npm run workspace:fix`. +- Do not edit `package-lock.json` by hand; let `npm install` regenerate it. +- Do not commit, tag, push, or open a PR. +- Do not run `npm run build`, `lint`, or tests after reinstall unless asked. +- Do not switch package managers or edit `packageManager`. diff --git a/.cursor/rules/create-alpha-packages.mdc b/.cursor/rules/create-alpha-packages.mdc new file mode 100644 index 00000000..dfc0e0ff --- /dev/null +++ b/.cursor/rules/create-alpha-packages.mdc @@ -0,0 +1,10 @@ +--- +description: Cut an alpha release of this monorepo by appending `-alpha.1` to the `version` field in every workspace package.json (root + apps/* + packages/*), removing `package-lock.json`, and running `npm run reinstall` from the repo root. Triggered by phrases like "create alpha packages", "bump alpha", or "alpha release". +alwaysApply: false +--- + +When the user asks to "create alpha packages", "bump alpha", "alpha release", or runs `/create-alpha-packages`, follow the canonical workflow: + +@.claude/skills/create-alpha-packages/SKILL.md + +That file is the source of truth. Do not deviate; do not improvise the steps. If anything is unclear, ask the user. diff --git a/.cursor/rules/uniform-concepts.mdc b/.cursor/rules/uniform-concepts.mdc new file mode 100644 index 00000000..99cb85fe --- /dev/null +++ b/.cursor/rules/uniform-concepts.mdc @@ -0,0 +1,11 @@ +--- +description: Uniform CMS core concepts — compositions, components, slots, patterns, naming, parameter/field types. Reference loaded when editing Uniform-aware code in apps/ or packages/csk-*. +globs: apps/**/*.{ts,tsx}, packages/csk-components/**, packages/csk-recipes/**, packages/design-extensions-tools/** +alwaysApply: false +--- + +When working in Uniform-consuming code (component definitions, registrations, composition rendering, patterns, slots), follow the canonical reference: + +@docs/uniform/concepts.md + +That file is the source of truth. Do not improvise Uniform modeling rules; consult it for slot allowability, pattern semantics, naming conventions, parameter types, and what MCP/AI can and cannot do. diff --git a/.cursor/rules/uniform-sdk.mdc b/.cursor/rules/uniform-sdk.mdc new file mode 100644 index 00000000..1454e12e --- /dev/null +++ b/.cursor/rules/uniform-sdk.mdc @@ -0,0 +1,11 @@ +--- +description: Uniform SDK / CLI / MCP usage — env vars, uniform.config.ts, sync push/pull, MCP-vs-CLI rules, App Router catch-all route wiring. Reference loaded when editing Uniform SDK setup, content sync, or routing. +globs: apps/*/uniform.config.ts, apps/*/content/**, apps/*/.env*, apps/*/src/app/** +alwaysApply: false +--- + +When wiring or maintaining the Uniform SDK in this repo (CLI scripts, env vars, catch-all routes, content sync, MCP usage), follow the canonical reference: + +@docs/uniform/sdk.md + +Critical rules from that doc: never hand-edit files under `apps/*/content/`; never use `uniform:push` to write entities (use Uniform MCP or the web app); always run `npm run uniform:pull` in the affected app after MCP changes. diff --git a/.cursor/rules/update-uniform-packages.mdc b/.cursor/rules/update-uniform-packages.mdc new file mode 100644 index 00000000..4cd57767 --- /dev/null +++ b/.cursor/rules/update-uniform-packages.mdc @@ -0,0 +1,10 @@ +--- +description: Bump every external @uniformdev/* dependency in this monorepo to its latest npm version, leaving the local @uniformdev/* workspace packages untouched, then wipe the lockfile and run `npm run reinstall`. Triggered by phrases like "update uniform packages" or "bump uniform". +alwaysApply: false +--- + +When the user asks to "update uniform packages", "bump uniform", or runs `/update-uniform-packages`, follow the canonical workflow: + +@.claude/skills/update-uniform-packages/SKILL.md + +That file is the source of truth. Do not deviate; do not improvise the steps. If anything is unclear, ask the user. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..46153ea1 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,71 @@ +# AGENTS.md + +Guidance for AI coding agents working in this repository. Plain markdown, no enforced schema. Deep reference material lives in [`docs/uniform/`](docs/uniform/) and is loaded selectively (Cursor via `.cursor/rules/*.mdc` globs; other agents follow the links below when relevant). This file stays slim and always-applicable. + +## Project overview + +This is the **Uniform Component Starter Kit (CSK)** monorepo — an npm workspaces project with workspaces under [`apps/*`](apps/) and [`packages/*`](packages/). All workspaces keep their `version` field in lockstep (enforced by `manypkg check`). External `@uniformdev/*` packages come from npm; several `@uniformdev/*` packages are produced *by* this repo (workspace packages) and must not be confused with the npm-published ones. + +Package manager: **npm 11.x**. Node: `^18.18.0 || ^19.8.0 || >= 20.0.0`. Stack: **Next.js App Router**. + +## Common scripts (run from repo root) + +| Command | What it does | +|---|---| +| `npm run build` | Full build via Turbo across all workspaces. **Use this to verify changes** — workspace-level checks can miss runtime errors that the full root build catches. | +| `npm run lint` / `npm run lint:fix` | Turbo lint across all workspaces | +| `npm run format` | Turbo format | +| `npm run workspace:check` | `manypkg check` — verifies workspace versions are in lockstep | +| `npm run workspace:fix` | `manypkg fix` — resolves workspace version drift | +| `npm run reinstall` | Wipe `node_modules` + build artifacts everywhere, then `npm install` | + +## Workflows (project-level skills) + +Deterministic, repeatable chores — follow the canonical procedure in the linked file, don't improvise: + +- **Update Uniform packages** → bump every external `@uniformdev/*` dependency to its latest npm version (skipping the local workspace `@uniformdev/*` packages), wipe the lockfile, run reinstall. Triggered by "update uniform packages" / "bump uniform" / `/update-uniform-packages`. Procedure: [`.claude/skills/update-uniform-packages/SKILL.md`](.claude/skills/update-uniform-packages/SKILL.md). +- **Create alpha packages** → bump every workspace's `version` field from `X.Y.Z` to `X.Y.Z-alpha.1` (all workspaces stay in lockstep), wipe the lockfile, run reinstall. Triggered by "create alpha packages" / "bump alpha" / "alpha release" / `/create-alpha-packages`. Procedure: [`.claude/skills/create-alpha-packages/SKILL.md`](.claude/skills/create-alpha-packages/SKILL.md). + +## House rules + +- **Never bump the local workspace `@uniformdev/*` packages to npm registry versions.** The packages with `@uniformdev/*` *names* under `apps/*` and `packages/*` are produced by this repo and resolved via npm workspaces; they are not the same as the npm-published `@uniformdev/*` SDK packages. +- **Workspace versions stay in lockstep.** Don't bump one workspace's `version` without bumping them all. Use `npm run workspace:fix` if drift is detected. +- **Do not commit, tag, push, or open PRs autonomously.** Leave that to the human. +- **Do not skip git hooks** (`--no-verify`, `--no-gpg-sign`, etc.) unless the human explicitly asks. +- **Do not run `build` / `lint` / tests automatically after a reinstall** unless asked. +- **Lockfile**: don't hand-edit `package-lock.json`. If a workflow requires regenerating it, delete it and run `npm run reinstall`. +- **Verification**: prefer `npm run build` from the repo root over workspace-scoped checks — the root build catches RSC runtime errors that scoped checks miss. + +## Coding standards + +- Generate clean code; remove unused code so the linter and TypeScript checks pass automatically. +- **Package manager: npm.** This repo uses npm workspaces with `package-lock.json`. Do not introduce `pnpm` or `yarn`; do not commit alternative lockfiles. +- You are a senior front-end engineer — follow current Next.js / React / TailwindCSS best practices. Do not re-invent the wheel. +- Do not over-deliver. Make the minimum changes the user asked for; do not create more components, files, or abstractions than requested. +- **Verification: `npm run build` from the repo root** is the canonical post-change check — it catches RSC runtime errors that workspace-scoped checks (typecheck/lint) miss. Do **not** run a build *concurrently* with `npm run dev` — stop the dev server first, since they share build artifact directories. + +## Environment variables + +Always wire up when working with Uniform: + +- `UNIFORM_API_KEY` — server-side API key (read-published-compositions permission minimum, more for CLI usage). +- `UNIFORM_PROJECT_ID` — server-side project ID. +- `NEXT_PUBLIC_UNIFORM_PROJECT_ID` — client-exposed mirror (already used across `packages/csk-components` etc.). +- `UNIFORM_PREVIEW_SECRET=hello-world` — default value when setting up locally so preview works out of the box. + +## Deep references (load when relevant) + +These docs are linked, not inlined — consult them when working on the matching surface area. Cursor auto-attaches them via globs in `.cursor/rules/`; Claude Code and other agents should read them on demand from these links. + +- **[docs/uniform/concepts.md](docs/uniform/concepts.md)** — Uniform CMS modeling: compositions, components, slots, patterns, naming, parameter/field types, MCP unsupported features. Consult when designing or describing Uniform entities. Cursor auto-attach globs: `apps/**/*.{ts,tsx}`, `packages/csk-components/**`, `packages/csk-recipes/**`, `packages/design-extensions-tools/**`. +- **[docs/uniform/sdk.md](docs/uniform/sdk.md)** — Uniform SDK / CLI / MCP usage: `uniform.config.ts`, sync push/pull, App Router catch-all route wiring, MCP-vs-CLI rules, the "never hand-edit `apps/*/content/`" rule. Consult when wiring or maintaining the SDK. Cursor auto-attach globs: `apps/*/uniform.config.ts`, `apps/*/content/**`, `apps/*/.env*`, `apps/*/src/app/**`. + +## How agents discover these workflows + +| Agent | Always-on | Loaded selectively | +|---|---|---| +| Claude Code | [`CLAUDE.md`](CLAUDE.md) → `@AGENTS.md` | [`docs/uniform/*.md`](docs/uniform/) via markdown links when relevant; [`.claude/skills//SKILL.md`](.claude/skills/) for workflows | +| Cursor | this `AGENTS.md` (natively read per Cursor docs as an alternative to `.cursor/rules`) | [`.cursor/rules/uniform-concepts.mdc`](.cursor/rules/uniform-concepts.mdc) + [`.cursor/rules/uniform-sdk.mdc`](.cursor/rules/uniform-sdk.mdc) auto-attach via globs; workflow `.mdc` files trigger on intent | +| Codex / Aider / Copilot / Zed / JetBrains Junie / Warp / Devin / Google Jules / others | this `AGENTS.md` | `docs/uniform/*.md` via the markdown links above | + +If you're editing always-on rules, edit **this file only**. If you're editing Uniform deep reference, edit the relevant `docs/uniform/*.md` only. If you're editing a workflow procedure, edit the `SKILL.md` only — entry-point files pick up changes automatically. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..5be24caf --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,7 @@ +# Claude Code project memory + +This project's agent guidance is consolidated in [AGENTS.md](AGENTS.md) — that file is the single source of truth, read by every agent that works in this repo (Cursor reads it natively; Codex / Aider / Copilot / Zed / JetBrains Junie / others read it via the open AGENTS.md convention). + +For Claude Code, the line below imports AGENTS.md into project memory so its rules apply automatically. + +@AGENTS.md diff --git a/apps/csk-marketing-site/package.json b/apps/csk-marketing-site/package.json index 5cfd87e2..5f2ab042 100644 --- a/apps/csk-marketing-site/package.json +++ b/apps/csk-marketing-site/package.json @@ -1,6 +1,6 @@ { "name": "@uniformdev/csk-marketing-site", - "version": "6.1.84", + "version": "6.1.85", "private": true, "engines": { "yarn": "please-use-npm", diff --git a/apps/csk-storybook/package.json b/apps/csk-storybook/package.json index b55decb3..9d0fa1ff 100644 --- a/apps/csk-storybook/package.json +++ b/apps/csk-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@uniformdev/csk-storybook", - "version": "6.1.84", + "version": "6.1.85", "description": "CSK vNext Storybook is an interactive Storybook build showcasing components from the CSK vNext component starter kit. It provides detailed documentation, live previews, and testing capabilities for easy integration into your projects.", "main": "index.js", "scripts": { diff --git a/apps/csk/package.json b/apps/csk/package.json index b10559e7..60c92546 100644 --- a/apps/csk/package.json +++ b/apps/csk/package.json @@ -1,6 +1,6 @@ { "name": "@uniformdev/component-starter-kit", - "version": "6.1.84", + "version": "6.1.85", "private": true, "engines": { "yarn": "please-use-npm", diff --git a/docs/uniform/concepts.md b/docs/uniform/concepts.md new file mode 100644 index 00000000..f2b80d1f --- /dev/null +++ b/docs/uniform/concepts.md @@ -0,0 +1,125 @@ +# Uniform CMS — core concepts + +Reference for how Uniform models content. Read this before creating, editing, or describing Uniform entities. This doc is loaded automatically by Cursor when editing Uniform-aware code (see [`.cursor/rules/uniform-concepts.mdc`](../../.cursor/rules/uniform-concepts.mdc)) and is linked from [`AGENTS.md`](../../AGENTS.md) for all other agents. + +## Authoring practices (critical) + +1. **Component patterns**: Always create a component pattern when pushing a new component to a Uniform project, and fill it with realistic content (using prior examples of the component's usage where possible; otherwise generate sensible defaults). +2. **Slot defaults**: When creating a new slot in Uniform, configure it with `allowAllComponents=true`, `inheritAllowedComponents=false`, and `patternsInAllowedComponents=false`. +3. **Parameter overridability**: When pushing a component pattern, mark every parameter as overridable by default. +4. **Repeated properties**: When you see repeated property sets (e.g. `title1/description1/image1`, `title2/description2/image2`, …), model the repeated set as a child component and render it via `UniformSlot`. Avoid suffix-numbered parameter pollution. + +## Compositions + +A **composition instance** is roughly equivalent to a page. **Composition definitions** define a reusable schema for instances — same structure as a component (parameters + slots), plus a route/page binding that instances use. + +- "Composition" alone is ambiguous — infer from context: schema/template ⇒ definition; page/route ⇒ instance. +- Composition **parameters** are for global content that will never be personalized (e.g. OpenGraph / meta tags). Don't put "hero title" on the composition — put it on a `Hero` component in the content slot. +- A single composition definition called `Page` is usually enough. Add more (e.g. `Popup`, `Minimal Page`) only when the page shell or parameters genuinely differ. + +## Entries + +**Entries** are instances of structured content defined by a **content type** (the blueprint). Each entry has a built-in slug; do not define an explicit `slug` field. + +How entries differ from compositions/components: an entry is design-agnostic structured content. A component/composition is the experience layer that displays content. The same entry can be shown via a hero, a card, or a list component by binding entry fields to component parameters in a pattern. + +Entries can reference other entries (relationships) to compose complex structures. + +## Components + +A Uniform component is a CMS-author-manipulable visual element with **parameters** (props) and **slots** (named child-component containers). Each component has a definition (schema) and instances (placed within composition slots). + +Component definition attributes: _name_, _public ID_, _parameters_, _slots_. + +Slot definition attributes: _name_, _public ID_, _allowed components_, _min components_, _max components_. + +**Slot allowability rules**: + +1. `allowAllComponents: true` — anything goes. +2. `allowAllComponents: false` — `allowedComponents` is an explicit list of public IDs. Component patterns are listed with a `$p:` prefix. +3. `patternsInAllowedComponents`: + - `true` — a pattern is only allowed if its specific `$p:` is in the list. Other patterns based on the same base component are not allowed. + - `false` — a pattern is allowed if its base component type is in the list. (When flipping this to `false`, remove any `$p:` entries first.) +4. When editing a component or composition **pattern definition**, the slot section component (`$slotSection`) is always allowed in any slot. + +Before adding components to a slot, confirm they're allowed by the above rules. + +## Slot sections (`$slotSection`) + +Only valid inside **component patterns** and **composition patterns** — not on regular component definitions. + +- A slot section creates an extension point so pattern consumers can insert components into a slot that's otherwise locked down by the pattern. +- Slot sections have one slot, `$slotSectionItems`. When pattern consumers add components, they target `$slotSectionItems` — not the parent slot name. +- At delivery time, the slot section dissolves and its children become part of the parent slot. +- Slot sections cannot have default components when defined on a pattern. +- Slot section contents on nested patterns may only be set on the direct parent consumer. To expose a nested slot section, re-export it by adding a slot section to the parent pattern in the child's slot section. +- Do NOT include `$slotSection` in lists of allowed components for plain (non-pattern) entities. + +## Content types + +Define a reusable structure for content (e.g. `Product`, `BlogPost`) with fields. Entries are instances. A content type schema differs from a component schema: components represent a specific visual rendering; content types are abstract content shapes that can be presented many ways via patterns. + +Content type attributes: _name_, _public ID_, _fields_. + +## Patterns + +Patterns are units of reuse. Updates to a pattern propagate to every consumer immediately. + +- **Component pattern** — a shared component instance with parameter values and slot children. Can be nested 2–3 levels deep (more causes performance issues). +- **Composition pattern** — a shared composition template; non-overridable data is locked down. +- **Entry pattern** — same idea for entries. +- **Overrides** — a pattern definition can mark parameters/fields as overridable. Consumers can break inheritance and supply their own values. Nested patterns inherit overridability; you cannot re-lock an already-overridable parameter from an outer pattern. +- **As shared content snippets** — reuse exact content (e.g. legal disclaimer on every press release). +- **As data binding templates** — a pattern can declare a **data resource** (e.g. a Uniform entry or external REST API) and bind parameters to it via **dynamic tokens** like `${#jptr:/myEntry/fields/title}`. Example: a `Product Card` pattern with an entry data resource auto-fills `title` and `image` from a chosen product. + +Pattern attributes: _name_, _type_ (base component public ID), _public id_, _data resources_ (name, type), _parameters_ (value, overridable), _slots_. + +## Assets + +Media files live in the **Asset Library**. Mesh integrations can add external sources (DAM, Unsplash, Getty, …). + +Asset attributes: _public id_, _type_ (`image`/`video`/`audio`/`document`/`other`), _source_ (`uniform-assets` or a Mesh integration ID), _fields_ (title, description, file, URL, focal point, dimensions, …). + +## Localization + +Locales are declared at the project level. Compositions, entries, and patterns must **enable** a locale before they can have content in it. Enable the default locale on new entries/patterns/compositions unless the user specifies otherwise. + +## Field / parameter types + +Common attributes: _name_, _public ID_ (unique within a component or content type; cannot be changed after creation), _localizable_, _required_, _type_, _guidance_, _overridable_ (only on pattern definitions). + +Allowed types: `text`, `richText` (Lexical JSON), `select`, `multi-select`, `number`, `date`, `dateTime`, `checkbox`, `link`, `asset`, `json` (not author-friendly), `contentReference` (content types only — not components), `$enr` (enrichment tagging), `group` (visual grouping; grouped fields must immediately follow the group in the fields list). + +## Naming conventions + +- Names use **title-cased prose**: `Main Header`, not `main-header` or `MainHeader`. Don't include the entity type in the name (`Hero`, not `Hero Component`). +- Don't name entities after sample content; describe meaning. `

Hello

` is FPO — the component is `Headline`, not `Hello`. +- **Public IDs** are camelCase, slugified from the name (`Main Header` → `mainHeader`). Unique within their entity type. Immutable after creation. +- Public IDs that start with `$` are **system-owned**. Don't try to alter system components like `$personalization` or remove the `$viz` parameter. You may add/remove system components such as `$test` in `allowedComponents` lists. +- Help text is 1 short sentence, plain text, no markdown/HTML. Often unnecessary — only add it when expectations are non-obvious (e.g. "Image must be 250×250 px"). + +## Tool usage tips + +- Before creating or updating Uniform Patterns, fetch the relevant Component Definitions so you know valid types and parameters. +- Batch multiple updates to the same pattern into a single tool call. +- When a Uniform tool returns an edit URL, surface it to the user as a link. +- Before reordering parameters/fields on a definition, fetch the latest data so you target the correct positions. +- Reordering = remove + re-add in the new order. +- Enable the default locale on new entries/patterns/compositions unless the user says otherwise. +- Duplicating entries/compositions/patterns: use the duplicate function, not "create new + copy data". + +## Unsupported via MCP / AI today + +If the user asks for any of these, explain the limitation and (where possible) offer a Uniform web app link instead: + +- Creating new Loop component instances +- Adding/editing/removing block-type fields, parameters, or definitions +- Editing conditional values on parameters/fields (default value is editable) +- Setting visibility rules on component instances +- Changing data sources, types, or resources +- Adding/removing project map nodes or linking compositions to them +- Adding/removing content from Uniform Releases, or modifying releases (lock, schedule) +- Anything that requires published content (you only have draft access) +- Managing workflows or workflow stage transitions +- Creating, uploading, editing, or deleting assets +- Changing user permissions diff --git a/docs/uniform/sdk.md b/docs/uniform/sdk.md new file mode 100644 index 00000000..700eb35d --- /dev/null +++ b/docs/uniform/sdk.md @@ -0,0 +1,68 @@ +# Uniform SDK / CLI / MCP usage + +How to wire and maintain the Uniform SDK in this Next.js App Router monorepo. Loaded automatically by Cursor when editing `uniform.config.ts`, files under `apps/*/content/`, or App Router routes (see [`.cursor/rules/uniform-sdk.mdc`](../../.cursor/rules/uniform-sdk.mdc)). Linked from [`AGENTS.md`](../../AGENTS.md) for all other agents. + +## SDK usage rules (critical) + +1. **Full Uniform integration when asked to "add Uniform"**: do all of it — install packages, register the component, change prop types to Uniform parameter types for links/assets, and render text via `UniformText` / `UniformRichText` rather than raw strings. +2. **Never use `uniform:push` directly to write Uniform entities**: do not invoke the `uniform:push` script as a way to create or modify component definitions, component patterns, compositions, entries, or any Uniform entity. Use the Uniform MCP tool when configured; otherwise direct the user to perform the action in the Uniform web app, then re-run `npm run uniform:pull` to refresh local state. + +## Authenticating + +Uniform API keys are stored as `UNIFORM_API_KEY` in `.env`. They start with `uf...`. Minimum permission for reading compositions is "Read Published Compositions"; CLI usage requires read+write on whatever entity types you intend to sync (the `developer` role is a quick way to get full permissions). Use the **"Copy as .env"** button in the Uniform dashboard when creating a key — it emits all the env vars you need. + +Required env vars in this repo: + +- `UNIFORM_API_KEY` — server-side API key. +- `UNIFORM_PROJECT_ID` — server-side project ID. +- `NEXT_PUBLIC_UNIFORM_PROJECT_ID` — client-exposed mirror (used across `packages/csk-components` etc.). +- `UNIFORM_PREVIEW_SECRET=hello-world` — default value when setting up locally so preview works out of the box. + +## How Uniform delivers layout data + +A composition instance is hierarchical JSON: components nested in slots. Each component has a type that maps to a front-end component via the project's component map / registration. + +**Routing** is delegated via Uniform's **Project Map**. The front-end defines a wildcard route that hands the path to Uniform's **Route API**, which resolves the correct composition instance. + +## Next.js (App Router) wiring + +This repo uses the **Next.js App Router** (`apps/csk/src/app/`, `apps/csk-marketing-site/src/app/`), not the Pages Router. + +1. **Catch-all routing for Uniform compositions**: place the catch-all at the App Router root — e.g. `apps//src/app/[...path]/page.tsx`. If a conflicting `page.tsx` exists at the same level, rename it to `.off` (e.g. `page.tsx.off`) so it stops being a route, rather than deleting it. +2. **Composition-component coverage**: when adding the SDK, scan the Uniform project for composition components and **automatically create a corresponding front-end component for each in the codebase**, register it via the component map, and define every slot from the composition definition. Without this the preview can't resolve which React component renders the composition and will error. + +## CLI + +The CLI lives in the `@uniformdev/cli` npm package and **must be a devDependency** (already configured in `apps/csk` and `apps/csk-marketing-site`). + +Config files in this repo: + +- [`apps/csk/uniform.config.ts`](../../apps/csk/uniform.config.ts) +- [`apps/csk-marketing-site/uniform.config.ts`](../../apps/csk-marketing-site/uniform.config.ts) + +These select which entity types to sync and where serialized files live (this repo serializes to **`./content/`** per the configs, not `./uniform-data/` — adjust any prior knowledge accordingly). + +Two primary CLI commands: + +- `uniform sync pull` — pull online project state into serialized files on disk. +- `uniform sync push` — push serialized files into the online project (mirror semantics: creates, updates, **and deletes**). + +In this repo the scripts are wired per-app, not at the root: + +- `npm run uniform:pull` (in `apps/csk` or `apps/csk-marketing-site`) +- `npm run uniform:push` (same) +- `npm run uniform:publish` (same) + +Get CLI help: `uniform --help`. + +## CRITICAL — don't hand-edit serialized Uniform data + +**Never create, read, update, or delete the YAML/JSON files under `apps/*/content/` directly when trying to manipulate Uniform components, content types, patterns, entries, or any other Uniform entity.** Those files are a mirror of online state; editing them by hand drifts state and is fragile. + +Instead: + +1. **If the Uniform MCP server is configured** (check for `.mcp.json` or active MCP tools), use it to make changes. +2. **Otherwise**, direct the user to perform the change in the Uniform web app and then run `npm run uniform:pull` in the affected app (`apps/csk` or `apps/csk-marketing-site`) to refresh disk state. +3. If you cannot reach an MCP action and the user expects one, return a graceful message and abort rather than attempting a CLI push. + +After any MCP-driven change, **always run `npm run uniform:pull`** in the affected app so the on-disk state matches the online state. diff --git a/package-lock.json b/package-lock.json index 9d69ed84..e1981fc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "csk-packages", - "version": "6.1.84", + "version": "6.1.85", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "csk-packages", - "version": "6.1.84", + "version": "6.1.85", "workspaces": [ "apps/*", "packages/*" @@ -27,7 +27,7 @@ }, "apps/csk": { "name": "@uniformdev/component-starter-kit", - "version": "6.1.84", + "version": "6.1.85", "dependencies": { "@uniformdev/assets": "^20.64.0", "@uniformdev/canvas": "^20.64.0", @@ -74,7 +74,7 @@ }, "apps/csk-marketing-site": { "name": "@uniformdev/csk-marketing-site", - "version": "6.1.84", + "version": "6.1.85", "dependencies": { "@uniformdev/assets": "^20.64.0", "@uniformdev/canvas": "^20.64.0", @@ -122,7 +122,7 @@ }, "apps/csk-storybook": { "name": "@uniformdev/csk-storybook", - "version": "6.1.84", + "version": "6.1.85", "devDependencies": { "@chromatic-com/storybook": "^5.2.1", "@repo/eslint-config": "*", @@ -23417,7 +23417,7 @@ }, "packages/csk-cli": { "name": "@uniformdev/csk-cli", - "version": "6.1.84", + "version": "6.1.85", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@inquirer/prompts": "^8.4.3", @@ -23454,7 +23454,7 @@ }, "packages/csk-components": { "name": "@uniformdev/csk-components", - "version": "6.1.84", + "version": "6.1.85", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@inquirer/prompts": "^8.4.3", @@ -23511,7 +23511,7 @@ }, "packages/csk-recipes": { "name": "@uniformdev/csk-recipes", - "version": "6.1.84", + "version": "6.1.85", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@inquirer/prompts": "^8.4.3", @@ -23550,7 +23550,7 @@ }, "packages/design-extensions-tools": { "name": "@uniformdev/design-extensions-tools", - "version": "6.1.84", + "version": "6.1.85", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@inquirer/prompts": "^8.4.3", @@ -23586,7 +23586,7 @@ }, "packages/eslint-config": { "name": "@repo/eslint-config", - "version": "6.1.84", + "version": "6.1.85", "devDependencies": { "@eslint/js": "^9.31.0", "@next/eslint-plugin-next": "^16.2.6", @@ -23607,12 +23607,12 @@ }, "packages/internal-scripts": { "name": "@repo/internal-scripts", - "version": "6.1.84", + "version": "6.1.85", "license": "ISC" }, "packages/typescript-config": { "name": "@repo/typescript-config", - "version": "6.1.84", + "version": "6.1.85", "license": "MIT" } } diff --git a/package.json b/package.json index 46b55c8e..a9760548 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "csk-packages", - "version": "6.1.84", + "version": "6.1.85", "private": true, "scripts": { "build": "turbo build", diff --git a/packages/csk-cli/package.json b/packages/csk-cli/package.json index 774bfb8e..3259d67a 100644 --- a/packages/csk-cli/package.json +++ b/packages/csk-cli/package.json @@ -1,6 +1,6 @@ { "name": "@uniformdev/csk-cli", - "version": "6.1.84", + "version": "6.1.85", "description": "Command-line interface (CLI) tool designed to streamline the development workflow within Uniform projects. It provides commands for pulling additional data and generating components based on Canvas data", "license": "SEE LICENSE IN LICENSE.txt", "engines": { diff --git a/packages/csk-components/package.json b/packages/csk-components/package.json index e4db1993..9b0e04af 100644 --- a/packages/csk-components/package.json +++ b/packages/csk-components/package.json @@ -1,6 +1,6 @@ { "name": "@uniformdev/csk-components", - "version": "6.1.84", + "version": "6.1.85", "description": "Components Starter Kit that provides a set of basic components for building websites within a Uniform project", "license": "SEE LICENSE IN LICENSE.txt", "engines": { diff --git a/packages/csk-recipes/package.json b/packages/csk-recipes/package.json index 633254f8..9d3304eb 100644 --- a/packages/csk-recipes/package.json +++ b/packages/csk-recipes/package.json @@ -1,6 +1,6 @@ { "name": "@uniformdev/csk-recipes", - "version": "6.1.84", + "version": "6.1.85", "description": "command-line interface (CLI) and utility functions to help you work with recipes in a CSK project. It simplifies project initialization by allowing you to choose templates and include specific recipes", "license": "SEE LICENSE IN LICENSE.txt", "engines": { diff --git a/packages/design-extensions-tools/package.json b/packages/design-extensions-tools/package.json index 2c4c7e67..b7c0b282 100644 --- a/packages/design-extensions-tools/package.json +++ b/packages/design-extensions-tools/package.json @@ -1,6 +1,6 @@ { "name": "@uniformdev/design-extensions-tools", - "version": "6.1.84", + "version": "6.1.85", "description": "Command-line interface (CLI) tool and a set of utilities for working with design extension integrations", "license": "SEE LICENSE IN LICENSE.txt", "engines": { diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 67e6c20e..48e1565b 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@repo/eslint-config", - "version": "6.1.84", + "version": "6.1.85", "type": "module", "private": true, "exports": { diff --git a/packages/internal-scripts/package.json b/packages/internal-scripts/package.json index b828176e..e5be330c 100644 --- a/packages/internal-scripts/package.json +++ b/packages/internal-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@repo/internal-scripts", - "version": "6.1.84", + "version": "6.1.85", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json index 16643d98..a4d2d689 100644 --- a/packages/typescript-config/package.json +++ b/packages/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@repo/typescript-config", - "version": "6.1.84", + "version": "6.1.85", "private": true, "license": "MIT", "publishConfig": {