.agents/skills/sanity-default-plugins/SKILL.md
Before adding a core plugin, read the sanity-plugin-authoring skill at ../sanity-plugin-authoring/SKILL.md to understand the general Sanity plugin API and what plugins can provide. Then inspect nearby plugins and these files:
packages/sanity/src/core/config/resolveDefaultPlugins.tspackages/sanity/src/core/config/types.tspackages/sanity/src/core/config/studio/types.tspackages/sanity/src/core/*/plugin/The new plugin should be added inside core so it can be imported into the default plugins.
Prefer local patterns over new abstractions.
Use definePlugin and export a stable internal name constant:
import {definePlugin} from '../../config/definePlugin'
export const FEATURE_NAME = 'sanity/feature'
export const feature = definePlugin({
name: FEATURE_NAME,
studio: {
components: {
layout: FeatureStudioLayout,
},
},
i18n: {
bundles: [featureUsEnglishLocaleBundle],
},
})
Use ../../config/definePlugin when matching existing internal plugin files. ../../config is also available in some folders.
Default core plugins that render UI text should add a locale resource bundle. Follow the pattern from packages/sanity/src/core/singleDocRelease:
packages/sanity/src/core/<feature>/i18n/index.ts: exports the locale namespace, US English bundle, and resource key type.packages/sanity/src/core/<feature>/i18n/resources.ts: exports default locale strings and keyof resource type.packages/sanity/src/core/<feature>/plugin/index.ts: imports the bundle and registers it under i18n.bundles.Example i18n/index.ts:
import {type LocaleResourceBundle} from '../../i18n'
export const featureNamespace: 'feature' = 'feature'
export const featureUsEnglishLocaleBundle: LocaleResourceBundle = {
locale: 'en-US',
namespace: featureNamespace,
resources: () => import('./resources'),
}
export type {FeatureLocaleResourceKeys} from './resources'
Example i18n/resources.ts:
const featureLocaleStrings = {
'action.example': 'Example',
}
export type FeatureLocaleResourceKeys = keyof typeof featureLocaleStrings
export default featureLocaleStrings
Example plugin registration:
import {featureUsEnglishLocaleBundle} from '../i18n'
export const feature = definePlugin({
name: FEATURE_NAME,
i18n: {
bundles: [featureUsEnglishLocaleBundle],
},
})
Default core plugins are listed in resolveDefaultPlugins.ts.
defaultPlugins(options) in the desired composition order.plugin.name === FEATURE_NAME branch in getDefaultPlugins.DefaultPluginsWorkspaceOptions in types.ts.getDefaultPluginsOptions, build default plugin options directly from workspace config defaults and spreads. Do not call config property reducers here; reducers belong to resolved source/workspace config, while default plugin options are a lightweight workspace-level input for plugin insertion.packages/sanity/src/core/config/__tests__/resolveConfig.test.ts with focused default plugin tests:
Example default option shape:
variants: {
enabled: false,
...workspace.beta?.variants,
}
Remember: user plugins are appended before default plugins in prepareConfig.tsx, then the component middleware chain reverses flattened config order. Check the existing chain before relying on wrapper order.
For default plugin changes, run:
pnpm vitest run --project=sanity packages/sanity/src/core/config/__tests__/resolveConfig.test.ts
Also run lint/read diagnostics for edited files. Add component-level tests only when the plugin changes runtime rendering beyond insertion.