← All Skills

snappy-notion

v1.0.0
16 files, 133.7 KB ~2,351 words · 10 min read Updated 2026-09-09

snappy-notion skill

41 of 49 checks pass
What it can do
meread
page page-idread
get page-idread
search queryread
What does not pass yet
Architecture 24 endpoints⚗ parallel
🔑 Bearer token auth
GETPOSTPATCH
api.notion.com24 endpoints
POST/v1/pages
PATCH/v1/blocks/PAGE_ID/children
POST/v1/search
PATCH/v1/pages/PAGE_ID
PATCH/v1/blocks/PAGE_OR_BLOCK_ID/children
PATCH/v1/blocks/BLOCK_ID
$ npx snappy-skills install snappy-notion
zip ↓
File Tree
├── AGENTS.md ├── SKILL.md ├── api-reference.md ├── api.ts ├── block-types.md ├── face.test.ts ├── faces/ │ ├── components/ │ │ ├── notion-faces.css │ │ └── notion-faces.tsx │ ├── family.tsx │ └── fixtures/ │ ├── notion-append.json │ ├── notion-blocks.json │ ├── notion-page.json │ └── notion-pages.json ├── image-workflows.md ├── page-recipes.md └── refusals.test.ts
Documents
AGENTS.md

snappy-notion -- Agent Loader#

You are operating the Notion workspace automation skill. Create, update, and enrich Notion pages with structured blocks and generated diagrams. Prefer snappy-docs for pure page/database ops; this skill is kept for its Charlotte MCP image generation integration.

API module#

typescriptimport { search, getPage, createPage, getBlockChildren, appendBlocks, queryDatabase } from "../snappy-notion/api.ts";

Or CLI:

bashnpx tsx ~/.claude/skills/snappy-notion/api.ts search "query"    # search workspace
npx tsx ~/.claude/skills/snappy-notion/api.ts page <id>         # get page by ID

API functions#

Function Purpose
search(query) Search the Notion workspace
getPage(id) Retrieve a page by ID
createPage(parent, title, children?) Create a new page
getBlockChildren(blockId) Get child blocks of a block
appendBlocks(blockId, children) Append blocks to a page/block
queryDatabase(dbId, filter?) Query a Notion database

Rules#

  1. Auth via .env.cache. NOTION_TOKEN loads from snappy-settings/.env.cache via env("KEY") from ../snappy-settings/load.ts. See snappy-settings/SKILL.md.
  2. Notion-Version: 2022-06-28 on every request.
  3. Search to discover. Never guess page IDs or URLs. Use /v1/search.
  4. 100 blocks max per append request. 2000 chars max per rich text element.
  5. 3 req/sec average. Respect Retry-After on 429.
  6. External image URLs only. Notion fetches them server-side; URL must be publicly accessible.
  7. Share pages with the integration in Notion UI before any read/write.

Quick start#

bash# NOTION_TOKEN comes from .env.cache
NOTION_HEADERS=(-H "Authorization: Bearer $NOTION_TOKEN" -H "Notion-Version: 2022-06-28" -H "Content-Type: application/json")

# Search workspace
curl -s -X POST "https://api.notion.com/v1/search" "${NOTION_HEADERS[@]}" \
  -d '{"query": "search term", "page_size": 10}' | jq '.results[] | {id, title: .properties.title.title[0].plain_text, url}'

# Create page
curl -s -X POST "https://api.notion.com/v1/pages" "${NOTION_HEADERS[@]}" \
  -d '{"parent": {"page_id": "PARENT_ID"}, "properties": {"title": {"title": [{"text": {"content": "Title"}}]}}, "children": []}' | jq '{id, url}'

The draft never arrives alone#

A page's conversation IS its blocks: appending a paragraph is joining a document

mid-sentence. --json on append is a PREVIEW and touches nothing:

bashnpx tsx ~/.claude/skills/snappy-notion/api.ts append <page_id> "…" --json
# {kind: null, faceGap, thread, threadKind: "notion-page", draft:{kind, text, page, pageId, block}, doors:[Append, Later]}
  • thread is the SAME block rows page --json prints, in the page's own order.

Show the document above the words before asking anyone to approve them.

  • kind is null on purpose: snappy-faces draws no Notion block composer.

faceGap names it. Borrowing notion-page for the draft would redraw the

whole page as if it were the new words.

  • draft.block is what the API will actually receive — Notion's unit is the

BLOCK, never a markdown string.

  • A page this token cannot read gives thread: [] and the page id as the

label, never "(untitled)": that is a real answer for a real blank page, and

printing it here would claim the document is empty when it is unreadable.

  • A search row now carries id, which is what page and append take.
  • WITHOUT --json, append writes the paragraph at the end of the page.

Diagram generation + insert#

  1. Generate via Charlotte MCP image_generate (style: illustration, 16:9, 2K)
  2. Insert the returned URL as a Notion image block at the target position

Key capabilities#

  • Create pages under any parent (page or database)
  • Append blocks: heading, paragraph, callout, code, list, table, toggle, image, divider, quote, bookmark
  • Insert images at exact positions via "after": "BLOCK_ID"
  • Query and filter Notion databases
  • Search the entire workspace by title or content

Skill files#

File Contents
SKILL.md Full reference (workflows, block types, position options, rate limits)
block-types.md All block types with copy-paste JSON
api-reference.md Full CRUD endpoint reference
image-workflows.md Diagram generation + insertion pipeline
page-recipes.md Rich page templates (tech doc, meeting notes, KB article, tracker)

Relationship to snappy-docs#

snappy-docs is the canonical Notion primitive (full error handling, production patterns). This skill adds Charlotte MCP diagram generation. Use snappy-docs for pure page/database ops; use this skill when you need generated diagrams inserted into pages.


If this loader doesn't cover your case:

bashecho "[$(date -u +%FT%TZ)] snappy-notion: <what was missing>" >> ~/.claude/logs/agents-md-feedback.log

<!-- SKILL-INDEX-START -->

[snappy-notion Index]|root: ~/.claude/skills/snappy-notion|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md,api-reference.md,block-types.md,image-workflows.md,page-recipes.md}

<!-- SKILL-INDEX-END -->

Used by#

Nothing in the collection names this skill.

<!-- SNAPPY-CONTRACT-VERBS-START -->

Contract verbs#

Generated from api.ts HAND_CONTRACT. Do not hand-edit this block.

Verb Contract arguments Effect First call
me read npx tsx ~/.claude/skills/snappy-notion/api.ts me
page page-id read npx tsx ~/.claude/skills/snappy-notion/api.ts page <page-id>
get page-id read npx tsx ~/.claude/skills/snappy-notion/api.ts get <page-id>
search query read npx tsx ~/.claude/skills/snappy-notion/api.ts search "<query>"

Show the result#

When an answer carries face_hint, show it with one snappy_present(<answer>) call.

See /snappy-faces for face selection. Human-facing images must crop to the

element, render at 2x on Retina, and fill the destination channel instead of

placing a small card in a full-page screenshot.

<!-- SNAPPY-CONTRACT-VERBS-END -->

---
name: snappy-notion
role: Fast Notion workspace automation with built-in image generation via Charlotte MCP
loaded-by: PreToolUse hook (auto-injected when "snappy-notion" is mentioned)
---

# snappy-notion -- Agent Loader

You are operating the Notion workspace automation skill. Create, update, and enrich Notion pages with structured blocks and generated diagrams. Prefer `snappy-docs` for pure page/database ops; this skill is kept for its Charlotte MCP image generation integration.

## API module

```typescript
import { search, getPage, createPage, getBlockChildren, appendBlocks, queryDatabase } from "../snappy-notion/api.ts";
```

Or CLI:
```bash
npx tsx ~/.claude/skills/snappy-notion/api.ts search "query"    # search workspace
npx tsx ~/.claude/skills/snappy-notion/api.ts page <id>         # get page by ID
```

## API functions

| Function | Purpose |
|----------|---------|
| `search(query)` | Search the Notion workspace |
| `getPage(id)` | Retrieve a page by ID |
| `createPage(parent, title, children?)` | Create a new page |
| `getBlockChildren(blockId)` | Get child blocks of a block |
| `appendBlocks(blockId, children)` | Append blocks to a page/block |
| `queryDatabase(dbId, filter?)` | Query a Notion database |

## Rules

1. **Auth via `.env.cache`.** `NOTION_TOKEN` loads from `snappy-settings/.env.cache` via `env("KEY")` from `../snappy-settings/load.ts`. See `snappy-settings/SKILL.md`.
2. **`Notion-Version: 2022-06-28`** on every request.
3. **Search to discover.** Never guess page IDs or URLs. Use `/v1/search`.
4. **100 blocks max** per append request. 2000 chars max per rich text element.
5. **3 req/sec** average. Respect `Retry-After` on 429.
6. **External image URLs only.** Notion fetches them server-side; URL must be publicly accessible.
7. **Share pages with the integration** in Notion UI before any read/write.

## Quick start

```bash
# NOTION_TOKEN comes from .env.cache
NOTION_HEADERS=(-H "Authorization: Bearer $NOTION_TOKEN" -H "Notion-Version: 2022-06-28" -H "Content-Type: application/json")

# Search workspace
curl -s -X POST "https://api.notion.com/v1/search" "${NOTION_HEADERS[@]}" \
  -d '{"query": "search term", "page_size": 10}' | jq '.results[] | {id, title: .properties.title.title[0].plain_text, url}'

# Create page
curl -s -X POST "https://api.notion.com/v1/pages" "${NOTION_HEADERS[@]}" \
  -d '{"parent": {"page_id": "PARENT_ID"}, "properties": {"title": {"title": [{"text": {"content": "Title"}}]}}, "children": []}' | jq '{id, url}'
```

## The draft never arrives alone

A page's conversation IS its blocks: appending a paragraph is joining a document
mid-sentence. `--json` on `append` is a PREVIEW and touches nothing:

```bash
npx tsx ~/.claude/skills/snappy-notion/api.ts append <page_id> "…" --json
# {kind: null, faceGap, thread, threadKind: "notion-page", draft:{kind, text, page, pageId, block}, doors:[Append, Later]}
```

- `thread` is the SAME block rows `page --json` prints, in the page's own order.
  Show the document above the words before asking anyone to approve them.
- `kind` is **null on purpose**: snappy-faces draws no Notion block composer.
  `faceGap` names it. Borrowing `notion-page` for the draft would redraw the
  whole page as if it were the new words.
- `draft.block` is what the API will actually receive — Notion's unit is the
  BLOCK, never a markdown string.
- A page this token cannot read gives `thread: []` and the page **id** as the
  label, never "(untitled)": that is a real answer for a real blank page, and
  printing it here would claim the document is empty when it is unreadable.
- A `search` row now carries `id`, which is what `page` and `append` take.
- WITHOUT `--json`, `append` writes the paragraph at the end of the page.

## Diagram generation + insert

1. Generate via Charlotte MCP `image_generate` (style: illustration, 16:9, 2K)
2. Insert the returned URL as a Notion image block at the target position

## Key capabilities

- Create pages under any parent (page or database)
- Append blocks: heading, paragraph, callout, code, list, table, toggle, image, divider, quote, bookmark
- Insert images at exact positions via `"after": "BLOCK_ID"`
- Query and filter Notion databases
- Search the entire workspace by title or content

## Skill files

| File | Contents |
|---|---|
| SKILL.md | Full reference (workflows, block types, position options, rate limits) |
| block-types.md | All block types with copy-paste JSON |
| api-reference.md | Full CRUD endpoint reference |
| image-workflows.md | Diagram generation + insertion pipeline |
| page-recipes.md | Rich page templates (tech doc, meeting notes, KB article, tracker) |

## Relationship to snappy-docs

snappy-docs is the canonical Notion primitive (full error handling, production patterns). This skill adds Charlotte MCP diagram generation. Use snappy-docs for pure page/database ops; use this skill when you need generated diagrams inserted into pages.

---

If this loader doesn't cover your case:
```bash
echo "[$(date -u +%FT%TZ)] snappy-notion: <what was missing>" >> ~/.claude/logs/agents-md-feedback.log
```

<!-- SKILL-INDEX-START -->
[snappy-notion Index]|root: ~/.claude/skills/snappy-notion|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md,api-reference.md,block-types.md,image-workflows.md,page-recipes.md}
<!-- SKILL-INDEX-END -->

## Used by

Nothing in the collection names this skill.

<!-- SNAPPY-CONTRACT-VERBS-START -->
## Contract verbs

Generated from `api.ts` `HAND_CONTRACT`. Do not hand-edit this block.

| Verb | Contract arguments | Effect | First call |
|---|---|---|---|
| `me` | — | `read` | `npx tsx ~/.claude/skills/snappy-notion/api.ts me` |
| `page` | `page-id` | `read` | `npx tsx ~/.claude/skills/snappy-notion/api.ts page <page-id>` |
| `get` | `page-id` | `read` | `npx tsx ~/.claude/skills/snappy-notion/api.ts get <page-id>` |
| `search` | `query` | `read` | `npx tsx ~/.claude/skills/snappy-notion/api.ts search "<query>"` |

## Show the result

When an answer carries `face_hint`, show it with one `snappy_present(<answer>)` call.
See `/snappy-faces` for face selection. Human-facing images must crop to the
element, render at 2x on Retina, and fill the destination channel instead of
placing a small card in a full-page screenshot.
<!-- SNAPPY-CONTRACT-VERBS-END -->

Keyboard Shortcuts

Search in document⌘K
Focus search/
Previous file tab
Next file tab
Close overlayEsc
Show shortcuts?