Skip to content

Repository files navigation

Noted.

Privacy-first meeting assistant — self-hosted. Real-time transcription, note surfacing during meetings, live answers in an overlay that's invisible to screen capture, fact-checking against your own meeting history, and auto-generated minutes.

Built from the Figma wireframe in designs/Noted..svg and the spec in the dev handoff. The UI is deliberately macOS-styled on every platform (traffic-light chrome, frameless, vibrancy-style panels) — that's the brand choice, not a macOS-only build.

Motion follows the same premium macOS direction: surfaces open with a quick soft lift, close with a short fade/lift before the native window dismisses, buttons and traffic lights get restrained press feedback, live content enters quietly, and the app respects reduced-motion settings. There are no shine or glow effects in this motion pass.

Window reopen paths restore minimized surfaces before focusing them, and draggable titlebars explicitly exclude their traffic-light controls so red, yellow, and green remain clickable after tray/reopen cycles. Preferences tabs crossfade into place with the same restrained content-entry motion.

The native renderer smoke test uses Windows-safe file URLs and exercises real traffic-light coordinates. It also verifies that pointer movement affects only widget content and the command strip while the header remains still, unless reduced-motion is enabled on the test machine.

The current depth treatment is intentionally matte: widget sections, answer surfaces, and search results use shallow elevation; selected results lift by 1px; controls use a short physical press response; and content staggers in quietly. There is no perspective tilt, shine, or glow, and reduced-motion settings disable the depth motion.

The widget also has a restrained mouse-only parallax: the content plane is capped at ±2px and the command strip at ±0.9px. The titlebar remains fixed so the app chrome never drifts under the pointer. Touch input and reduced-motion preferences leave the layout still.

The standalone motion storyboard at docs/motion/noted-motion-storyboard.tsx captures a seven-second meeting-memory handoff: matte shell arrival, transcript/search context, answer arrival, tactile yellow minimize, restore, and a reduced-motion resting state. docs/motion/remotion-entry.tsx registers the composition, and the rendered MP4 is at docs/motion/noted-motion-storyboard.mp4. Remotion is installed as a development-only renderer; it adds no runtime dependency to the app. The optional inference.sh belt renderer is available through npx @inferencesh/belt; its device login requires browser approval and is not required for the local render.

The production smoke test opens a fresh Electron window and validates the widget's yellow minimize button, green expand/restore button, title-bar stability, bounded parallax response, companion-window visibility/opacity/theme persistence, Preferences/Search close-and-reopen, and overlay hide/show restoration. Run it with NOTED_SMOKE_TEST=1; use NOTED_SMOKE_TEST_REDUCED=1 as well to verify the reduced-motion branch. A failed assertion returns a non-zero exit code.

Layout spacing now follows the shared 4 / 8 / 12 / 16 / 24 / 32 px token scale. Reusable surfaces use those tokens for padding, gaps, and outer document rhythm; deliberately optical values (for compact controls and aligned labels) remain explicit.

Noted. includes a context-aware Next actions inbox. Tasks can be captured from the main widget, linked to meeting action items, filtered by Inbox / Next / Waiting / Done, and opened back at their source meeting. The inbox keeps the task's context attached without introducing project-management clutter. AI can also suggest unfinished work from completed transcripts and answer-overlay conversations; suggestions stay in a review queue until you explicitly Approve or Dismiss them. You can edit a suggestion’s task title before approval; the approved wording becomes the Inbox task while its evidence and source context remain preserved.

The floating widget follows the supplied wireframe: a 360px assistant with a dedicated recording row, compact transcript, session insights, and an action strip. Transcript, insights, composer, and controls use consistent rounded inset surfaces, with shared light and dark appearance tokens. The action strip opens Search Past Meetings; screen analysis is available from the Assistant chat overlay's Analyze control.

Preferences uses the same frameless macOS-style chrome as the rest of the app: red cancels unsaved previews and closes, yellow minimizes the Preferences window, green toggles maximize/restore, and Save Changes is the only explicit commit action. The titlebar remains draggable while its controls stay clickable.

The Answer Overlay uses the same functional traffic-light chrome: red hides the overlay, yellow minimizes it, green toggles maximize/restore, and the transparent window shell clips into soft rounded corners.

The Answer Overlay footer uses Analyze instead of Close. Analyze can target Auto, Screen, or Choose: Auto captures the most likely visible non-Noted window, Screen captures the primary screen, and Choose opens the detailed capture picker. Results stream back into the overlay for questions, coding prompts, docs, or visible problem statements.

Answer Overlay message, error, code, and composer surfaces use softer rounded inset styling so the content matches the macOS-style shell instead of reading like a flat web form.

The Answer Overlay opens wider by default so the Analyze target selector and command buttons remain readable. Footer controls have stable widths while the text input is the only flexible element.

The Analyze target selector uses a compact custom chevron so Auto, Screen, and Choose fit cleanly without excess arrow spacing.

The Answer Overlay stays open when focus moves to another app or window. Close it intentionally with the red traffic light or Esc. Search result sets enter as a short coordinated sequence, and active conversations show a quiet source-context handoff such as the meeting they came from. Minimizing and restoring the overlay preserves that meeting context and the current scroll position. Closing and reopening it resets the transient closing state so the overlay remains interactive.

The Next actions capture field now includes an inline scheduler intent assistant with real-time AI enrichment. A local deterministic parser runs first (instant, on-device) and recognises @mentions, today, tomorrow, next Monday, 2pm, 2:00pm, 14:00, noon, midnight, for 30 minutes, every day, every Monday, daily, weekly, monthly, and event/task signals such as coffee, meet, call, lunch, invite, schedule, check, send, review, follow up, prepare, draft, publish, update, create, finish, confirm, look into, set up, fix, deploy, and ship. The configured LLM provider then enriches the intent with a sharper title, higher confidence, and edge-case detection. Locally detected people are preserved through AI enrichment and accepted tasks retain them, for example Meetup with @Maria · due 2026-08-12. Event-like drafts with a date/time recommend a connected calendar provider; task-like drafts recommend Add to Inbox, with calendar as an alternate when a date exists. If no provider is connected, the Calendar action opens Preferences instead of silently downloading a file. If AI credentials are unavailable, Noted. keeps the instant local parser active and shows Add AI API Key for AI Recommendations. The agent shows a parsing state while waiting for AI. Press Tab to accept, Esc to dismiss. Date/time words prefixed with @ (such as @Today, @Tomorrow) are correctly recognised as dates, not person mentions. In demo mode the AI enrichment is skipped gracefully. Reduced-motion mode disables all agent animations and shows the final static pose. Scheduler presentation now uses a shared visual-state contract (idle, typing, understanding, recommendation-ready, accepting, accepted, and dismissed) so the SVG agent and future 2.5D/WebGL surfaces cannot drift apart. The everyday recommendation is now a layered matte 2.5D card: semantic people/date/recurrence chips assemble above a rear surface, the card lifts by 2px when ready, and real buttons remain in the DOM throughout. Its text and SVG agent stay on crisp 2D paint planes; depth is supplied by matte layers and shadows rather than compositing the readable content in 3D. Reduced motion removes the perspective, chip, and lift transitions while preserving the same details and actions. An adaptive motion-quality policy now selects static for reduced-motion or low-power contexts, 2.5d for normal widget/Todo use, and webgl only for the explicit Focus mode after a successful lazy capability probe; normal startup never creates a WebGL context.Late AI results cannot revive an accepted or dismissed recommendation.

Recommendations now include an optional Focus action. Focus mode is a real calendar planning workspace: edit the date, time, duration, and attendee names, inspect the updated plan, then explicitly confirm Add to Calendar or Add to Inbox. It opens a renderer-level matte workspace without duplicating parser or persistence state. It lazy-loads the procedural Three.js/React Three Fiber scene only when the quality policy permits it, uses demand-driven transitions with a fixed camera, and falls back to the readable 2.5D Focus view when WebGL is unavailable or reduced motion is active. Important event details remain in regular DOM text outside the canvas, and Esc/Done closes Focus without losing the active recommendation.

The Focus scene uses only procedural low-poly geometry: a small desk companion, one calendar card, a matte floor, and restrained lighting. It has no bloom, glow, orbiting camera, remote assets, or production dependency on the Remotion MP4.

Calendar Accounts in Preferences supports Google Calendar + Meet, Microsoft Outlook + Teams, and generic CalDAV services such as iCloud and Nextcloud. Google and Microsoft use OAuth opened in the system browser; CalDAV uses an app-specific password stored in Electron secure storage. Google/Microsoft create online meetings when the provider supports them, while CalDAV creates the calendar event without inventing a meeting link. Attendee names without email addresses remain local display-only mentions; email addresses are required before invitations are sent.

Search, Analyze Screen, and Preferences also stay open when clicking outside their content. Noted. windows are pinned above normal apps and reassert visibility after focus changes so the assistant stays visible while you switch tabs or work in another app.

Preferences shows Keep Noted. visible as a locked status, not a toggle, because persistent visibility is core product behavior.

Summary and Minutes use quieter document-style hierarchy: broad sections are flatter bands, while repeated data objects keep compact card treatment. Summary now exports a designed PDF directly: the PDF includes the meeting overview, summary, decisions, action items, mood timeline, participation bars, open items, and fact-check flags. Share still copies the text summary, while Markdown export remains available only through the lower-level export bridge for compatibility.

Shortcut conflicts now persist inside Preferences after Save Changes. If Windows rejects a shortcut, the Shortcuts tab shows the failed binding and offers alternate shortcuts.

Workspaces / clients

Noted. now keeps meetings, notes, Todos, search, and AI context inside a durable workspace boundary. The active workspace is captured when recording starts, so switching from Personal to Acme cannot move or overwrite an existing meeting. Existing databases migrate their records into a Personal workspace automatically without changing meeting IDs or content.

Use the workspace control in the widget or any document window to switch clients, create a workspace, or restore an archived workspace. Archiving is reversible and non-destructive: it hides a workspace from the default switcher and blocks new recordings until restored. Summary and Minutes remain loaded by meetingId, while the Summary window exposes workspace meeting history and an explicit Linked context picker for prior meetings and notes.

Default search, note surfacing, Todos, and fact-check context are scoped to the active workspace. Search can be expanded to All workspaces explicitly, with workspace labels on every result. Historical context is never injected automatically: accept a suggested/latest record or link it manually before it can influence future AI generation.

The dedicated Meeting Archive window is available from the widget's document controls. It starts in the active workspace and shows active-workspace meetings newest first. Choose All workspaces to reveal broader status filters; Include archived is intentionally hidden until that scope is selected, starts unchecked every time the window opens, and is required before archived client data can appear. The Linked context filter finds meetings that either link to another record or are referenced by one. Archive browsing is read-only, and Summary/Minutes buttons always open the selected meeting by its immutable meeting ID.

Manual workspace check

  1. Create Acme, switch to it, and start a demo meeting; stop it and confirm its Summary appears in Acme history.
  2. Switch to Personal, confirm the Acme meeting and tasks are absent from the default list, then use Search → All workspaces to find it with its Acme label.
  3. Archive and restore Acme; verify its data remains intact and recording is blocked while archived. Open the Acme Summary and link a prior Acme meeting or note through Linked context.
  4. Open Meeting Archive, switch to All workspaces, confirm Include archived starts off, enable it deliberately, filter Has linked context, then close and reopen to confirm archived inclusion resets.

Quick start

npm install        # installs deps + rebuilds better-sqlite3 for Electron
npm run dev        # launches the app (demo mode, zero models required)

No models needed to see it work: the default "demo" provider simulates a live meeting (scripted Q3 budget review with speaker diarization, a live contradiction flag, RAG surfacing, participation, and mood). Press Start Meeting and watch it run.

Try these

  1. Start Meeting — watch the live transcript, RAG suggestions ("From your notes"), and the fact-check flag when $150k contradicts the $120k cap.
  2. Global shortcut Ctrl/Cmd+Shift+Space — summons the Answer Overlay; ask anything, it answers from your local notes index.
  3. Analyze Screen — pick a window/screen, confirm the privacy banner, and get a vision-model answer streamed into the overlay.
  4. Summary / Minutes tabs — auto-generated summary, decisions, assignable action items, participation, mood timeline; export the Summary as a designed PDF or export Minutes as Markdown/PDF.
  5. Settings → Note Settings — point it at a folder of .md/.txt notes; they're embedded into a local vector index.

Architecture

src/
├─ shared/          # Types + IPC contracts + provider classification + scheduler parser
├─ main/            # Electron main process
│  ├─ index.ts      #   app lifecycle, seeding, tray, shortcuts, IPC registration
│  ├─ windows.ts    #   main window + content-protected overlay windows
│  ├─ session.ts    #   live meeting engine (transcript, RAG, fact-check, mood)
│  ├─ ipc.ts        #   every IPC channel from the handoff table
│  ├─ tray.ts       #   system tray + native menu
│  ├─ shortcuts.ts  #   global hotkeys (configurable in Settings)
│  ├─ data/         #   SQLite (better-sqlite3) + in-memory fallback, repos, seeding
│  ├─ providers/    #   STT + LLM registry: demo / Whisper / Ollama / Deepgram / custom
│  └─ services/     #   rag, factcheck, mood, summary, minutes, capture, answer, task suggestions
├─ preload/         # contextBridge → window.noted (fully typed)
└─ renderer/        # React UI (main window + overlay windows via ?view=)

Windows

Window Purpose Protection
Main window Sidebar (360px) + live transcript widget content-protected when enabled in Privacy settings
Next actions (?view=todo) Context-aware task inbox and quick capture follows app theme and window privacy settings
Meeting Archive (?view=archive) deterministic historical meeting browsing and recovery filters follows app theme and window privacy settings
Answer Overlay (?view=answer) streaming answers, suggestions, fact-check setContentProtection(true) — hidden from capture
System tray start/stop recording, overlays, settings, quit

Data & privacy

  • SQLite (better-sqlite3, WAL) at userData/noted.db — meetings, transcript lines, speakers, decisions, action items, participation, mood, settings, minute templates.
  • Local vector index over note chunks (Markdown/plain text). Embeddings come from the configured response provider (Ollama nomic-embed-text or a custom /embeddings endpoint) with a deterministic offline n-gram fallback — search works with zero models.
  • If the native module can't load (ABI mismatch), the app falls back to an in-memory store and still runs in demo mode. npm run rebuild recompiles it.
  • Cloud/custom providers trip the external-server warning; note excerpts and embeddings may also be sent to the selected response endpoint.
  • Analyze Screen screenshots live in memory only and are discarded after the request; only the text answer persists (and only if you save it to a note — v1 surfaces it via the overlay).

Providers

Kind Where it runs Status
demo local, simulated ✅ full
ollama local ✅ chat + embeddings + vision (HTTP)
whisper local 🚧 scaffolded (testConnection + wiring point; streaming engine = next milestone)
deepgram cloud 🚧 API key validated; live streaming = next milestone
custom custom endpoint ✅ chat + embeddings + vision (HTTP)

Calendar provider setup

For Google OAuth, set NOTED_GOOGLE_CLIENT_ID and optionally NOTED_GOOGLE_CLIENT_SECRET. For Microsoft OAuth, set NOTED_MICROSOFT_CLIENT_ID and optionally NOTED_MICROSOFT_CLIENT_SECRET. Register http://127.0.0.1 as a loopback redirect for the desktop OAuth client. Then open Preferences → Calendar Accounts → Connect. CalDAV services use their server calendar URL, username, and an app-specific password entered in Preferences; the password is encrypted with Electron secure storage.

Roadmap (from the handoff, not yet designed)

  • Cross-meeting participation trends (weeks/months)
  • Generated minute templates (vs. selecting from a list)
  • Additional note sources beyond Markdown/text/Notion
  • Region-select capture for Analyze Screen, local Whisper streaming, Deepgram live streaming

Scripts

npm run dev          # dev server + Electron
npm run motion:render # render the Phase 4 storyboard MP4
npm run typecheck    # tsc for main/preload + renderer
npm run build        # production build to out/
npm run start        # preview the build
npm run rebuild      # rebuild native module (better-sqlite3) for Electron

About

Your Live AI Assistant That Takes Notes, Create Summary Reports, Minutes, Suggestions, and AI Chat in Real Time.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages