feat: configure agent skills as part of sanity init#1079
Conversation
|
Claude finished @jonahsnider's task in 2m 24s —— View job Review
Findings1. Prompt wording is misleading in Suggest either parameterizing the message (pass through 2. Bugbot finding #1 is stale 3. The comment says this is because the cwd may not exist yet during init. A safer pattern: let init create the dir as part of normal project bootstrap, and have 4. Init now has a soft external dependency on 5. Test coverage gap — 6. Minor: dead mock in 7. Changeset Direct answer to the PR question
I'd recommend keeping |
📦 Bundle Stats —
|
| Metric | Value | vs main (f0906a0) |
|---|---|---|
| Internal (raw) | 2.1 KB | - |
| Internal (gzip) | 799 B | - |
| Bundled (raw) | 10.97 MB | -98 B, -0.0% |
| Bundled (gzip) | 2.06 MB | -24 B, -0.0% |
| Import time | 837ms | -12ms, -1.5% |
bin:sanity
| Metric | Value | vs main (f0906a0) |
|---|---|---|
| Internal (raw) | 975 B | - |
| Internal (gzip) | 460 B | - |
| Bundled (raw) | 9.84 MB | - |
| Bundled (gzip) | 1.77 MB | - |
| Import time | 2.01s | +6ms, +0.3% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — @sanity/cli-core
Compared against main (f0906a04)
| Metric | Value | vs main (f0906a0) |
|---|---|---|
| Internal (raw) | 95.5 KB | -721 B, -0.7% |
| Internal (gzip) | 22.5 KB | -40 B, -0.2% |
| Bundled (raw) | 21.60 MB | -721 B, -0.0% |
| Bundled (gzip) | 3.42 MB | -93 B, -0.0% |
| Import time | 792ms | +4ms, +0.5% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — create-sanity
Compared against main (f0906a04)
| Metric | Value | vs main (f0906a0) |
|---|---|---|
| Internal (raw) | 976 B | - |
| Internal (gzip) | 507 B | - |
| Bundled (raw) | 50.7 KB | - |
| Bundled (gzip) | 12.6 KB | - |
| Import time | ❌ ChildProcess denied: node | - |
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
8576c1f to
f8d67c8
Compare
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fffa215. Configure here.
…x or Claude Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
|
@jonahsnider could you address CI checks and bot review findings first? |
…s to `skills` agents Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
Signed-off-by: Jonah Snider <jonah@jonahsnider.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Nice job, I've got a couple of questions around this but mainly the UX:
The proposed flow of sanity init would still show something like this as I understand it:
? Configure Sanity MCP and agent skills for your editor?
◉ Cursor
◉ Claude Code
◯ VS Code (missing credentials)
A few issues:
a) The prompt conflates two things with very different scopes.
MCP writes to global config (~/.cursor/mcp.json, ~/.claude.json). Skills writes to the project dir. The user can't tell from "Configure Sanity MCP and agent skills for your editor?" that one of these is happening to their home directory and the other to their new project. No way to separate them either — it's one checkbox per editor.
b) Already-MCP-configured editors silently re-appear, with no explanation.
The "actionable" predicate now includes editors that already have MCP set up globally, because they still need project-local skills. Those editors show up in the prompt with no label distinguishing them from unconfigured ones — getEditorLabel only handles auth expired / missing credentials, not "MCP done, skills pending". So a user who already configured MCP last week sees Cursor in the list and doesn't know what selecting it will do.
c) No success/preview text explains what happened.
After install you see:
✓ MCP configured for Cursor
✓ Installed Sanity agent skills for cursor
Two lines, lowercase agent name on the second one, no indication that skills landed in ./my-project/ vs MCP landing in ~/.cursor/. Users probably puzzle out the global-vs-local distinction once they look around.
d) --mcp / --no-mcp now controls both, as you've already noted.
Doubles down on the same conflation.
I would split these out to 2 separate questions and make skills more generic, MCP questions stays as is and "Install Sanity skills for your editors" is a single yes or no question, if yes we install so they'll work in all detected editors (it's all project level anyway) not options to install skills for each individual editor.
Also to answer the other question in your PR description about adding npx skills as a dependency:
I think we should add skills as a dependency here. We are directly calling it, so we should pin it, manage supply-chain risk, avoid "cold start" issue of downloading it during init etc It is fairly chunky 433 kB addition to our current 3.87 MB bundle but yaml is already a dep of ours so it dedupes making it a little smaller.
If we need it we should add it as a proper dep though IMO.
Happy to discuss this sync or in Slack.
Also not pulled down and tested but will do when everything is green :)
| "@commitlint/types": "^20.4.0", | ||
| "@eslint/compat": "catalog:", | ||
| "@sanity/eslint-config-cli": "workspace:*", | ||
| "@vercel/detect-agent": "^1.2.3", |
There was a problem hiding this comment.
nit: I can only see this being used in the vitest config, do we need to add a new dep for this? (It's only dev dep so nit)
| try { | ||
| // The cwd may not exist yet when called during `sanity init` (project | ||
| // bootstrap happens later). Create it so `npx` doesn't bail with ENOENT. | ||
| await fs.mkdir(cwd, {recursive: true}) |
There was a problem hiding this comment.
If I understand this correctly, we're installing the skills "project" level not global and doing this work before pulling the template down?
If we create the directory here and add skills, could this conflict / break the template pulling down? I thought you got an error if the directory wasn't empty.
Apologies if tested or misunderstood but worth double checking this
I think we should probably invert this and ad the skills after the project has been pulled down and inited
|
Marking this a draft for now since I don't have time to follow up on the review feedback - @jwoods02 if you could create a followup PR with your implementation that'd be great (feel free to base it on this one if that's helpful) |
|
Closing in favour of #1124 |


Description
Configure agent skills alongside the MCP server when running
sanity init. The same logic is reused across both MCP setup and the skills setup for selecting what agents/editors, so that you only get asked once.Internally this is just shelling out to the
skillsCLI, which is what Neon'sneonctlCLI does as well.What to review
--mcpand--no-mcpare a little confusing, since they now also decide whether agent skills are added. Should we deprecate these flags and add new ones? Keep same?npx skillsor does it make sense to addskillsas a dependency of the CLI? Should be a lot faster since we are no longer waiting fornpxto downloadskills, but means we need to stay on top ofskillsupdates via RenovateTesting
TODO: write a brief guide on how to test locally, including a note about Sanity internal env
Todo list for myself
sanity inittosanity skillscommand for adding and updating agent skills in existing projectsNote
Medium Risk
Adds best-effort execution of an external
npx skills addcommand duringsanity init, which can affect init reliability/UX and write files into the new project directory. MCP setup logic is refactored to handle a newcwd/skills path and updated prompting/telemetry, increasing behavioral surface area.Overview
sanity initnow passes the new projectoutputPathintosetupMCP, which in turn installs Sanity agent skills (vianpx skills add sanity-io/agent-toolkit) for the selected/detected editors when acwdis provided.MCP setup is updated to track
skillsCliAgentmappings per editor, adjust the prompt copy, avoid writing MCP config for already-configured editors while still installing project-local skills during init, and surface skills-install failures separately without aborting MCP setup.Telemetry/test infrastructure is updated to record
installedSkillsCliAgents, add unit tests for the new skills installer and MCP/skills interactions, and switch Vitest “agent” detection to@vercel/detect-agent.Reviewed by Cursor Bugbot for commit d3b61c2. Bugbot is set up for automated code reviews on this repo. Configure here.