plugin-transfer

작성자: sanity-io

에이전트가 copy-plugin 생성기 워크플로를 사용하여 기존 플러그인을 이 모노레포로 마이그레이션하도록 안내합니다.

npx skills add https://github.com/sanity-io/plugins --skill plugin-transfer

Plugin Transfer

Use this skill when migrating an existing plugin repository into sanity-io/plugins.

Start Here

Always start with:

pnpm generate "copy plugin"

This is the canonical transfer flow and scaffolds monorepo-compatible files and test-studio wiring.

Do not keep migration TODOs in the repo. If the generator creates README.todo.md, delete it after moving its contents into the transfer PR description. Maintainers can update PR checklists directly on GitHub without a code change.

Required vs Unnecessary Config

Keep and maintain these monorepo config files in the transferred plugin:

  • package.json
  • tsdown.config.ts
  • tsconfig.json
  • vitest.config.ts

Do not copy standalone-repo-only setup such as custom root CI/build/lint/test configs that are already handled by this monorepo.

Clean Up the Transferred README

The original README.md is preserved, but old standalone-repo content is almost always stale in the monorepo. Remove or rewrite the following before opening the PR:

  • Old release/development sections. Delete sections that describe the original repo's release or dev tooling, e.g. ## Develop & test (typically references @sanity/plugin-kit) and ### Release new version (references the original repo's GitHub Actions / semantic-release). The monorepo handles building, testing, and releasing centrally, so these instructions are wrong here.
  • Links to old/forked versions. Remove pointers like "for the v2 version, see this other repo" that link to pre-transfer forks or legacy repositories.
  • Specific Sanity Studio major versions. Do not reference the current latest Studio major (e.g. "Sanity Studio v6") since it ages quickly, and do not mention long-gone majors like v3. Reword phrasing such as "migrated to Sanity Studio V3" / "only the v3 version is maintained" to a version-agnostic statement (e.g. "maintained by Sanity.io"). Only mention a version when genuinely necessary—at most as v2 - legacy to disambiguate a legacy line—and usually omit it entirely.

Keep the substance that is still accurate: intro/description, screenshots, acknowledgements, install, usage, configuration, and license sections.

Required Transfer Checks

  1. Keep the original plugin README.md in the new plugin workspace, but clean it up (see Clean Up the Transferred README).
  2. Restore LICENSE from the original repository when it credits authors beyond Sanity.io alone (the copy-plugin generator deletes it during cleanup). If kept, update the copyright year(s) to the current year.
  3. Add and verify the generated test-studio example under dev/test-studio/src/<plugin-example>/index.tsx.
  4. Confirm the plugin is wired in dev/test-studio/sanity.config.ts.
  5. Do not update .github/CODEOWNERS during transfer unless explicitly requested.
  6. Add a changeset with a major bump for the transferred plugin (see Changesets).
  7. Update the root README.md plugins table with the transferred plugin.
  8. Add pending transfer TODOs to the transfer PR description only (see PR description checklist—not in a README or other repo file).
  9. Run the full pre-PR verification suite (see Before Submitting a PR).

Before Submitting a PR

Run these commands in order. All must pass or CI will fail:

# 1. Format code
pnpm format

# 2. Check for unused exports, dependencies, and catalog entries
pnpm knip

# 3. Run linters (includes TypeScript type checking)
pnpm lint

# 4. Build all packages
pnpm build

# 5. Run tests
pnpm test run

Knip

The copy-plugin generator adds a workspace entry to knip.jsonc. After transfer, fix any knip issues in the plugin:

  • Remove unused exports (e.g. helpers only used internally should not be exported).
  • Remove dead code flagged as unused.

Catalog warnings for dev/* workspaces (e.g. @sanity/vision used only by dev/test-studio) are expected—the root knip.jsonc sets "catalog": "warn" for those.

Lint

Transferred plugins may carry legacy patterns that fail monorepo lint rules. Fix what you can; for remaining issues in legacy src/ or test/ code, add targeted .oxlintrc.json overrides or ignorePatterns rather than disabling rules repo-wide.

Common legacy fixes:

  • Replace createRequire / require() with ESM import (add "resolveJsonModule": true to the plugin tsconfig.json for JSON imports).
  • Use import.meta.url with fileURLToPath instead of __dirname in tests.
  • Remove stale eslint-disable comments that oxlint reports as unused.

Duplicate sanity peer variants break type-aware lint

Type-aware lint can fail (sometimes intermittently, especially on cold installs) with errors like Type 'import(".../.pnpm/sanity@X_<hashA>/...").D' is not assignable to type 'import(".../.pnpm/sanity@X_<hashB>/...").D' in dev/test-studio/src/** examples. This happens when the transferred plugin resolves sanity to a different pnpm peer-variant than the other plugins, creating an extra duplicate copy of sanity's type definitions.

To keep the plugin on the shared sanity variant, declare these in the plugin devDependencies:

  • "@types/node": "catalog:"
  • "styled-components": "catalog:" (when the plugin depends on @sanity/ui, which peers on styled-components; without the declaration pnpm may auto-install a separate copy of the peer)

Verify alignment by checking that the plugin importer's sanity version string in pnpm-lock.yaml matches other plugins (e.g. plugins/@sanity/sfcc).

Do not migrate styling during a transfer. When the plugin already uses styled-components, leave it in place for the initial port — the goal is a faithful, low-risk move. styled-components is still migrated to vanilla-extract (the styling target for every plugin), but in a separate follow-up PR, done with care to preserve visual fidelity and avoid regressions. The styled-components: catalog: alignment above applies until then. For the follow-up, use the migrate-styled-components-to-vanilla-extract skill; the sanity-plugin-best-practices styling reference (Migrating off styled-components) covers the patterns.

Tests

Vitest runs against built dist/ output (pretest builds packages automatically). Fix path resolution and module import issues in legacy test files. The plugin's own test/ suite (if present) runs via the root vitest config when included in the plugin workspace.

Changesets

Every transferred plugin needs a major changeset. Compare the transferred plugin's package.json (peer dependencies, engines, exports, and build config) against the last published version on npm. Do not copy a template blindly—only list breaking changes that actually apply.

Credit every contributor

Because the transfer PR is opened by someone else (often the 🤖 bot), the generated release would otherwise thank the wrong person. Add an author: directive so the changelog credits the people who actually built the plugin. Multiple author: lines are supported, so list everyone who worked on the plugin being ported — not just the latest author — so they all get their thanks in the release notes.

  • Use the contributors' GitHub usernames, always with a leading @ (e.g. author: @stipsan).
  • Put each author: line on its own line, before the summary text. The lines are stripped from the rendered changelog.
  • Gather contributors from the original repo's commit history, package.json author/contributors, and the README acknowledgements.
---
'package-name': major
---

author: @stipsan
author: @rexxars

Port PACKAGE-NAME to the Sanity plugins monorepo

This produces a release line thanking each contributor:

Thanks @stipsan, @rexxars! - Port PACKAGE-NAME to the Sanity plugins monorepo

See AGENTS.md → Crediting Original Authors for the full rationale.

Format

Use this format (add the author: lines from Credit every contributor above the summary):

---
'package-name': major
---

author: @stipsan
author: @rexxars

Port PACKAGE-NAME to the Sanity plugins monorepo

This major release includes several breaking changes as part of the migration to the monorepo:

- **React Compiler enabled**: ...
- **ESM-only**: CommonJS support has been removed. The package now ships only ESM
- **React 19.2+ required**: ...
- **Sanity Studio v5+ required**: ...
- **Node.js 20.19+ required**: ...

Include additional bullets only when they apply to the plugin—for example:

  • styled-components 6.1+ required (UI plugins that use styled-components)
  • react-dom 19.2+ required (when newly added as a peer dependency)
  • Dropped Sanity v3/v4 support (when the previous peer range allowed older Studio versions)

Example for sanity-naive-html-serializer:

---
'sanity-naive-html-serializer': major
---

author: @stipsan
author: @rexxars

Port sanity-naive-html-serializer to the Sanity plugins monorepo

This major release includes several breaking changes as part of the migration to the monorepo:

- **React Compiler enabled**: The package is now built with React Compiler targeting React 19
- **ESM-only**: CommonJS support has been removed. The package now ships only ESM
- **React 19.2+ required**: Minimum React version is now 19.2 (previously ^18.3 || ^19)
- **react-dom 19.2+ required**: `react-dom` is now a required peer dependency
- **Sanity Studio v5+ required**: Minimum Sanity version is now v5 (Sanity v3 and v4 are no longer supported)
- **Node.js 20.19+ required**: Minimum Node.js version is now 20.19 (previously >=18)

PR description checklist

Put all pending transfer work in the PR description as unchecked checkboxes. Do not create README.todo.md or similar todo files in the plugin workspace—the maintainer should be able to check items off on GitHub without opening a PR to edit repo files.

Include these sections in every transfer PR:

Transfer verification

  • Trusted publishing configured: npm trust github <package-name> --file=release.yml --repository=sanity-io/plugins
  • package.json dependencies/peerDependencies/exports verified against original repo
  • LICENSE restored with updated copyright year when the original credits authors beyond Sanity.io alone
  • Test studio example wired and manually verified (pnpm dev)
  • pnpm format, pnpm knip, pnpm lint, pnpm build, pnpm test run all pass
  • Major changeset added with validated breaking changes

Maintainer follow-up

Agents cannot complete these steps themselves. Ask the maintainer to handle them:

  • Update the original repo README (<link to readme>) and replace it with: # [This plugin has moved](<new location>)
  • Transfer pending issues from the original repo to this monorepo and label them as <plugin-name>
  • Archive the original repo: <repo link>/settings

Example for sanity-naive-html-serializer:

Anything Else To Consider

  • Do not migrate styling during the transfer. Keep an existing styled-components plugin on styled-components for the initial port; defer any vanilla-extract migration to a follow-up PR using the migrate-styled-components-to-vanilla-extract skill (see the styling note above).
  • Review copied dependencies and peer dependencies carefully.
  • Run the Before Submitting a PR verification suite—not just pnpm build and pnpm dev.
  • Use pnpm dev to manually verify the test-studio example after the automated checks pass.

sanity-io의 다른 스킬

tdd
sanity-io
레드-그린-리팩터 루프를 사용한 테스트 주도 개발. 사용자가 TDD로 기능을 구축하거나 버그를 수정하려 할 때, "레드-그린-리팩터"를 언급하거나, 원할 때 사용합니다...
performance-optimization
sanity-io
애플리케이션 성능을 최적화합니다. 성능 요구사항이 있거나, 성능 회귀가 의심되거나, Core Web Vitals 또는 로드 시간이…
content-experimentation-best-practices
sanity-io
콘텐츠 실험을 설계, 실행, 분석하여 전환율과 참여도를 개선하기 위한 체계적인 가이드입니다. 가설 프레임워크, 지표 선택, 표본 크기 계산, A/B 및 다변량 실험의 통계적 유의성 검정을 다룹니다. p-값, 신뢰 구간, 검정력 분석, 결과 해석을 위한 베이지안 방법에 대한 상세 자료를 포함합니다. 필드 수준에서 변형을 관리하고 외부 시스템과 연결하기 위한 CMS 통합 패턴을 제공합니다.
content-modeling-best-practices
sanity-io
구조화된 콘텐츠 모델링 가이드로, 스키마 설계, 재사용성, 멀티채널 전달을 다룹니다. 콘텐츠를 페이지가 아닌 데이터로 취급하고, 단일 진실 공급원을 유지하며, 미래 채널을 고려한 설계와 편집자 워크플로우 최적화를 위한 핵심 원칙을 포함합니다. 참조와 임베디드 객체 간의 결정 프레임워크, 관심사 분리, 콘텐츠 재사용 패턴을 제공하며, 플랫, 계층적, 패싯 접근 방식에 대한 분류 및 분류 체계 가이드를 포함합니다. 다음에 적용됩니다...
portable-text-conversion
sanity-io
HTML 및 Markdown 콘텐츠를 Sanity용 Portable Text 블록으로 변환합니다. 레거시 CMS에서 콘텐츠를 마이그레이션하거나 HTML 또는 Markdown을 Sanity로 가져올 때 사용합니다.
portable-text-serialization
sanity-io
Portable Text를 React, Svelte, Vue, Astro, HTML, Markdown 및 일반 텍스트로 렌더링하고 직렬화합니다. 모든 프론트엔드에서 Portable Text 렌더링을 구현할 때 사용합니다…
sanity-best-practices
sanity-io
Sanity CMS 개발을 위한 포괄적인 모범 사례 및 통합 가이드로, 다양한 프레임워크와 주제를 다룹니다. Next.js, Nuxt, Astro, Remix, SvelteKit, Angular 등 10개 이상의 프레임워크 통합을 프레임워크별 패턴 및 설정 가이드와 함께 포함합니다. 스키마 디자인, GROQ 쿼리 최적화, Visual Editing, Portable Text, 이미지, TypeGen, 현지화, 콘텐츠 마이그레이션을 위한 주제 가이드를 제공합니다. 작업 유형에 따라 관련 가이드만 로드할 수 있는 빠른 참조 구조를 제공합니다.
sanity-migration
sanity-io
다른 CMS 및 콘텐츠 시스템에서 Sanity로의 마이그레이션을 계획, 구현 및 검토합니다. AEM, Adobe Experience Manager, Contentful, Strapi, Webflow, WordPress, Payload, Drupal, Markdown/MDX/frontmatter 파일, WXR/XML 내보내기, CMS API, 데이터베이스 덤프, 정적 HTML에서 Sanity로 마이그레이션하거나 리플랫폼할 때, 또는 추출, 변환, Portable Text 변환, 에셋 마이그레이션, 리디렉션, 검증 및 전환 워크플로를 설계할 때 사용합니다.
data-analysisdatabasedevelopment