sanity-canvas-skill
v0.3.2
Published
Read and write Sanity Canvas documents. Markdown ↔ Portable Text conversion with diff-based push.
Readme
Canvas Writer
Create and update Sanity Canvas documents programmatically.
Includes a reusable TypeScript library for markdown ↔ Canvas Portable Text conversion, and a CLI tool for reading/writing Canvas documents directly.
How It Works
Canvas documents live in a resource (not a regular Sanity project/dataset). The CLI uses @sanity/client with a special resource config to talk directly to the Canvas API.
The conversion library handles mapping between standard markdown and Canvas-specific Portable Text block types:
| Markdown | Canvas PTE Type |
|---|---|
| Paragraphs, headings, blockquotes | block (with style) |
| Bold, italic, code, strikethrough | span marks (strong, em, code, strike-through) |
| Bullet/numbered lists | block with listItem |
| Links [text](url) | link annotation with href |
| Code blocks ```lang ``` | canvasCode (lines as nested blocks) |
| Images  | canvasImage (ephemeral src) |
| Horizontal rules --- | canvasDivider |
What an Agent Needs From the User
To write to Canvas, an agent needs two things:
A Sanity auth token — a global token (not project-scoped). Set as
SANITY_TOKENenvironment variable. The user can generate one at sanity.io/manage.A Canvas resource ID — identifies which Canvas workspace to write to. The user can find this by:
- Going to
canvas.sanity.ioand looking at the URL path, OR - Using the Canvas API:
GET https://api.sanity.io/vX/canvases?organizationId={orgId}returns resources with anidfield.
- Going to
That's it. With those two values, the agent can create, read, update, and delete Canvas documents.
Setup
# Clone and install
git clone [email protected]:snorrees/canvas-writer-studio.git
cd canvas-writer-studio
pnpm install
# Set your Sanity token
export SANITY_TOKEN="your-global-sanity-token"CLI Usage
All commands require --resource <id> to specify the Canvas resource.
# List all documents
pnpm canvas --resource <resourceId> list
pnpm canvas --resource <resourceId> list --search "query"
# Read a document
pnpm canvas --resource <resourceId> read <docId>
# Create a new document from markdown
echo "# Hello World" | pnpm canvas --resource <resourceId> create "My Document"
# Set (replace) content from markdown
cat article.md | pnpm canvas --resource <resourceId> set <docId> content
# Set (replace) notes from markdown
cat notes.md | pnpm canvas --resource <resourceId> set <docId> notes
# Set title
pnpm canvas --resource <resourceId> set <docId> title "New Title"
# Append to content
cat extra.md | pnpm canvas --resource <resourceId> append <docId> content
# Append to notes
cat extra.md | pnpm canvas --resource <resourceId> append <docId> notes
# Delete a document
pnpm canvas --resource <resourceId> delete <docId>Library API
The conversion functions can be imported directly for use in other tools:
import {markdownToCanvas} from './src/lib/markdownToCanvas'
import {canvasToMarkdown} from './src/lib/canvasToMarkdown'
// Markdown → Canvas Portable Text blocks
const blocks = markdownToCanvas('# Hello\n\nA paragraph with **bold**.')
// Canvas Portable Text blocks → Markdown
const markdown = canvasToMarkdown(blocks)Development
# Run tests (37 tests covering all block types + roundtrip)
pnpm test
# Type check
pnpm typecheck
# Regenerate types after schema changes
pnpm typegen
# Lint
pnpm lint
# Build Studio
pnpm build
# Deploy Studio
pnpm deployProject Structure
src/
lib/
markdownToCanvas.ts # Markdown → Canvas PTE conversion
canvasToMarkdown.ts # Canvas PTE → Markdown conversion
__tests__/
canvasMarkdown.test.ts # 37 vitest tests
scripts/
canvas-write.ts # CLI tool
schemaTypes/ # Canvas document schema (mirrors sanity-io/canvas)
components/
SyncToCanvasInput.tsx # Studio sync component (browser-side)
structure.ts # Custom Studio structure
sanity.types.ts # Generated types (via pnpm typegen)
sanity.config.ts # Studio config
sanity.cli.ts # CLI config + typegen config
schema.json # Extracted schema (for typegen)Studio
This repo also includes a Sanity Studio deployed at canvas-writer.sanity.studio. The Studio mirrors the Canvas schema and includes a sync component that can push documents to Canvas from the browser. The CLI approach is generally more useful for agents.
