Sanity Studio Upgrade
SanityOfficialPublished by Sanity
- Skill
- Workflow
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Sanity Studio upgrade planner provides a focused, repository-specific migration path for Sanity Studio projects from v3 onwards. Rather than providing a generic changelog, it inspects the current project's lockfile, configuration, and source code to identify only the breaking changes that are actually relevant. It emphasizes verification over speculation, requiring live registry lookups for versions and strictly forbidding any automated modification of the user's codebase.
What it does
- Detects the current Sanity Studio version and identifies if the project is out of scope (v2).
- Calculates the upgrade span from the current installed version to the latest release.
- Identifies applicable breaking changes based on the project's specific configuration and dependencies.
- Provides a sequence of recommended intermediate upgrade stops to isolate potential issues.
- Assesses plugin compatibility and identifies potential dependency conflicts.
- Generates a comprehensive report in the repository root for team review.
When to use it
- When you need to upgrade or modernize a Sanity Studio project from v3 or later.
- When you want to understand the specific breaking changes involved in a version bump.
- When you need to determine how far behind your current Studio version is.
- When you are troubleshooting a broken Studio environment following a previous upgrade attempt.
Advantages
- Reduces noise by filtering out breaking changes that do not apply to your specific configuration.
- Prevents common upgrade pitfalls by verifying Node.js version floors and dependency coupling.
- Provides a safe, read-only analysis that does not modify your repository files.
- Offers a structured, step-by-step plan that is easy to share with team members.
Usage examples
- “upgrade sanity studio”
- The agent inspects the local lockfile, determines the current version, and generates a SANITY-UPGRADE-PLAN.md file detailing the necessary steps to reach the latest version.
- “what breaks if we upgrade our sanity studio?”
- The agent analyzes the current configuration and dependencies to list only the specific breaking changes that will impact the project, excluding irrelevant ones.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/sanity-io/sanity-studio-upgrade/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip sanity-studio-upgrade.zip -d .agents/skills
Documentation by Sanity
Sanity Studio upgrade planner
Generate an upgrade plan for the Sanity Studio in the current repository.
The plan's value is subtraction. A list of every breaking change between two versions already exists; it is called the changelog, and it is not useful to someone mid-upgrade. This skill produces the much shorter list of changes that apply to this repository, plus the questions only a human can answer.
Three rules that determine whether the output is trustworthy
1. Never state a version number from memory. Look it up, and confirm it exists.
Package versions change weekly. Every version in the report must come from either the repository's lockfile (for current state) or a live registry query (for targets). If a lookup is not possible, say so in the report rather than guessing. A plan that names a stale "latest" is worse than no plan, because the reader will act on it.
There is a second, worse version of this failure: a version number that was never published at all, arrived at by assuming one package tracks another's numbering. That one fails at install. Any version you are about to describe as "lockstep" or "matches core" needs an existence check first.
The same applies to API names. An export, an import subpath, or a function signature recalled from memory is a guess, and it is a guess the reader will paste into their editor. Read it from the package's README or exports map, or mark it with an inline // VERIFY: comment at the snippet itself. See section 6 of plugins.md and section 8 of report-template.md.
2. Read and report. Never modify.
Inspect files, run read-only shell commands, query registries. Do not edit package.json, config files, or source. The reader decides what to change; a planner that edits code will be turned off. If the user explicitly asks you to perform the upgrade afterward, that is a separate task they have consented to.
Where the line actually falls, because a vague version of this rule makes an agent hesitate over commands that are fine:
Never: writing to any file in the repository, installing into it, or mutating a lockfile.
pnpm install,npm install,npm ciandnpxwithout--no-installare all out.Fine: reading files, and network reads such as
npm view, a changelog fetch, ornpm packinto a temporary directory outside the repository that you then delete.Recommended to the reader, not run by you:
pnpm install --lockfile-onlyis how a dependency prediction gets settled. It belongs in the report as a command for them to run, with what to expect from it. Do not run it yourself, because it rewrites their lockfile.
The one place this skill writes anything is unpacking a tarball to inspect type declarations, and section 6 of plugins.md shows how to keep that outside the project.
3. Separate what you verified from what you inferred.
Every finding lands in one of three buckets: confirmed applicable (you found the condition in the repo), needs a human answer (you cannot determine it from code), or not applicable (omit it entirely). Never pad the report with items you could not check. An honest short report beats a comprehensive-looking one.
One consequence is easy to miss and worth stating outright: a read-only planner has no dependency resolver, so it cannot know what a tree will contain after a change. Predictions about deduplication belong in the report as expectations with the verification command attached, never as findings. See package-coupling.md.
The verification rules, in one place
These are referred to by number throughout the reference files, so they are stated once here rather than restated in each. Everything above is R1 to R4; the rest are the specific ways those go wrong.
| Rule | Where it bites | |
|---|---|---|
| R1 | Never state a version from memory. Take current state from the lockfile, targets from a live registry query. | version-lookup.md §1 |
| R2 | Read and report. Nothing in the repository changes, nothing is installed, no lockfile is mutated. | Above, and plugins.md §6 |
| R3 | Separate verified from inferred. Never assert what a dependency tree will contain after a change; a planner has no resolver. | package-coupling.md §6, plugins.md §5 |
| R4 | Confirm every recommended version was actually published before it goes in the report. | version-lookup.md §3 |
| R5 | Every "X requires Y" names the manifest it was read from, at the version being installed at that stop. Requirements do not carry backwards across majors. | version-lookup.md §6 |
| R6 | Evaluate a version range, never read it. Anything with a ||, a <, or two comparators in one clause goes through semver.satisfies first. | version-lookup.md §6 |
| R7 | A name in an export list is not a working export. Check its declared type and any @deprecated tag; never means removed. | plugins.md §6 |
R6 and R7 exist because both have already produced confident, wrong, specific advice: a Node version reported as unsupported when it was fine, and a required code edit filed under "already satisfied". They are cheap to run and they fail silently when skipped.
Scope: v3 and later
This skill plans upgrades from Studio v3 onward. Studio v2 is out of scope and is a hard stop.
The reason is not that v2 is hard. It is that v2 to v3 is a rewrite of the Studio's configuration and plugin layer rather than a dependency upgrade: the config format changed, the "parts" system that v2 plugins and overrides were built on no longer exists, packages were consolidated, and much of the v2-era plugin ecosystem was never ported. A generated plan for that boundary would be a list of confident-sounding specifics that this skill cannot verify, handed to someone about to spend weeks on the work. That is the worst possible output.
If you detect v2, stop and report rather than planning. Step 1 covers detection and what to say. Do not write a plan file for a v2 project.
Procedure
Step 1: Establish ground truth, and check the version floor
Read references/detect.md and follow it. It lists the files to read, the commands to run, and the facts to record.
The single most common mistake is reading versions from package.json. Caret ranges are not installed versions. Get the resolved version from the lockfile.
The second most common mistake is reading them from the wrong lockfile. A repository can contain several installs that disagree, so decide which tree the plan is for, take every version fact from that tree, and name it in the report header.
If there is no Sanity Studio in this repository, say so and stop.
Then check the floor before doing anything else. If the resolved sanity major is below 3, or there is no sanity package and the project depends on v2-era packages such as @sanity/base or @sanity/desk-tool, or there is a sanity.json and no sanity.config.*, this is a v2 project. Stop there and tell the reader:
What you detected, and the evidence for it
That this skill covers v3 and later, and why v2 to v3 is a different kind of project: a rewrite of the configuration and plugin layer, not a version bump
That the right starting point is the official v2 to v3 migration guide, which they should find on the Sanity docs site rather than take from you second-hand
That every v2-era plugin needs its own compatibility check, since many were never ported
That once they are on v3, running this skill again will plan the rest of the span, which is a much smaller job
Be useful about it. A hard stop that explains itself and points somewhere is a good answer; a refusal is not. But do not soften it into a partial plan, and do not estimate the v2 to v3 work.
If both sanity.json and sanity.config.* are present, treat the resolved sanity version as authoritative. A leftover sanity.json in an otherwise v3+ project is worth mentioning as cleanup, not a reason to stop.
Step 2: Determine the span
You need two versions: from (resolved, installed) and to (the target).
Read references/version-lookup.md for how to query current versions and changelogs authoritatively.
The target is latest. Recommend it and give the reasoning. Landing short means doing the whole job and still being behind, and more importantly, current plugin versions track current core, so an older core with current plugins often produces a worse dependency tree than the newest release does. Report the target's publish date and a one-line fallback so the reader can apply constraints you cannot see, but that is disclosure, not a hedge, and it does not change the recommendation. Deviate only for a constraint the reader has actually stated, and then give the pin a review date.
State the span explicitly in the report. A v3 project and a v5.31 project are completely different jobs and the reader needs to know which one they have.
Step 3: Load only the boundaries you cross
Read references/boundaries.md first. It is a short index: the coverage bounds, the two-edge fetch rule, and a table saying which boundary files the span needs.
Then read only those files. Boundary content is split one file per major, so a span that crosses one boundary loads one file rather than all of them. A project on 5.31 crossing into v6 reads the index, boundary.v6.md and deprecations.md, and nothing else: the v4 and v5 files would cost context and invite findings that do not apply.
Each boundary.v*.md holds the crossing into that major plus the undeclared changes inside that major's line, because a span that crosses a boundary lands somewhere in the line above it and needs both.
Then read references/package-coupling.md. It applies to every span.
Step 4: Fetch what the references do not cover
references/boundaries.md declares two bounds on its within-line coverage, and both need respecting.
Fetch the changelog for any part of the span that falls above the upper bound or below the lower bound. A project starting below the lower bound needs two fetches: from its current version up to that bound, and from the upper bound to the target. The curated middle is used as-is.
The lower bound matters as much as the upper one, and it fails more quietly. Without it you will trust the file for a range it never examined and report that nothing there applies, which reads as a verified finding and is actually an unexamined gap. Never state that a range is clean unless it sits inside the declared bounds or you fetched it yourself and got real content back.
That last clause is not padding. Below the lower bound the upstream changelog does not exist at all, so the fetch returns almost nothing, and an empty fetch is not a clean range. boundaries.md says which range this affects and what to report instead. Reporting silence as "nothing applies" there is the single easiest way for this skill to produce a confident lie.
Pay particular attention to breaking changes that shipped in minor releases without being labelled as breaking. Those are the ones that surprise people, because nobody reads minor release notes across forty releases. The references list known examples; assume more exist.
Step 5: Test applicability
For each candidate change, find the condition in the repository. If you cannot determine it from code, it goes in the human questions section, not in the findings.
Examples of the difference:
"Custom auth providers now replace built-ins instead of appending" → grep the config for an
authblock. Present or absent. Determinable."Default search strategy changed, results will shift" → whether that matters depends on how editors search. Not determinable. Ask.
Prefer conditions you can actually evaluate. grep -r "data-slate" is a real test. "Do you have complex custom components?" is not.
Step 6: Resolve the dependency graph
Apply references/package-coupling.md. This is where most upgrades actually break, and it is the part a changelog cannot tell you, because it depends on which packages this project happens to depend on directly.
The rule that matters most: for any @sanity/* package the project depends on directly, check what version the target sanity release depends on and match that, rather than taking the package's own latest. Taking latest for a shared package like @sanity/ui puts two majors of it in one dependency tree, which produces duplicate-context errors and unstyled components that look like unrelated bugs.
Step 6b: Assess plugins
Read references/plugins.md and follow it whenever the project has any plugin, which is nearly always.
Plugins block more upgrades than the Studio itself does, so they get their own pass and their own section in the report. Three things to carry into it: verify every plugin's compatibility rather than assuming it from who publishes it; let ownership decide the path once something is incompatible, not the verdict; and verify the API shape of any snippet you write against the package, separately from verifying its version, because a compatible version can still have renamed the export you are about to recommend.
Step 7: Write the report
Follow references/report-template.md exactly. Write it to SANITY-UPGRADE-PLAN.md in the repository root unless the user names a different path.
Write a file rather than only printing to the terminal. The plan usually needs to reach people who are not at this keyboard: a lead, a reviewer, a support engineer. A file can go into a pull request or be pasted into a thread; terminal output cannot.
Judgment calls worth making explicitly
Recommend a sequence, not a single jump. Crossing several majors in one commit makes failures impossible to attribute. Suggest intermediate stops at the last release of each major, and say why: it isolates each set of changes.
But a stop is only real if it is reachable. Each one needs its plugin versions resolved, because a plugin peering only recent majors can make an intermediate stop impossible to install. If you cannot resolve a stop, label it provisional rather than presenting the sequence as validated. Fewer verified stops beat more hypothetical ones.
When you drop a stop, name what it costs. Skipping one is often right: a boundary whose only applicable change is a Node floor is not worth a commit of its own, and a stop that cannot be reached without a forced duplicate major is worse than no stop. But the resulting hop then crosses two boundaries at once, and that is the exact thing the sequence exists to prevent. A plan that shows the evidence for skipping and stays silent on the consequence reads as though the trade were free.
So say both halves: why the stop was dropped, and that a failure in the combined hop could originate at either boundary, so debugging it means bisecting rather than reading the plan. One sentence covers it. The reader can accept the trade once they can see it.
Size the work honestly. If the project has two files importing @sanity/ui and no custom auth, say the upgrade is small. Inflating scope to look thorough wastes the reader's week. Equally, if the project imports from sanity/_internal or has a large custom component surface, say the upgrade is substantial rather than producing a plan that makes hard work look easy.
Make the plan survive being skimmed. It will be. A multi-boundary plan runs to several thousand words, and the person reading it is about to spend a week on the work, not an afternoon studying the document. So the top of the plan carries the whole thing in one screen, everything below it is reference to be read as the work reaches it, and findings are grouped by what the reader has to do rather than by which release the change came from. The specific failure to design against: a change that fails silently, sitting in a uniform table between two cosmetic ones, at identical visual weight. Length is not the enemy; flat weighting is.
Write for the engineer who has to do the work, and describe the tree rather than the team. This plan is usually read by someone at the customer, often someone who did not make the decisions that produced the current state. Keep the evidence, the specificity and the severity exactly as strong as the facts support: softening a real blocker or a real cost is a disservice, and an engineer can tell. What to drop is the implied verdict. "The deploy pipeline builds from the caret ranges rather than the lockfile" and "whoever set this up got it wrong" contain the same finding, and only one of them gets acted on. Reserve "you" for what to do next. Stay inside the upgrade, too: an unused dependency is not an upgrade finding, and a plan that drifts into general code review spends the reader's attention on things that do not gate the work.
Name what you could not see. Monorepos hide things: a tsconfig.json that extends a base file outside the repository, a workspace root that hoists React, a CI config in another directory. If a fact you needed was out of reach, put it in the human questions section by name. "I could not read moduleResolution because your tsconfig extends a file outside this repo" is useful. Silently omitting it is not.
Do not promise roadmaps. If asked whether a deprecated API will return or be removed, describe its current documented state and stop. Never speculate about future releases.
Reference files
| File | Read when |
|---|---|
references/detect.md | Always, at step 1 |
references/version-lookup.md | Always, at step 2 and step 4 |
references/boundaries.md | Always, at step 3. Index: coverage bounds and which boundary files to read |
references/boundary.v4.md | Step 3, if the span crosses into or sits in v4 |
references/boundary.v5.md | Step 3, if the span crosses into or sits in v5 |
references/boundary.v6.md | Step 3, if the span crosses into or sits in v6 |
references/deprecations.md | Step 3, always. Short, and not tied to a boundary |
references/package-coupling.md | Always, at step 6 |
references/plugins.md | Step 6b, whenever the project has plugins |
references/report-template.md | Step 7 |
Files
- ATTRIBUTION.mdAdded by AutoGineer873 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md19.0 KiB
- references/boundaries.md4.8 KiB
- references/boundary.v4.md5.9 KiB
- references/boundary.v5.md7.2 KiB
- references/boundary.v6.md7.7 KiB
- references/deprecations.md2.5 KiB
- references/detect.md14.7 KiB
- references/package-coupling.md14.6 KiB
- references/plugins.md23.3 KiB
- references/report-template.md17.2 KiB
- references/version-lookup.md18.9 KiB
references/report-template.md
Report template
Write to SANITY-UPGRADE-PLAN.md in the repository root unless the user names a different path.
Rules for filling it in
R1 to R7 in SKILL.md apply to everything below and are not restated here. The rules in this file are the ones specific to writing the document.
Omit sections that have no content. An empty "Custom code" heading is noise. The structure below is a menu, not a form to complete.
State what is already satisfied. Requirements the project already meets belong in section 2 as one-liners. It is what tells the reader the upgrade is smaller than they feared, and it stops them re-checking what you checked.
Section 2 carries the highest cost per error in the document, because of that last clause: everywhere else a mistake is something the reader trips over, here it is an instruction not to look. The bar for "no change needed" is higher than for a finding, not lower. R7 is the one that bites here.
Never include an item you could not evaluate. It goes in the questions section. A finding implies you found something.
Never assert plugin compatibility you did not verify, in either direction. Ownership decides the path when something is incompatible, not whether it is.
Mark an unverified API shape at the snippet, not in the prose around it. Format is // VERIFY: <what to check> - <where to check it>, inline, immediately above or beside the code. A hedge two sentences later does not travel: the snippet gets copied out of the document and the caveat stays behind. See section 8 below.
Weight findings by severity, and never let the format flatten them. Severity is likelihood of breaking something multiplied by how hard it is to notice, so silent failures outrank loud ones: a build error gets fixed in ten minutes, a stylesheet that silently stops applying ships to production. Group by what the reader has to do, put silent failures at the top of their group, and demote no-action items out of the main tables.
Stay inside the upgrade. Unused dependencies, stale type packages that block nothing, and tidiness in trees the Studio does not deploy from are not upgrade findings. Leave them out or give the whole set one closing line. A plan that drifts into code review spends the reader's attention on things that do not gate the work.
Describe the state of the tree, not the decisions that produced it. "The deploy pipeline builds from the caret ranges rather than the lockfile" and "whoever set up CI misconfigured it" carry the same information; only one gets acted on. Reserve "you" for what to do next. This is about attribution, not certainty: keep the evidence and the severity exactly as strong as they are.
One tree per plan. Name the lockfile every version came from in the header and take all of them from that tree. A version read from a sibling tree looks authoritative and describes a different install.
Length is a symptom, not a target. Never trim a finding that carries file-level evidence to hit a word count. Two checks cut the length that should not be there:
A finding without file-level evidence is changelog leakage. If "applies because" names no file, line, script, or grep result, applicability was never tested. Remove it or move it to the questions.
More than roughly fifteen action rows on a three-boundary span means re-test applicability before accepting the number.
Link sources. Every non-obvious claim carries a link to the changelog entry or doc it came from.
Template
# Sanity Studio upgrade plan
**Repository:** <path or name>
**Planning for:** <the tree this plan covers, e.g. `studio/` via `studio/pnpm-lock.yaml`. Name the lockfile every version below came from. If the repository has other trees, list them and their `sanity` versions here too.>
**Generated:** <date>
**Current:** sanity <resolved version, from that lockfile>
**Target:** sanity <version> <`latest`, with its publish date. Recommend `latest` unless the reader has stated a constraint; if they have, say so and give the pin a review date. Add one clause naming the fallback so they can overrule you, without building out a second plan for it. **If `latest` published within the last few days, give the date rather than "recently", state what differs in the previous minor, and put the soak-time choice in section 9** rather than leaving it as a header aside. See section 5 of `version-lookup.md`.>
**Span:** <n> major boundaries: <list them>
> Version data retrieved from the npm registry on <date>. Re-verify before acting on this plan if significant time has passed.
## Start here
<**Required, and it must fit on one screen.** Everything below this block is reference material to be read section by section as the work reaches it. This block is the plan.
It contains four things and nothing else:
1. **The sequence**, one line per stop: the version, and the three-to-six-word reason for the stop. No detail; section 10 has it.
2. **Anything that invalidates the plan if skipped**, stated first if it exists. A deploy pipeline that builds a different tree, an unreachable stop, a blocking plugin. One line each.
3. **The changes that fail silently**, by name. These are the reason this block exists: they are the items a reader most easily misses in a table and most expensively discovers in production.
4. **What needs a decision from a human before the work starts**, as a pointer to section 9 with the count. Not the questions themselves.
Introduce nothing here that is not covered below, and repeat nothing here that does not need to be seen first. If this block cannot be written in a screen, the plan has not decided what matters.>
## 1. Summary
<Two or three sentences of sizing, then the two or three things that make this more than a dependency bump. This is the narrative version for someone deciding whether to schedule the work, where the Start here block is the work list for whoever does it, so do not restate that block.
If the honest answer is "a dependency bump plus three edits," say that. If it is "a rewrite of the configuration layer," say that. Frame the hard parts as consequences rather than faults: "fix this first or every stop below is theoretical" says what is at stake without telling anyone they made a mistake.>
## 2. Already satisfied
<One line each, for requirements the project already meets. Include the evidence.>
- Node.js: requirement is >= X, project is on Y
- React: requirement is >= X, project resolves to Y
- No `auth` block in config, so the v6 auth provider change does not apply
- No `data-slate` references, so the 6.3.0 Portable Text DOM change does not apply
## 3. Needs attention before you start
<Open the section with one sentence saying why it is here, in the report itself and not only in this template: these conditions exist in the current tree before any version changes, they may already be causing behavior the team has noticed, and leaving them in place adds variables to every step below. Without that sentence the reader meets a list of faults with no stated purpose, which is the wrong first impression and the wrong reading of what the list is for.>
<Include only what affects the upgrade. Qualifying: duplicate majors of a shared package, a plugin already violating its own peers, a deploy pipeline building from a different manifest or lockfile than the tree being planned, undeclared imports resolving only through hoisting, relaxed peer resolution masking conflicts. Not qualifying: unused dependencies, stale type packages that block nothing, tidiness in a tree the Studio does not deploy from. Those can have one closing line between them, or none.>
<**Order by consequence and say which is load-bearing.** If one of these makes the rest of the plan theoretical when skipped, it goes first and says so plainly. The others follow. A flat list of seven equally weighted items reads as an audit; the same seven, with the one that gates everything named as such, reads as a plan.>
<For each: what the current state is, the evidence, and what it affects downstream. Describe the tree, not the decisions behind it. Give specific versions and what pulled each one in.>
## 4. Requirements to meet
<Hard floors that are not yet met. Node, React, TypeScript settings. Each with where it needs changing: engines, .nvmrc, CI, build host. A requirement the project already satisfies goes in section 2, not here.>
## 5. Breaking changes that apply
<**Group by what the reader has to do, not by which boundary the change came from.** Boundary is a column, not a heading. Grouping by boundary mirrors the changelog's structure rather than the work's, and it puts a build-breaking import next to a cosmetic default at identical weight, which is exactly how the important row gets missed. The boundary still matters for sequencing, so keep it visible per row and let section 10 order the work.>
<For each item: what changed, why it applies here (the evidence you found), what to do, and a source link. Include the failure mode when it is non-obvious.>
### Breaks the build or the Studio
<Loudest and cheapest to find, but still first because nothing else can be tested until these are done. Failures that are silent go at the top of this group and say so, since a silent failure outranks a loud one of the same size.>
| Change | Boundary | Applies because | Action |
| --- | --- | --- | --- |
| ... | ... | ... | ... |
### Changes behavior, needs a decision
<Defaults that flipped, strategies that changed, anything that writes different data or shows editors something different. Each one needs an owner or a decision, not just an edit. Cross-reference section 9 where the decision belongs to a human.>
| Change | Boundary | Applies because | Decision |
| --- | --- | --- | --- |
| ... | ... | ... | ... |
### Worth knowing, no action
<Everything that applies but requires no change: informational defaults, deprecations still functional at the target, items already covered by another section. **Keep these out of the tables above.** One line each, as a plain list, so they are on the record without competing for attention with work that has to happen.>
- <version, boundary> ... (informational)
## 6. Dependency changes
<A single code block the reader can diff against their package.json. Comment each changed line with the old value and the reason. Include additions for missing peer dependencies.>
```jsonc
"dependencies": {
"sanity": "<version>", // was <version>
...
}
```
<Then the dedupe verification command and what to expect from it.>
## 7. Plugins
<A row per plugin. The owner column states what the registry `repository` field showed, not a support level. Keep compatible plugins to one line each; they are routine.>
| Plugin | Installed | Latest | Peer `sanity` | Owner | Verdict |
| --- | --- | --- | --- | --- | --- |
| ... | ... | ... | ... | `sanity-io` / third party / private | compatible, bump to X / **blocked** / needs a decision |
<Then one short subsection per blocked plugin: what it is used for, why it blocks, and the recommended next step. Use a heading that makes ownership unambiguous, so a Sanity-maintained gap is not mistaken for the reader's homework.>
### Blocked on a Sanity-maintained plugin: <name>
<Installed version, latest version and publish date, its declared peer range, the target it does not accept, and what breaks without it. State that this is being raised with Sanity rather than implying a date. Give only the honest interim options.>
### Blocked on a third-party plugin: <name>
<The evidence: last publish date, peer range, whether the repo is archived, whether an issue or PR already tracks the target. Then the recommended step from the ladder, including whether the plugin is still needed at all.>
## 8. Code changes
<Only if there are any. File path, then the specific edit. Show before and after for anything mechanical. If there are many instances of one pattern, give the count and one example rather than listing all of them.>
<**Every snippet whose API shape you did not read from the package carries an inline marker.** Verified snippets carry nothing; the absence of a marker is the claim that you checked. Format:>
```ts
// VERIFY: export name and signature - check the plugin README and its
// package.json `exports` map before running this
import {someHelper} from 'some-plugin/subpath'
```
<Use `VERIFY` rather than `UNVERIFIED`. The information is identical and the imperative is more useful: it tells the reader what to do about it, and it does not read as a disclaimer about the document as a whole.>
<Do not replace the marker with a sentence in the surrounding paragraph. The snippet is what gets copied; the paragraph is not.>
## 9. Questions only you can answer
<The judgment half. Each question should say why it matters and what changes based on the answer. This section is the honest boundary of what static analysis can determine, and it is usually the most valuable part of the plan for whoever has to act on it.>
Typical entries:
- Which Node version runs in CI and on the build host? Detected <X> locally, which may not be the same.
- Do editors find documents by typing the name of a related record? The v6 search default change stops reference-traversed preview fields contributing to matching.
- <Any fact that was out of reach: a tsconfig extending outside the repo, a hoisted dependency, a CI config elsewhere. Name it specifically.>
- Is content consumed by anything that cannot be updated quickly, such as a mobile app or a partner integration? Two default changes write new characters and new marks into stored content.
- Are there plugins from a private registry not visible in the public dependency data?
## 10. Suggested sequence
<Numbered, with intermediate stops at the last release of each major and the reasoning for each stop. Include where to verify before proceeding. For multi-boundary spans, make the stops explicit; for a single boundary, this can be four lines.>
<**A stop that accepts a duplicate major has to show the version walk that justifies it.** Name the candidate versions checked and what each depends on. Without that, an accepted duplicate is indistinguishable from a plugin set that was taken at `latest` and rationalized, which is the most common defect in a multi-stop sequence. See section 5 of `plugins.md`.>
<**Do not schedule work that depends on a working Studio UI at a stop with a duplicate theming package.** A content migration, or any step verified by looking at the Studio, belongs at a stop with a single `@sanity/ui` major.>
<**Every stop needs its plugin versions named, or an explicit note that the stop is provisional.** A stop that says "bump plugins to versions that accept this major, check at execution time" is not a validated step: it hands back the hardest unanswered question in the plan. If you could not resolve a stop, label it provisional and say what needs checking. See section 5 of `plugins.md`.>
<**A skipped stop needs its cost stated, not just its justification.** Dropping a boundary whose only applicable change is a Node floor, or one that cannot be reached without a forced duplicate, is frequently the right call, and the evidence for it belongs here. But the hop that results crosses two majors at once, so add the consequence in the same breath: a failure in that hop could come from either boundary, and isolating it means bisecting rather than consulting this plan. Showing the evidence and omitting the cost makes the trade look free.>
## 11. Test checklist
<Derived from what this repository actually has, not a generic list. If there are no custom document actions, do not include a line about testing them. Split into build-and-types and functional.>
**Build and types**
- [ ] ...
**Functional**
- [ ] ...
## 12. Sources
<Every changelog entry, migration guide, and registry query the plan relied on. The reader should be able to check your work.>What a good report is not
Not the changelog. If the report contains items whose applicability was never tested, it has failed at its only real job. The reader can already read the changelog.
Not padded with generic advice. "Test thoroughly before deploying" adds nothing. "Publish a document that previously failed validation, because 6.7.0 changed URI validation with custom schemes" is worth reading.
Not an audit of the repository. The plan reports the current state only where it bears on the upgrade. Every finding that does not gate the work spends attention that the findings which do gate it needed, and a document that opens with a long list of everything wrong reads as a judgment on the team rather than a route through the work.
Not flat. A plan where every finding has the same visual weight has pushed the triage back onto the reader, which is the job it was supposed to do for them. If the most dangerous item in the document is not findable in the first thirty seconds, the structure has failed regardless of how accurate the content is.
Not falsely reassuring. If the project imports from sanity/_internal, or has forty @sanity/ui import sites, or crosses three majors, the report should say the upgrade is substantial. A plan that makes hard work look easy fails the reader more expensively than one that overestimates.
Not silent about its own gaps. If a registry lookup failed, if a tsconfig could not be resolved, if the CI config was not found, the report says so. The reader can fill a named gap; they cannot fill one they do not know about.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Node.js
The author says: Requires network access to the npm registry and sanity.io docs for version and changelog lookups
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Sanity
- Publisher
- Sanity (Official)
- Source
- sanity-io/agent-toolkit · skills/sanity-studio-upgrade · commit 3ed3a14
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Sanity or Sanity.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download sanity-studio-upgrade.zip