5.2 KiB
M-13 — Notion Structured Export Decision Memo
Status: BLOCKED on Marko's design decisions — DO NOT IMPLEMENT until the four questions below are answered.
Context: M-13 is the last sub-item in the M-11..14 Wiki v2 block. The
audit (docs/plans/WIKI-V2-AUDIT-2026-04-20.md) noted it's the only item
with no prior art and needs external-API integration choices. M-11/M-12/
M-14 shipped in this session; M-13 is queued.
The four questions
Q1 — Auth surface
Option A — Reuse the existing agent's Notion OAuth flow
packages/agent/src/connectors/notion-connector.ts has a Notion OAuth
client already wired up. It's scoped to READ for memory ingestion. For
writes we'd need to broaden the scope (new consent screen text, new
redirect URI if different, new token column, migration for existing
connected users).
- Pro: Single identity per user; the same Notion connection powers both "read my Notion into memory" and "write my wiki into Notion."
- Con: Scope creep on the existing consent screen; users who consented to read-only feel different when they see "allow writes"; existing tokens need re-consent.
Option B — Separate Notion write token in Vault
Add a new Vault entry notion-wiki-token that the user pastes from
Notion's internal-integration settings (https://www.notion.so/my-integrations).
- Pro: Zero coupling with the ingest flow; users who don't use Notion-as-source can still export; simpler consent story.
- Con: Two Notion creds to manage; power users ask "why does my connector not work for export?"
Recommendation: B for v1. Separate write token. Ships clean without OAuth scope migrations; upgrade to unified OAuth if M-29 MS Graph pattern (which is v2-deferred anyway) ever lands.
Q2 — Parent-page UX
Notion requires a parent page/database when creating child pages. Options:
Option A — Auto-create a top-level "Waggle Wiki" page on first
export, remember its page_id in wiki_pages.notion_root_page_id (new
column) or a settings row.
Option B — User selects at export time. UI either shows a list of the user's top-level pages (requires search API call) OR asks for the page URL paste.
Recommendation: B with paste-URL fallback. "Paste the URL of the Notion page that should be your wiki's root." Obsidian M-12 already established the pattern: prompt for path. Notion prompt for URL.
Q3 — Update vs. insert on re-run
Re-running export against the same Notion root: should we UPDATE existing Notion pages or create new ones?
Option A — Always update (keep a wiki_pages.notion_page_id column
keyed by slug). Requires a migration to add the column + handling
partial-fail cleanup.
Option B — Delete + recreate on every export. Simpler but loses Notion's comment threads, per-block history.
Option C — Delta only changed pages (detected via content_hash).
Best UX but requires A's column + delta comparison.
Recommendation: C. Uses the existing content_hash from
CompilationState.upsertPage for change detection. Migration adds
one INTEGER column (notion_page_id). Worst case falls back to A
behavior (update even unchanged pages).
Q4 — Markdown → Notion blocks converter
Current wiki markdown is simple (H1/H2/H3, paragraphs, bullet lists, occasional blockquotes, no tables per compiler.ts inspection).
Option A — Roll our own ~150 LOC converter that handles the 5-6 block types we actually emit.
Option B — Use a library (marked + custom renderer, or
@notionhq/client's built-in support? Notion's API takes blocks
directly; no library I know of converts markdown to Notion blocks
canonically).
Recommendation: A. The markdown shape is predictable and narrow. Writing the 150 LOC means we don't inherit a library's edge-case behavior for something we control end-to-end. Tests cover H1-H3, paragraphs, bullets, links (become Notion rich_text with link property), and YAML frontmatter extraction (drops from the body, maps to Notion page metadata).
Proposed v1 scope if all four land as recommended
- Add
notion-wiki-tokenVault entry type. - UI: WikiTab "Export to Notion" button → prompt for (a) vault token if not set, (b) root page URL.
- Adapter
packages/wiki-compiler/src/adapters/notion.ts:writeToNotionWorkspace(pages, { token, rootPageId }): Promise<NotionExportResult>- Markdown-to-blocks converter (H1/H2/H3, paragraphs, bullets, links, blockquotes).
- Per-page: if
notion_page_idin cache + content_hash matches: skip; if mismatch:pages.update+ replace block children; elsepages.createunder root.
- Migration:
ALTER TABLE wiki_pages ADD COLUMN notion_page_id TEXT. - Route:
POST /api/wiki/export/notion { rootPageUrl }— reads token from Vault. - Tests: unit for the block converter, integration mock for the API client.
Scope estimate with recommendations accepted: ~1 d (matches audit).
Scope estimate if rewriting auth (Option A Q1): ~1.5 d + OAuth scope migration.
What to do next session
- Marko reviews and picks answers (or proposes alternatives) for Q1-Q4.
- Add an M-13 task with the chosen scope.
- Execute. First commit: the migration. Second: the adapter + converter
- tests. Third: route + UI.
Author: Claude (memo queued per S4 session M-13 deferral) Date: 2026-04-20