* fix(skills): nest initial value templates under schema in localization rule
* fix(skills): correct newDocumentOptions filter in localization rule
The "New document" filter in section 5 of the localization reference
empties the menu instead of narrowing it to the base language.
Two things combine. Templates that declare `parameters` are excluded
from the auto-generated new-document list, so `post-en` never reaches
the filter. The remaining items are built as `{templateId, description,
icon, title}` with no `parameters` key, so `item.parameters?.language
=== 'en'` is always false and `post`/`page` are dropped as well. The
result is an empty menu, verified by resolving a real workspace and
calling `document.resolveNewDocumentOptions({type: 'global'})`.
Add the parameterized templates to `newDocumentOptions` explicitly,
with the parameter values on the item, and filter out only the
auto-generated entries they replace. Generalize both blocks over a
`LOCALIZED_TYPES` list so `page` gets a template too, rather than being
filtered out with nothing to replace it.
Verified against sanity@6.11.0: the menu now offers `post-en` and
`page-en`, and each resolves an initial value of `{language: 'en'}`.
Both blocks type-check under `tsc --strict`, including in the annotated
`const config: Config` form where excess-property checking fires.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Chk3fV36ApvJWqN7gs4Fzy
* fix(skills): use type-only import for Template in localization rule
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XowPCwHVq9KVxW48fQisT
---------
Co-authored-by: Claude <noreply@anthropic.com>
* docs: fix schema.md icon examples for @sanity/icons v5 subpath imports
@sanity/icons v5 (pulled in transitively by sanity ^6.7.0) removed named
icon exports from the package root; only the icons map and Icon component
remain there, with named icons moved to per-icon subpaths. The root's
type declarations still declare the old names (as `never`, with a
deprecation note), so the old import style type-checks but crashes
Sanity Studio at runtime.
Update schema.md's icon import example and content-type table to use
the v5 subpath style (e.g. `@sanity/icons/DocumentText`) so agents
following this skill don't ship a working build that crashes in the
browser.
* docs: fix @sanity/icons v5 subpath imports in localization, page-builder, seo refs
Same broken root-import pattern fixed in schema.md: @sanity/icons v5
removed named icon exports from the package root, so the old
`import { XIcon } from '@sanity/icons'` style type-checks but crashes
Sanity Studio at runtime. Update the icon import examples in
localization.md, page-builder.md, and seo.md to the v5 per-icon
subpath style (e.g. `@sanity/icons/Home`).
* docs: trim icon-import explanation to the code examples
The mechanism paragraph explained internals an agent never acts on, and
claimed the bad import "crashes Studio at runtime". It doesn't — Vite
and esbuild both fail the bundle with `"DocumentTextIcon" is not
exported by @sanity/icons`, so `sanity build` errors immediately.
Keep the ✅/❌ pair and the table's Import column (the parts that change
behavior), and correct the failure mode in the ❌ comment.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rune Botten <rbotten@gmail.com>
* fix: correct buggy example code in skill references
Several reference examples contain code an agent would copy verbatim but
that doesn't behave as intended:
content-experimentation-best-practices/references/cms-integration.md
- assignVariant drew Math.random() * 100 without normalizing against the
sum of variant weights, so weights that don't total 100 skew the split
- it reused a cached cookie value without checking it's still a valid
variant, leaving users bucketed to removed/renamed IDs
- it assumed a non-empty variants array (variants[length - 1] throws on [])
- the GROQ example filtered experimentVariants only by experiment status,
so the first running experiment won regardless of the user's assignment;
now scoped by experimentId plus the assigned variantId
sanity-best-practices/references/migration-html-import.md
- the custom <a> deserializer returned a top-level _type: 'link' block;
htmlToBlocks expects an __annotation with a markDef and children from
next(), matching portable-text-conversion/rules/html-to-pt.md
sanity-best-practices/references/functions.md
- the auto-tag function listened on create/update and wrote to tags with
no guard, re-triggering itself in a loop; added !defined(tags) to the
filter, mirroring the recursion guard in the translation example
* fix: more buggy example code in skill references
Second batch of fixes from automated review (Cursor Bugbot):
- cms-integration.md: the assignVariant fallback returned the last variant
without calling setCookie, so visitors who hit that path (stale/invalid
cookie, zero total weight) were re-bucketed on every request; persist it
- functions.md: the step-by-step 'Creating a Function' tutorial filtered on
_type == "post" while its handler patches the same document — add the
!defined(firstPublished) recursion guard the file itself prescribes
- angular.md: the Transfer State snippet had literal '+' diff markers pasted
in, making it invalid TypeScript; strip them and hoist the imports
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix: address Copilot review findings in skill examples
- migration-html-import: guard `el.tagName` with optional chaining so the
custom rules fall through for non-element nodes (text nodes) instead of
throwing, matching portable-text-conversion/rules/html-to-pt.md.
- angular: widen the TransferState key to `ClientReturn<Query> | null` so
`get(key, null)` type-checks against Angular's
`get<T>(key: StateKey<T>, defaultValue: T): T`.
* fix: guard null href/src in htmlToBlocks deserializer examples
`getAttribute` returns null for a missing attribute, so the examples could
emit `href: null` markDefs and the literal string `image@null` — the latter
only fails later at asset-upload time, with no pointer back to the bad node.
Both rules now read the attribute once and fall through when it is absent,
so the surrounding text is still deserialized by the default handling.
Applies the same fix to portable-text-conversion/rules/html-to-pt.md, which
carried the identical `image@null` bug.
* docs: scope _sanityAsset examples to the NDJSON import path
`_sanityAsset` is resolved by the CLI importer, which fetches each `image@<url>`
and swaps in a real asset reference. The mutation API does not interpret it, so
the same blocks written via @sanity/client, `sanity exec`, or `defineMigration`
are stored verbatim, leaving an image field with no `asset` reference.
Neither example said so, and migration-html-import.md labelled the directive
"Upload image separately, store reference" — a description of the client-upload
path it is not. It then went on to demonstrate `defineMigration`, the very path
where the directive is inert. Name the supported path at both call sites, add a
note pointing at the upload-first alternative, and flag the constraint in the
`defineMigration` section.
Refs: https://www.sanity.io/docs/content-lake/importing-data
* docs: use canonical plural CLI topics throughout
The skills used both forms: `sanity dataset import` / `schema deploy` /
`migration run` alongside `blueprints *` / `functions *`. Standardize on the
plural form.
Plural is the canonical topic in @sanity/cli 7.x — registered in oclif.config.js
and backed by dist/commands/<topic>/, so oclif dispatches it directly. Singular
resolves only by missing oclif lookup and landing in the command_not_found hook,
which rewrites it via topicAliases. That shim works today and is silent, but it
is a compatibility path, and it is not what the docs show.
Covers dataset -> datasets, schema -> schemas, migration -> migrations.
`blueprints` and `functions` were already plural.
---------
Co-authored-by: Rune Botten <rbotten@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Add video hosting guidance to sanity-best-practices
Users keep serving video from Sanity file assets in production, which
delivers raw downloads with no adaptive streaming and leads to very high
bandwidth usage. Add a Video section to the skill's global guidance:
use sanity-plugin-mux-input or an external video platform and store only
the playback ID or embed URL in Sanity.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Siwz2hh1ZJdWfqnZZhQ9T1
* docs(skill): recommend Media Library video on Enterprise plans
Address PR feedback: Media Library supports transcoded, adaptively
streamed video (via Mux), but only as a paid add-on on certain
Enterprise plans. Recommend it first for those plans, and clarify that
sanity-plugin-mux-input uploads/manages videos in your own Mux account
rather than streaming from the Studio.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Knut Melvær <knut@sanity.io>
* fix(rules): correct GROQ pagination example, slice bounds can't be params
`[$start...$end]` is shown in groq.md and nextjs.md as valid pagination
syntax, but GROQ slice bounds must be constant numbers — parameters
aren't allowed there. Running it produces:
Invalid GROQ query: slicing must use constant numbers
Update both examples to validate the page bounds and interpolate them
into the query string instead of passing $start/$end as params.
* fix(sanity-best-practices): trim GROQ slice bounds guidance to a plain statement
Per maintainer feedback, drop the negative example and shorten the
explanation instead of dwelling on the failure mode. State plainly that
slice bounds must be constant numbers and keep only the corrected example.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ej91qtX9Y4EkNXTW9djBwU
---------
Co-authored-by: Claude <noreply@anthropic.com>
Onboarding flows start the agent from a parent folder containing the
Studio (studio/ or studio-*) next to the app folder. Teach the
get-started reference to find the Studio config across the workspace,
locate the app folder before detecting the framework (asking the user
when ambiguous), and run the smoke test from the app folder.
Co-authored-by: Cursor <cursoragent@cursor.com>
Embedding the Studio in the Next.js app slows dev/builds (Studio compiles
through next build instead of Vite), rules out Studio auto-updates (Next.js
lacks ESM import map support) and TypeGen watch mode, and nudges content
models toward being website-centric. Flip the recommendation to a standalone
Studio in a simple monorepo layout (studio/ + web/) and add migration steps
for existing embedded Studios.
Co-authored-by: Cursor <cursoragent@cursor.com>
Use the shorthand skill install command and replace unclear WordPress examples with runnable auth and XML parsing guidance.
Co-authored-by: Cursor <cursoragent@cursor.com>
Rewrite migration instructions to address the agent directly instead of referring to AI as a separate actor.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add a standalone migration skill with platform-specific references and route migration topics through the workspace knowledge router.
Co-authored-by: Cursor <cursoragent@cursor.com>
Reading process.env from a shared module bundled into the client throws
on lazy route transitions; split publishable VITE_* vars from secrets,
add image URL builder + smoke test step, and surface a cross-Vite warning.
Avoids collision with other Claude Code plugins (e.g. CodeRabbit) that also register /review in the shared flat slash-command namespace.
Co-authored-by: Cursor <cursoragent@cursor.com>
Combine updated Claude Code, Cursor, and Lovable install instructions with Codex plugin support from main.
Co-authored-by: Cursor <cursoragent@cursor.com>
Point users to the official Claude Code and Cursor marketplace install flows, update Lovable to use the prebuilt chat connector, and align the Claude plugin name to sanity across manifests.
Co-authored-by: Cursor <cursoragent@cursor.com>
@nuxtjs/sanity bundles groq, @sanity/client, @sanity/visual-editing, and
@portabletext/vue as direct dependencies. It also auto-imports the groq and
defineQuery template tags plus a full set of composables (useSanity,
useSanityQuery, useSanityConfig, useSanityPerspective, the visual-editing
state helpers) and auto-registers <SanityContent>, <SanityImage>, and
<SanityFile> components. None of those needed to be in a separate install
step or import statement.
Updates:
- Drop `groq` from the install line (it's a transitive of @nuxtjs/sanity,
auto-imported by the module so Node-level resolution is irrelevant)
- Make @sanity/image-url an optional second install (only needed for the
manual urlFor() approach; <SanityImage> covers the common case)
- New "What the module auto-imports" subsection listing the composables,
GROQ helpers, and components agents can use without imports
- §4 Components now correctly documents <SanityContent> (the module's
Portable Text renderer) instead of <PortableText>
- §4 Images shows both <SanityImage> (asset-id based, falls back to NuxtImg
if @nuxt/image is installed) and the manual @sanity/image-url builder
- Bumped apiVersion default to 2026-05-15 for consistency
next-sanity is the official toolkit for Next.js + Sanity. It bundles
@sanity/client, groq (with defineQuery), and @portabletext/react, and adds
Next.js-specific subpath exports for live content (defineLive), draft mode,
visual editing, the Sanity Image component, embedded Studio, and webhooks.
Updates to the Next.js inline guide:
- Install line shrinks from four packages to two: next-sanity + @sanity/image-url
- createClient, defineQuery, PortableText, and SanityDocument all import from
next-sanity (no more direct deps on @sanity/client, groq, @portabletext/react)
- Add { next: { revalidate: 30 } } fetch options to demonstrate Next.js ISR
integration
- Use SanityDocument type from next-sanity for fetch return shape
- Bump apiVersion default to 2026-05-15 to match other framework references
- Updated "see nextjs.md" pointer to enumerate the next-sanity subpath exports
(live, draft-mode, visual-editing, image, studio, webhook)
The previous SvelteKit guide used @sanity/svelte-loader, whose useQuery store
returns empty on the client under Svelte 5 (no error, just no data). Replace
the entire flow with the official @sanity/sveltekit package, which is built
for Svelte 5 and bundles @sanity/client, @sanity/visual-editing, and groq as
re-exports.
Updates throughout:
- Svelte 5 idioms: const {data} = $props(), {@render children()}, $derived
- useQuery wrapped in $derived and read via $query.data (the working pattern)
- Scaffold command added (npx sv@latest create … --no-add-ons --install npm)
- Full file set: api.ts, client.ts, client.server.ts, queries.ts, image.ts,
hooks.server.ts, app.d.ts, +layout.{server.ts,svelte}, +page.{server.ts,svelte},
post/[slug]/+page.{server.ts,svelte}
- Named createImageUrlBuilder import (the default export warns at runtime)
- Yarn-classic + Visual Editing caveat called out