Zero-Friction Knowledge Capture: A Cursor-Ready MVP Spec

Source: ~/Downloads/Cursor_MVP_Implementation_Guide.pdf
Phase: final
Index: Index - Cursor MVP Implementation Guide
Trajectory: Trajectory - Inner Map
Pipeline: CONSTITUTION - Publishable Asset Pipeline · 00 - Master Index
Status: draft
Mode: Authority


Opening: the agent will overbuild unless you cut first

I did not need another “research clipper” brainstorm. I needed a build contract that an agent like Cursor cannot expand into a second brain platform by accident.

The failure mode is familiar. You ask for save-to-Markdown. You get tagging menus, AI summaries, cloud sync, folder pickers, and a settings page. Each of those sounds helpful. Each of them puts a decision between you and the thing you just found. At the moment of discovery, decision is the tax.

So the brief opens as a scope weapon, not a feature catalog:

Build a perfect screwdriver, not a Swiss Army knife. Phase 1 only.

And the product feeling is one sentence:

Never ask the user a question during capture. Capture is immediate, headless, and silent. It runs in the background.

Everything below is the engineering lock that makes that sentence true offline, on a normal Chrome MV3 extension, with files you can still open in ten years.


1. The constraint check (how to refuse “MVP features”)

Before architecture, a kill filter:

If removing a feature does not make the product worse, it is not part of the MVP.

That line is for the agent and for me. “Nice” is not a reason to ship. Capture silence is. Local durable Markdown is. Losing either makes the product worse. Losing a tag picker does not.

Stick exclusively to what is documented. No adjacent inventiveness.


2. Architecture and tech stack

Goal of the stack: rapid build, extreme stability, zero cloud dependency in Phase 1.

PieceRole
Manifest V3Standard manifest.json with permissions for activeTab, contextMenus, downloads, and storage.
Background service worker (background.js)Context menu clicks, keyboard shortcuts, export queue orchestration.
Content scripts (content.js)Read DOM, extract selection or full-page HTML, grab metadata.
Turndown.js (local)HTML to Markdown. Links, bold, code blocks preserved.
chrome.downloads.download()The local write path. This is how you get zero-friction saves without a custom filesystem bridge.

Vanilla MV3. No framework tax. No remote summarizer in the critical path.


3. Core data flow (one capture, no interruption)

How a single capture moves without turning into a form:

  1. User highlights text, or clicks the extension affordance on empty space / a link.
  2. Context menu: Export to Memory.
  3. Content script extracts HTML, DOM state, and metadata.
  4. Turndown converts HTML to clean Markdown.
  5. String is wrapped in the fixed metadata template.
  6. chrome.downloads routes to Memory/Inbox/YYYY/MM/DD/title.md.
  7. Background script updates local storage (duplicate detection hash).

No rename prompt. No project picker. No “where should this go?” The Inbox is the answer.


4. Local Inbox via Chrome downloads

Browsers sandbox filesystem access. Folder selection dialogues break the zero-interaction rule. The workaround is intentional path construction plus saveAs: false.

const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
 
const filePath = `Memory/Inbox/${year}/${month}/${day}/${safeTitle}.md`;
 
chrome.downloads.download({
  url: 'data:text/markdown;charset=utf-8,' + encodeURIComponent(markdownContent),
  filename: filePath,
  saveAs: false // CRITICAL: no popup dialogue
});

Why this is product policy, not a preference panel: dated Inbox paths enforce Capture First, Organize Later. Decision fatigue moves to a later session when you still care. At capture time, you do not care. You only need the artifact to land.


5. Capture modes (three, not a dozen)

On install, the background script registers three modes only:

ModeTriggerBehavior
Export Entire PageRight-click empty space (or full-page path)Full extract path through scraper heuristics.
Export SelectionText highlightedSelected DOM node only, so surrounding context of the highlight is preserved without dumping the whole chrome UI.
Export LinkRight-click a hyperlinkLink-oriented capture without forcing a full page scrape.

If a fourth mode does not survive the constraint check, it does not ship.


6. Specialized DOM parsing (AI chats are not “just HTML”)

Standard pages are easy. AI chatbot UIs nest conversational turns. A naive document.body dump loses structure, or worse, stuffs chrome chrome into the note.

Heuristics locked in the brief:

  • ChatGPT: target div[data-message-author-role] so turns stay attributable.
  • Claude: target div.font-claude-message.
  • Generic pages: if no specialized scraper matches, fall back to document.body or a lightweight Readability-style strip (navbars, footers out) before Turndown.

The point is not a universal scraper platform. The point is: the two surfaces where knowledge actually appears in long form (AI threads + ordinary articles) survive export as readable Markdown.


7. Duplicate detection and the export queue

Maintain a lightweight queue in the background worker.

On capture:

  1. Hash URL + content.
  2. Store the hash in chrome.storage.local.
  3. If the hash already exists, intercept the capture.
  4. Temporary UI notice only: Already captured.

That is the full “smart” layer in Phase 1. No semantic search. No “you might also mean.” Intercept repeats; stay silent on first success.


8. Markdown export specification (non-negotiable)

Every export follows this layout so the file remains readable forever, independent of proprietary software and independent of the extension still being installed.

# {Page Title}
 
**Source:** {Domain name (e.g., ChatGPT, Reddit)}
**Date:** {YYYY-MM-DD}
**Time:** {HH:MM AM/PM}
**URL:** {Full URL}
 
---
 
{Converted Markdown Content Here}
{Ensure Code blocks are properly fenced with language tags}
{Ensure links are preserved as [Text](URL)}
 
---
 
**Metadata:**
Browser: {User Agent string (summarized)}
Capture Mode: {Selection | Full Page | Link}

This template is not a suggestion. It is the contract between capture-time automation and later-you reading a file in any editor.


9. Friction Counter (instrument before you invent)

The brief’s hidden gem is not another capture mode. It is instrumentation.

Implement a tiny persistent control (or a shortcut such as Ctrl+Shift+F) that opens a micro-modal with a single text input. On submit, append a row to a local CSV:

Path: Memory/Friction/log.csv
Fields: URL, timestamp, user note.

That log is how you learn what actually hurts in the field before you add OCR, voice, tags, or cloud. Features should answer friction rows, not imagination.


10. Capture First, Organize Later (and offline-first)

Inbox only in MVP. Temporary Inbox vs Projects is a deliberate refusal. Routing everything to Memory/Inbox/... kills the urge to classify mid-thought.

Offline-first guarantee: Phase 1 uses no external APIs for the critical path. No cloud sync, no AI summarization at capture time. If the DOM is loaded, the content script can read it and chrome.downloads can save it. Network is optional. The note is local.

Organize later is not laziness. It is protecting the only moment that is scarce: attention at discovery.


11. Executive summary matrix (what Cursor must validate)

Feature categoryMVP scope (Phase 1)Strictly excluded (postponed)
Data captureFull page, selection, linkOCR, voice memos
FormattingClean Markdown + automatic metadataProprietary formats, AI summaries, auto-tags
Storage routingDirect to local Memory/Inbox/...Cloud sync, Notion APIs, folder selection prompts
User interactionZero questions during capture; background queueRename prompts, tagging menus, confirmations
ResilienceDuplicate detection, offline-firstSemantic search, collaboration

If a PR adds a cell from the right column, it is not Phase 1. Send it back.


Closing: what this spec is really protecting

The technical pieces matter: MV3 worker, Turndown, dated Inbox paths, AI DOM selectors, hash dedupe, fixed Markdown.

The thing they protect is simpler.

When something is worth keeping, the system should get out of the way hard enough that the only residual act is the gesture that started capture. No questions. No cloud tax. No “organize this first.” A file lands under today’s Inbox date, forever-readable, hash-guarded against dumb duplicates.

That is the screwdriver.

If Cursor (or I) feel the urge to bolt on a Swiss Army blade, re-run the constraint check. If removing it would not make capture worse, it was never MVP. Log the itch in the Friction Counter instead, and keep Phase 1 boring in the only way that ships: silent, local, and done.