# Notion Docs

> Hierarchical Knowledge Base via Notion API. The "brain" of your organization — strategy, priorities, decisions, metrics. Use when reading/updating Active Context, strategy docs, or operational knowledge. Triggers on "active context", "brain", "knowledge base", "strategy doc".

- Skill: `kkauf/notion-docs` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add kkauf/notion-docs`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kkauf/notion-docs/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Research & Search
- Author: kkauf (https://skillmd.com/u/kkauf)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/kkauf/notion-docs

---


# Brain — Notion Knowledge Base

## Overview

The Knowledge Base is the "brain" of your organization — the semantic layer where strategy, priorities, metrics, and decisions live. The code repo is the "limbs" (execution). Docs in the codebase are "muscle memory" (how the limbs work).

**Source of truth for:** Active Context, strategy docs, billing, positioning, pricing model, platform strategy.

**NOT for:** Code docs (live in repo), legal docs (GDrive), spreadsheets, team artifacts.

## Architecture

Hierarchical pages under a Brain root page. Five **sections** act as typed containers:

```
Brain (root page)
  Active Context          <- cross-cutting dashboard, stays at root
  Konban                  <- database, managed by konban skill
  Strategy/               <- why we build, how we position
  Operations/             <- how the business runs day-to-day
  Product/                <- what we build, platform specs
  Research/               <- external knowledge, read-mostly
  Archive/                <- superseded content (hidden from default index)
```

Pages are found by title regardless of which section they're in. `find_page()` searches Brain root and all sections automatically.

**Metadata callout format** (top of each page):
```
Domain: Strategy | Status: Current | Updated: 2026-02-21
Summary: One-liner description
```

**Page ID:** `BRAIN_PAGE_ID` in your env file (see Credentials below)

### Section Routing Table

When creating new pages, route them to the right section:

| Signal | Section | Naming | Icon |
|--------|---------|--------|------|
| Company direction, positioning, "why" | Strategy | Descriptive title | Pick a meaningful emoji |
| Day-to-day execution, billing, playbooks | Operations | Descriptive title | Pick a meaningful emoji |
| Feature specs, platform standards | Product | Descriptive title | Pick a meaningful emoji |
| External research, market/legal analysis | Research | `Research: [Topic]` prefix | Pick a meaningful emoji |
| Superseded content | Archive | Keep original name | Keep original icon |

**Always set an icon** when creating pages: `--icon "🔬"` on `create`, or `meta "Title" --icon "🔬"` after the fact. Pick an emoji that reflects the page's content, not its section.

**Cross-cutting dashboards** (Active Context) stay at root — they don't belong to one section.

## Helper Script

```bash
python3 <skill-dir>/notion-docs/notion-api.py <command> [args]
```

### Commands

```bash
# Hierarchical semantic map (THE starting point)
python3 <script> index
python3 <script> index --all    # include Archive section

# Read full page as markdown (works regardless of section)
python3 <script> read "Active Context"
python3 <script> read "Billing & Invoicing"  # finds it under Operations/
python3 <script> read "Title" --raw  # skip metadata header

# Create new page under a section (always include --icon)
python3 <script> create "New Doc" \
  --parent "Research" --icon "🔬" --domain Research --summary "One-liner" <<'NOTIONEOF'
# Content here
NOTIONEOF

# Create at Brain root (no --parent)
python3 <script> create "Cross-Cutting Doc" \
  --icon "🎯" --domain Strategy --summary "..." <<'NOTIONEOF'
# Content here
NOTIONEOF

# Move page between sections (copy-and-archive — non-destructive)
python3 <script> move "Page Title" --to "Operations"
python3 <script> move "Page Title" --to "root"  # back to Brain root

# Update page content — FULL REWRITE
# ABORTS if page has open comments. Use --force to override.
python3 <script> update "Title" <<'NOTIONEOF'
...full updated markdown here...
NOTIONEOF

# Patch a SINGLE SECTION (fast — only touches that section's blocks)
python3 <script> patch "Title" \
  --section "Section Heading" <<'NOTIONEOF'
## Section Heading
- Updated content
NOTIONEOF

# Update metadata only (domain, summary, status, name, icon)
python3 <script> meta "Title" --summary "Updated summary"
python3 <script> meta "Old Name" --name "New Name"
python3 <script> meta "Title" --icon "🔬"

# Search (includes pages in all sections)
python3 <script> search "pricing"

# Comments
python3 <script> comments "Title"
python3 <script> comment "Title" "Reply text" -d <discussion_id>
python3 <script> comment "Title" "New comment"

# Archive (sets status to Archived in metadata)
python3 <script> archive "Old Doc"
```

### Common Mistakes (from real sessions)

**Run `index` before guessing page titles:**
```bash
# WRONG: read "Pricing Strategy"   (guessing — page might be named differently)
# RIGHT: first run index, then use the exact title shown
python3 <script> index
python3 <script> read "SaaS Pricing Model"
```

**Run `read --raw` before using `patch`** to see actual section headings:
```bash
# WRONG: patch "Active Context" --section "Current Sprint"  (guessing section name)
# RIGHT: read first, then patch with the exact heading
python3 <script> read "Active Context" --raw
python3 <script> patch "Active Context" \
  --section "Current Focus" <<'NOTIONEOF'
## Current Focus
- Updated content
NOTIONEOF
```

**No `--content` flag on `create` or `update`.** Use stdin (heredoc) or `--file`:
```bash
# WRONG: create "Doc" --content "Some text"
# WRONG: update "Doc" --content "New text"
# RIGHT (stdin):
python3 <script> create "Doc" --parent "Research" --icon "🔬" <<'NOTIONEOF'
Content here
NOTIONEOF
# RIGHT (file):
python3 <script> update "Doc" --file /tmp/doc.md
```

### Move Command Details

`move` uses copy-and-archive because the Notion API doesn't support reparenting pages. It:
1. Creates a new page under the target section
2. Copies all blocks from the old page
3. Archives (soft-deletes) the old page

Content is preserved. Comments on the old page are lost (they stay on the archived original). Page ID changes — but all lookups are by title, so this is transparent.

## Comment-Driven Editing Workflow

Team members can comment on Notion docs to give feedback. Claude reads, addresses, and replies.

**Preferred: Pull-Edit-Push with `patch`** (lean on tokens):
```bash
# 1. Pull doc + comments
python3 <script> read "Doc Title" --raw > /tmp/working-copy.md
python3 <script> comments "Doc Title"

# 2. Edit locally with the Edit tool — repeat as needed (~10 tokens each)

# 3. Push back SECTION BY SECTION + reply to comments
python3 <script> patch "Doc Title" \
  --section "Section Name" --file /tmp/section-extract.md

# 4. Reply to addressed comments
python3 <script> comment "Doc Title" \
  "Addressed: updated X per feedback" -d <discussion_id>
```

**Notion API limitation:** Cannot resolve comments programmatically. Reply with what was changed; the user resolves manually in Notion.

### Credentials

Stored at `~/.claude/secrets/notion.env` (auto-loaded by helper):
- `NOTION_TOKEN` — Internal integration token
- `BRAIN_PAGE_ID` — Root page ID (parent of all knowledge base pages). Also accepts `KH_BRAIN_PAGE_ID` for backward compatibility.

## Metadata Fields

| Field | Values |
|-------|--------|
| **Domain** | Free text — use what fits your organization (e.g., `Strategy`, `Product`, `Research`, `Operations`) |
| **Status** | `Current`, `Draft`, `Archived` |
| **Updated** | ISO date (auto-set on update) |
| **Summary** | 1-2 sentence description — this IS the semantic map |

## Typical Session Workflow

### Startup
```bash
# Step 1: Load hierarchical semantic map
python3 <script> index

# Step 2: Load Active Context (cross-cutting priorities dashboard)
python3 <script> read "Active Context"
```

### During Session
```bash
# Read any page — find_page searches all sections automatically
python3 <script> read "Billing & Invoicing"
python3 <script> search "pricing"
```

### Session Close
```bash
python3 <script> update "Active Context" <<'NOTIONEOF'
...full updated markdown...
NOTIONEOF
```

## CRITICAL: `update` Destroys Comments

**`update` does delete-all + rewrite. This NUKES all inline Notion comments on the page.**

**Decision tree:**
1. Page has open comments? -> Use `patch` (one section at a time)
2. Page has no comments + changing 1-2 sections? -> Use `patch`
3. Page has no comments + rewriting most of the doc? -> `update` is fine

## Performance Notes

| Operation | Doc size | Approx time | When to use |
|-----------|----------|-------------|-------------|
| `update` | Small (20-30 blocks) | ~10-15s | Small docs with NO comments |
| `update` | Large (100+ blocks) | ~45-60s | Only when rewriting the whole doc AND no comments |
| `patch` | Any section (5-15 blocks) | ~5-15s | **Preferred** — preserves comments, faster |
| `move` | Any page | ~3-30s | Copy-and-archive. Time scales with block count |

**Section matching:** `--section` matches the exact heading text (e.g., `"Recent Notes"`, not `"## Recent Notes"`).

## Content Format

Pages store content as Notion blocks, converted from/to markdown. Supported:
- Headings (H1-H3), paragraphs, bullet/numbered lists
- **Bold**, *italic*, ~~strikethrough~~, `code`, [links](url)
- Code blocks, blockquotes, horizontal rules, tables

