This document helps AI agents work successfully with the Sanity monorepo.
- Node.js: v24 or latest LTS
- Package Manager: pnpm v10+ (exact version managed via
packageManagerfield in package.json)
# Install dependencies (pnpm ONLY - enforced)
pnpm install
# Build all packages (required before testing)
pnpm build
# Run dev studio (requires auth, see below)
pnpm dev
# Format code (MUST pass CI)
pnpm chore:format:fix
# Fix all lint issues (MUST pass CI)
pnpm lint:fix
# Run tests
pnpm test
# Update snapshots if tests fail due to expected changes
pnpm test -- -u
# Type check
pnpm check:typesThese checks run on every PR and must pass:
| Check | Command | Notes |
|---|---|---|
| Format | pnpm check:format |
Uses Prettier. Fix with pnpm chore:format:fix |
| Oxlint | pnpm check:oxlint |
Fast Rust-based linter. Fix with pnpm chore:oxlint:fix |
| ESLint | pnpm lint |
Full linting. Fix with pnpm chore:lint:fix |
| Type Check | pnpm check:types |
TypeScript via tsgo + turbo |
| Unit Tests | pnpm test |
Vitest, sharded in CI |
| Export Tests | pnpm test:exports |
Ensures ESM/CJS/DTS work |
| Dep Check | pnpm depcheck |
Finds unused/missing deps |
| PR Title | Conventional commits | e.g., feat(scope): description |
Run these commands to avoid CI failures:
# Fix all formatting and lint issues
pnpm lint:fix
# Verify tests pass (build first if needed)
pnpm build && pnpm testIf tests fail due to expected snapshot changes, update them:
pnpm test -- -uSnapshot files are located in __snapshots__ directories alongside test files.
sanity/
├── packages/
│ ├── sanity/ # Main Sanity studio package
│ ├── @sanity/ # Scoped packages (cli, types, schema, etc.)
│ └── @repo/ # Internal tooling (eslint-config, test-config, etc.)
├── dev/ # Development studios for testing
│ └── test-studio/ # Primary dev studio (pnpm dev runs this)
├── e2e/ # End-to-end Playwright tests
├── perf/ # Performance testing
└── examples/ # Example studios
packages/sanity- Core studio package with all UI componentspackages/@sanity/types- TypeScript type definitionspackages/@sanity/schema- Schema compilationpackages/@sanity/mutator- Document mutation logic
- Package Manager: pnpm (version 10.x, enforced via
preinstall) - Build Orchestration: Turbo (caches builds)
- Versioning: Lerna-lite with conventional commits
pnpm build # Build all packages
pnpm watch # Watch mode for developmentpnpm dev # Starts dev studio at http://localhost:3333Note: The dev studio requires Sanity user authentication in the browser. It's a Vite application that communicates with Sanity API endpoints, so you'll need to log in with a Sanity account when you access http://localhost:3333 to use the studio.
This section clarifies what requires authentication and what doesn't—critical for AI agents to avoid getting stuck on auth flows.
Unit tests run in jsdom with mocks and do not require any authentication:
# Build first (required), then run all tests
pnpm build && pnpm test
# Run a single test file (IMPORTANT: use vitest directly with --project to avoid running all tests)
pnpm vitest run --project=sanity packages/sanity/src/core/hooks/useClient.test.ts
# Run a single test file with verbose output
pnpm vitest run --project=sanity --reporter=verbose packages/sanity/src/core/hooks/useClient.test.ts
# Watch mode for iterative development
pnpm test -- --watch
# Run tests for a specific package
pnpm test -- --project=sanityImportant: Do NOT use pnpm test -- path/to/file.test.ts for running a single file — it runs all tests across all projects. Use pnpm vitest run --project=<project> <path> instead.
Components that need auth context use createMockAuthStore in tests, so no real authentication is needed. This is the recommended way to verify most code changes.
pnpm dev # Starts at http://localhost:3333- Requires browser authentication on first visit—you'll be prompted to log in with a Sanity account
- Connects to a real Sanity project (configured in
dev/test-studio/sanity.config.ts) - Uses staging API by default (
api.sanity.work) - Session persists in browser, so subsequent visits won't require re-authentication
Use the dev studio when you need to:
- Visually verify UI changes
- Test real document editing workflows
- Debug issues that only appear with real data
E2E tests require authentication tokens. Add these to .env.local in the repo root:
SANITY_E2E_SESSION_TOKEN=<your-token>
SANITY_E2E_PROJECT_ID=<project-id>
SANITY_E2E_DATASET=<dataset-name>How to get a token:
# Option 1: Use your CLI token
sanity login
sanity debug --secrets # Look for "Auth token"
# Option 2: Create a project token at https://sanity.io/manage
# Navigate to: Project Settings → API → Tokens → Add API tokenThen run E2E tests:
pnpm e2e:build # Build E2E studio
pnpm test:e2e # Run E2E tests
pnpm test:e2e --ui # Interactive modeNote: E2E tests are typically run in CI, not locally during development. Most changes can be verified with unit tests.
What requires authentication:
- Running the dev studio (
pnpm dev) - E2E tests (
pnpm test:e2e) - Any command that connects to Sanity APIs
What does NOT require authentication:
- Building packages (
pnpm build) - Running unit tests (
pnpm test) - Linting and formatting (
pnpm lint,pnpm lint:fix) - Type checking (
pnpm check:types)
Recommendation: For most code changes, use pnpm build && pnpm test to verify correctness. This covers the vast majority of development tasks without any auth setup. Only use the dev studio when visual verification is specifically needed.
Coding standards are enforced by oxlint and eslint. Check your code with:
pnpm lint # Check for issues
pnpm lint:fix # Auto-fix issuesAll packages use ESM ("type": "module"). TypeScript strict mode is enabled.
pnpm test # Run all tests
pnpm test -- --watch # Watch mode
pnpm test -- -u # Update snapshots
pnpm test -- --project=sanity # Run specific projectTests require a build first because some tests use compiled output:
pnpm build && pnpm testpnpm e2e:build # Build E2E studio
pnpm test:e2e # Run E2E tests
pnpm test:e2e --ui # Interactive modeHusky runs lint-staged on commit, which:
- Runs Prettier on staged files
- Runs oxlint on staged
.js/.ts/.tsxfiles
If the hook fails, run pnpm lint:fix to fix issues.
# Add to specific package
pnpm --filter sanity add <package>
# Add to root (dev dependency)
pnpm add -w -D <package>- Create test file next to source:
MyComponent.test.tsx - Use existing test patterns from similar files
- Run
pnpm test -- MyComponentto verify
When making intentional changes that affect snapshots:
# Update all snapshots
pnpm test -- -u
# Update specific test's snapshots
pnpm test -- -u MyComponentReview snapshot changes carefully before committing.
This repo uses conventional commits for automated releases.
PR titles are validated by CI using the semantic-pull-request action. A PR with a non-conforming title will fail CI.
type(scope): lowercase description without special characters
- Type is required and must be one of:
feat,fix,chore,docs,refactor,test,perf,ci - Scope is required and should be the package or area affected (e.g.,
groq,cli,form,deps) - Description must start with a lowercase letter
- No backticks, quotes, or markdown in the PR title — keep it plain text
- Use
fixfor bug fixes,featfor new features,chorefor maintenance tasks
fix— Fixes a bug or resolves an issue (e.g.,fix(groq): resolve CJS type export issue)feat— Adds new functionality (e.g.,feat(form): add array input component)chore— Maintenance, dependency updates, CI changes (e.g.,chore(deps): update dependencies)docs— Documentation only (e.g.,docs(readme): improve installation instructions)refactor— Code restructuring without behavior change (e.g.,refactor(store): simplify document subscription logic)test— Adding or updating tests (e.g.,test(validation): add edge case coverage)perf— Performance improvements (e.g.,perf(search): optimize query execution)ci— CI/CD changes (e.g.,ci(e2e): add retry logic to flaky tests)
# ✅ Good PR titles
fix(groq): resolve CJS type export issue
feat(form): add new array input component
chore(deps): update dependencies
# ❌ Bad PR titles
feat(groq): add `types` condition # no backticks allowed
Fix(cli): Handle missing config # type must be lowercase, description must start lowercase
added new feature # missing type and scope
Always create PRs as drafts first.
# Create a draft PR — title MUST follow conventional commit format
gh pr create --draft --title "fix(scope): description" --body "..."Workflow:
- Agent creates draft PR - Push changes and open as draft
- Prompter reviews - The person who requested the changes reviews the draft
- Mark ready for review - Once the prompter approves, mark PR as ready:
gh pr ready - Team reviews - Team members review and approve
This ensures the person who prompted the changes can verify correctness before involving the broader team.
If you're asked to do something not documented here, update this file.
When working on a PR and you're asked to:
- Run a command that isn't in this guide
- Follow a workflow that isn't documented
- Fix something using a non-obvious process
Add that knowledge to this AGENTS.md file as part of the same PR. This keeps the guide accurate and helps future agents (and humans) avoid the same gaps.
Example: If asked "run the e2e tests for just the form inputs", and that's not documented, add it to the Testing section before completing the task.
# Clean everything and rebuild
pnpm clean && pnpm install && pnpm build- Ensure you've built:
pnpm build - Check if snapshots need updating:
pnpm test -- -u - Run specific test for better output:
pnpm test -- <test-name>
# Fix all lint issues
pnpm lint:fix
# Check what would be fixed (dry run)
pnpm check:format
pnpm check:oxlintKey env vars used in development:
SANITY_STUDIO_PROJECT_ID- Project ID for dev studioSANITY_STUDIO_DATASET- Dataset for dev studioSANITY_INTERNAL_ENV- Internal environment flag
See turbo.json for full list of environment variables that affect builds.
- CONTRIBUTING.md - Full contribution guidelines
- CODE_OF_CONDUCT.md - Community guidelines
- packages/sanity/README.md - Main package docs