Right now each tool is built as a vertical silo — it owns its own capture UI, its own data shape, its own auth, and its own destination. That's why it feels like 4 tools. But look at what actually varies vs. what's identical:
| QuickActions | Chrome (pending) | Review widget | Dev widget | |
|---|---|---|---|---|
| Surface | macOS menu bar | Browser, any page | Injected in mockup | Docked in app |
| Author | Internal (you) | Internal | External, anon | Internal, authed |
| Context | none (raw idea) | any URL | mockup variant | app page |
| Payload | text + tags | text + screenshot | pin + screenshot + section | form + screenshot |
| Lands in | Notion (direct) | ? | Supabase→email+Notion | /api/feedback |
| Lang | Swift | JS | vanilla JS | React |
The capture payload is ~80% identical across all four — text, optional screenshot, context (URL/section/viewport), author. What genuinely differs is only two axes: who's authoring (anon client vs internal) and where it should route (backlog idea vs design-review vs QA/support queue). Everything else is duplicated, not differentiated.
And you can already see the cost of the silo model in your own code: DevFeedbackWidget.tsx's header says it exists to replace "previously drifting copies" of the same widget. That drift is the symptom of organizing by tool instead of by seam.
design_feedback (then syncs to Notion), the dev widget hits a separate /api/feedback. Adding the Chrome extension naively makes it four sinks. Every new "capture more data" feature (richer screenshots, console logs, DOM snapshots) then has to be implemented N times.CAPTURE SURFACES CONTRACT INGESTION ROUTING ┌───────────────┐ │ macOS (Swift) │──┐ ├───────────────┤ │ ┌──────────────┐ ┌────────────────┐ ┌─ design review │ Chrome ext │──┼────► │ Feedback │──► │ POST /api/ │──► ├─ backlog (Notion) ├───────────────┤ │ │ Envelope │ │ feedback/intake│ ├─ QA queue │ Review widget │──┤ │ (versioned) │ │ (validate + │ ├─ support ├───────────────┤ │ └──────────────┘ │ fan out) │ └─ Slack/email │ Dev widget │──┘ └────────────────┘ └───────────────┘
Three seams to make explicit:
{ source, intent, author, context{url,project_id,variant_key,section,viewport,screenshot}, payload, metadata }. Versioned and additive (a metadata jsonb), so "capture more data over time" = add a field, not a new pipeline. You already have the right instinct here — design_feedback.section_context is a jsonb escape hatch. Generalize that.intent (idea→backlog, client-review→design_feedback, qa→QA queue, support→support). Auth becomes a per-source concern at the edge (anon token for review, session for internal), not a per-destination one.