Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
de141c5
feat: add agentic tool-calling system to Agent Mode
gabrielste1n Mar 16, 2026
8413080
feat: migrate agent mode to Vercel AI SDK
gabrielste1n Mar 16, 2026
e6f0cda
fix: pass reasoning_effort via providerOptions for Groq models with d…
gabrielste1n Mar 16, 2026
edcae98
fix: harden agent tool-calling with proper cleanup and error handling
gabrielste1n Mar 16, 2026
ecda304
feat: add note management tools (get, create, update) to agent mode
gabrielste1n Mar 16, 2026
bbc7748
feat: add cloud agent tool support with NDJSON streaming
gabrielste1n Mar 18, 2026
500c6f9
feat: use cloud semantic search in agent search_notes tool
gabrielste1n Mar 18, 2026
589947d
feat: stream cloud agent responses directly from renderer
gabrielste1n Mar 19, 2026
0921eec
fix: forward session cookies via IPC for direct agent streaming
gabrielste1n Mar 19, 2026
4a1d3e2
fix: use event-based IPC streaming instead of direct fetch
gabrielste1n Mar 19, 2026
c4222c7
feat: polish agent chat UX with rich tool step visualization
gabrielste1n Mar 19, 2026
c6b402f
fix: separate tool displayText from LLM data, truncate web search res…
gabrielste1n Mar 19, 2026
df15111
feat: clickable created notes, bump max tool steps to 20
gabrielste1n Mar 19, 2026
84dca04
feat: inline note cards in chat, recording-style input indicators
gabrielste1n Mar 19, 2026
43623f0
fix: use separate navigate-to-note event to avoid triggering meeting …
gabrielste1n Mar 19, 2026
49e6b2d
Merge branch 'main' into feat/agent-tool-calling
gabrielste1n Mar 23, 2026
71d5a3e
Merge remote-tracking branch 'origin/main' into feat/agent-tool-calling
gabrielste1n Mar 23, 2026
70dcf2f
fix: release hardening for v1.6.6
gabrielste1n Mar 23, 2026
d399106
chore: apply formatting to helpers and types
gabrielste1n Mar 23, 2026
13305e7
Merge remote-tracking branch 'origin/main' into feat/agent-tool-calling
gabrielste1n Mar 23, 2026
728cd21
fix: deduplicate types, populate metadata, memoize tool registry
gabrielste1n Mar 23, 2026
f36abc2
fix: use system audio granted state instead of denied status for perm…
gabrielste1n Mar 23, 2026
23dd071
fix(notes): resolve race conditions in note state management during r…
gabrielste1n Mar 24, 2026
67e52ff
feat: add local semantic search via Qdrant sidecar
gabrielste1n Mar 24, 2026
4353f75
docs: add local semantic search to CLAUDE.md
gabrielste1n Mar 24, 2026
29bf31f
refactor: make local semantic search always-on, remove toggle
gabrielste1n Mar 24, 2026
436643d
fix: add qdrant to electron-builder packaging, fix runtime download path
gabrielste1n Mar 24, 2026
7966210
ci: add Qdrant binary download to all CI/release workflows
gabrielste1n Mar 24, 2026
c1848d1
chore: add .qdrant-initialized to gitignore
gabrielste1n Mar 24, 2026
c45a037
fix(agent): skip LLM cleanup for all transcription paths in agent mode
gabrielste1n Mar 24, 2026
4648a7a
feat(chat): add sidebar chat tab with conversation history, cloud syn…
gabrielste1n Mar 24, 2026
16ae259
fix(chat): address code review findings — extract shared toolIcons, w…
gabrielste1n Mar 24, 2026
04505e9
fix(chat): address backend review — wire vector search, fix types, re…
gabrielste1n Mar 24, 2026
bcd4c0b
ci(win): add Azure Artifact Signing for Windows code signing
gabrielste1n Mar 24, 2026
69b77b9
fix(chat): show input field on new chat instead of empty state
gabrielste1n Mar 24, 2026
5d317cc
feat(chat): redesign thinking/streaming state — shimmer indicator + s…
gabrielste1n Mar 24, 2026
23bfd71
refactor(chat): move thinking indicator to message bubble as shimmer …
gabrielste1n Mar 24, 2026
9a8845a
fix(chat): electric blue shimmer, dynamic thinking text, improved inp…
gabrielste1n Mar 24, 2026
0947f7a
fix(chat): lighter electric shimmer — high lightness with soft chroma…
gabrielste1n Mar 24, 2026
f0cdabd
fix(chat): keep shimmer blue throughout, refocus input after send
gabrielste1n Mar 24, 2026
8f5fad3
fix(chat): silver metallic shimmer — near-zero chroma with cool under…
gabrielste1n Mar 24, 2026
e147f7d
fix(chat): match assistant bubble bg to input — both use bg-surface-1
gabrielste1n Mar 24, 2026
e07a9ea
fix(chat): remove redundant new-chat button from ChatHeader
gabrielste1n Mar 24, 2026
efddc53
refactor(chat): remove ChatHeader — title visible in conversation lis…
gabrielste1n Mar 24, 2026
4c14018
chore: delete unused ChatHeader.tsx
gabrielste1n Mar 24, 2026
b48aa53
fix(chat): only show archived toggle when archived chats exist
gabrielste1n Mar 24, 2026
4724f45
refactor(chat): fetch all conversations once, derive archived state c…
gabrielste1n Mar 24, 2026
dacb66b
feat(chat): replace inline search with action buttons + search dialog
gabrielste1n Mar 24, 2026
38978bf
refactor(chat): reuse CommandSearch for chat search, delete ChatSearc…
gabrielste1n Mar 24, 2026
64053bc
fix(linux): force XWayland on GNOME Wayland for window positioning (#…
gabrielste1n Mar 24, 2026
a9a1e36
fix(chat): fix duplicate conversations — includeArchived filter retur…
gabrielste1n Mar 24, 2026
f6510ca
fix(linux): use uinput before portal on GNOME Wayland (#494)
gabrielste1n Mar 24, 2026
3e63bf5
fix(chat): auto-focus input on new chat, always show send button
gabrielste1n Mar 24, 2026
95093e6
feat(chat): add empty state for new chats — subtle SVG illustration +…
gabrielste1n Mar 24, 2026
cbb9e09
fix(chat): update new chat empty state text — mention notes, transcripts
gabrielste1n Mar 24, 2026
fa6392e
fix(chat): default to new empty chat when selecting Chat tab
gabrielste1n Mar 24, 2026
a996347
fix(chat): retain input focus after messages, move copy button to bot…
gabrielste1n Mar 24, 2026
5e880d4
fix(ui): remove vertical accent bar selection indicators
gabrielste1n Mar 24, 2026
a893037
feat(agent): enable local model tool calling + RAG context injection
gabrielste1n Mar 25, 2026
833b73d
style: format chat components, command search, and locale files
gabrielste1n Mar 25, 2026
dc4ac9d
fix(linux): force XWayland on KDE/GNOME Wayland, fix hotkey startup race
gabrielste1n Mar 25, 2026
33eae8c
feat(notes): add embedded chat input to note bottom bar
gabrielste1n Mar 26, 2026
2035b41
feat(notes): add embedded chat panel with floating and sidebar modes
gabrielste1n Mar 26, 2026
942a7fd
refactor(notes): lift embedded chat hook to NoteEditor, simplify Embe…
gabrielste1n Mar 26, 2026
cd34a0a
refactor(notes): remove dead code from embedded chat feature
gabrielste1n Mar 26, 2026
7db0d91
refactor(notes): remove word count from note editor
gabrielste1n Mar 26, 2026
17ea38d
refactor(notes): redesign bottom bar and compact action picker
gabrielste1n Mar 26, 2026
e3d3849
feat(notes): add new note and search notes buttons to sidebar
gabrielste1n Mar 26, 2026
b345064
refactor(ui): align all dialogs with design system guidelines
gabrielste1n Mar 31, 2026
5ac56bf
Merge remote-tracking branch 'origin/main' into feat/agent-tool-calling
gabrielste1n Apr 2, 2026
75b9e9c
fix(meeting): resolve notification popup timing and detection lifecyc…
gabrielste1n Apr 2, 2026
da1eb52
feat(meeting): enable echo cancellation on mic and add note metadata …
gabrielste1n Apr 2, 2026
27803c7
feat(notes): add folder picker to metadata row and clean up input styles
gabrielste1n Apr 2, 2026
cca3aa9
fix(notes): resolve race conditions when switching folders quickly
gabrielste1n Apr 2, 2026
8b8d453
fix(meeting): prevent partial transcript spam and duplicate final seg…
gabrielste1n Apr 2, 2026
d1ad2b0
fix(notes): prevent meeting view from exiting when changing folder
gabrielste1n Apr 2, 2026
5e71cbc
style(ui): increase sidebar search and note metadata visibility
gabrielste1n Apr 2, 2026
21b23a3
fix(meeting): use local transcription provider for notes/meeting reco…
gabrielste1n Apr 2, 2026
2f36cba
fix(meeting): fix auto-detection not firing for browser meetings
gabrielste1n Apr 2, 2026
d0159df
feat(notes): add Actions sidebar button and redesign action editor di…
gabrielste1n Apr 2, 2026
2659338
Merge remote-tracking branch 'origin/main' into feat/agent-tool-calling
gabrielste1n Apr 2, 2026
e52f0c2
fix(build): add missing publisherName to Azure signing config
gabrielste1n Apr 2, 2026
5286776
feat(menu): add Cmd+, / Ctrl+, keyboard shortcut to open Settings
gabrielste1n Apr 2, 2026
a6d433d
fix(ci): fix Windows build signing on PRs and add missing mic-listene…
gabrielste1n Apr 2, 2026
330a36f
fix(permissions): remove mic permission gate, fix system audio detection
gabrielste1n Apr 2, 2026
2485f30
chore: bump version to 1.6.7, update changelog and readme
gabrielste1n Apr 2, 2026
1bf54f0
feat(notes): add save notes as files with folder hierarchy mirror
gabrielste1n Apr 2, 2026
165e0ad
fix(ci): hardcode azureSignOptions values to fix Windows code signing
gabrielste1n Apr 2, 2026
0c496d3
feat(ui): responsive settings dialog for narrow windows
gabrielste1n Apr 2, 2026
0a44474
docs: add save-as-files and responsive settings to changelog and readme
gabrielste1n Apr 2, 2026
5afb4f9
docs: move new features into 1.6.7 changelog section
gabrielste1n Apr 2, 2026
1affc5a
fix(permissions): resolve system audio permission on startup
gabrielste1n Apr 2, 2026
3248c83
fix(permissions): simplify system audio probe, remove stale guard
gabrielste1n Apr 2, 2026
02e68cb
fix(permissions): remove over-engineered marker file, simplify probe
gabrielste1n Apr 2, 2026
e1d1f50
fix(permissions): persist system audio status to disk, remove startup…
gabrielste1n Apr 2, 2026
c59f374
chore(permissions): delete orphaned PermissionsGate, clean up catch
gabrielste1n Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions .github/workflows/build-and-notarize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Cache Electron
uses: actions/cache@v4
with:
Expand Down Expand Up @@ -124,6 +129,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Download nircmd.exe
run: node scripts/download-nircmd.js
env:
Expand All @@ -132,12 +142,17 @@ jobs:
- name: Download windows-fast-paste.exe
run: node scripts/download-windows-fast-paste.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Download windows-key-listener.exe
run: node scripts/download-windows-key-listener.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Download windows-mic-listener.exe
run: node scripts/download-windows-mic-listener.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Cache Electron
uses: actions/cache@v4
Expand All @@ -152,13 +167,16 @@ jobs:
echo "GOOGLE_CALENDAR_CLIENT_ID=${{ secrets.GOOGLE_CALENDAR_CLIENT_ID }}" >> .env
echo "GOOGLE_CALENDAR_CLIENT_SECRET=${{ secrets.GOOGLE_CALENDAR_CLIENT_SECRET }}" >> .env

- name: Build Application
- name: Build and Sign Application
run: npm run build:win -- --publish never
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
VITE_NEON_AUTH_URL: ${{ vars.VITE_NEON_AUTH_URL }}
VITE_OPENWHISPR_API_URL: ${{ vars.VITE_OPENWHISPR_API_URL }}
VITE_OPENWHISPR_OAUTH_CALLBACK_URL: ${{ vars.VITE_OPENWHISPR_OAUTH_CALLBACK_URL }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}

- name: Upload Artifacts
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -212,6 +230,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current --platform darwin --arch ${{ matrix.arch }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}

- name: Cache Electron
uses: actions/cache@v4
with:
Expand Down
25 changes: 24 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Cache Electron
uses: actions/cache@v4
with:
Expand Down Expand Up @@ -116,6 +121,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Download nircmd.exe
run: node scripts/download-nircmd.js
env:
Expand All @@ -131,6 +141,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Download windows-mic-listener.exe
run: node scripts/download-windows-mic-listener.js
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Cache Electron
uses: actions/cache@v4
with:
Expand All @@ -144,13 +159,16 @@ jobs:
echo "GOOGLE_CALENDAR_CLIENT_ID=${{ secrets.GOOGLE_CALENDAR_CLIENT_ID }}" >> .env
echo "GOOGLE_CALENDAR_CLIENT_SECRET=${{ secrets.GOOGLE_CALENDAR_CLIENT_SECRET }}" >> .env

- name: Build Application
- name: Build and Sign Application
run: npm run build:win -- --publish always
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
VITE_NEON_AUTH_URL: ${{ vars.VITE_NEON_AUTH_URL }}
VITE_OPENWHISPR_API_URL: ${{ vars.VITE_OPENWHISPR_API_URL }}
VITE_OPENWHISPR_OAUTH_CALLBACK_URL: ${{ vars.VITE_OPENWHISPR_OAUTH_CALLBACK_URL }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}

build-macos:
runs-on: macos-latest
Expand Down Expand Up @@ -197,6 +215,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Download Qdrant binary
run: node scripts/download-qdrant.js --current --platform darwin --arch ${{ matrix.arch }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Cache Electron
uses: actions/cache@v4
with:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,4 @@ Thumbs.db
.macos-fast-paste.hash
.macos-fast-paste.*.hash
.linux-fast-paste.hash
.qdrant-initialized
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.6.7] - 2026-04-02

### Added

- **Save Notes as Files**: Export notes to the local filesystem as Markdown files, mirroring folder hierarchy
- **Responsive Settings Dialog**: Settings dialog adapts to narrow windows — sidebar collapses to icon rail, rows stack vertically, plan grid reflows
- **Chat Sidebar**: Full sidebar chat tab with conversation history, cloud sync, and semantic search
- **Chat UX Polish**: Empty state with illustration, shimmer thinking/streaming indicator, stop button, action buttons and search dialog
- **Local Semantic Search**: Always-on Qdrant vector DB sidecar for offline semantic search across notes — hybrid FTS5 + vector with Reciprocal Rank Fusion
- **Agent Tool Calling**: Agentic tool-calling system with note management tools (get, create, update, search), cloud agent support with NDJSON streaming, and local model tool calling with RAG context injection
- **Embedded Chat in Notes**: Embedded chat panel in the note editor with floating and sidebar modes
- **Per-GPU Device Selector**: Choose a specific GPU for transcription and intelligence processing (#539)
- **Settings Keyboard Shortcut**: Cmd+, / Ctrl+, keyboard shortcut to open Settings
- **Notes Actions Button**: Actions sidebar button with redesigned action editor dialog
- **Notes Folder Picker**: Folder picker in the note metadata row with cleaned-up input styles
- **Notes Sidebar Buttons**: New note and search notes buttons in the sidebar
- **Meeting Echo Cancellation**: Echo cancellation on mic input and note metadata chips in meeting view
- **Linux Wrapper Script**: Wrapper script to force XWayland and support user flags (#507)

### Changed

- **Vercel AI SDK Migration**: Agent mode migrated from raw API calls to Vercel AI SDK
- **Notes Bottom Bar Redesign**: Redesigned bottom bar with compact action picker
- **Dialog Design System Alignment**: All dialogs aligned with design system guidelines
- **Removed Note Word Count**: Removed word count from note editor
- **Cloud Agent Streaming**: Stream cloud agent responses directly from the renderer via IPC

### Fixed

- **Meeting Auto-Detection**: Fix auto-detection not firing for browser meetings
- **Meeting Transcription Provider**: Use local transcription provider for notes/meeting recording (#530)
- **Meeting Partial Transcript Spam**: Prevent partial transcript spam and duplicate final segments
- **Meeting Notification Timing**: Resolve notification popup timing and detection lifecycle bugs
- **Folder/Note Race Conditions**: Resolve race conditions when switching folders quickly, prevent meeting view from exiting when changing folder, fix rapid delete/switch state management
- **Clipboard Preservation**: Preserve images and HTML in clipboard during paste-and-restore (#381)
- **Transcription Retry Provider**: Retry transcription uses configured provider instead of forcing Parakeet
- **JSON Parse Validation**: Validate JSON.parse result type before calling .replace() in prompts (#541)
- **GPU Selector Polish**: Address code review feedback, rename Intelligence GPU label, fix dropdown chevron padding (#539)
- **Chat Duplicate Conversations**: Fix duplicate conversations — includeArchived filter returned all instead of only archived
- **Linux Wayland Fixes**: Force XWayland on KDE/GNOME Wayland, fix hotkey startup race; use uinput before portal on GNOME Wayland (#468, #494)
- **Mic Permission Gate**: Remove mic permission gate, fix system audio detection
- **Windows Build Signing**: Fix Windows build signing on PRs, add missing mic-listener download, add missing publisherName to Azure signing config
- **Dead optimizeAudio Crash**: Remove dead optimizeAudio call that crashes on recordings over 90 seconds (#524)
- **Download URL Logging**: Remove URL truncation from download log and add failure logging (#540)

### Security

- **picomatch**: Bump to 4.0.4
- **brace-expansion**: Bump to 1.1.13 (security backport)
- **yaml**: Bump to 2.8.3
- **tar**: Bump to 7.5.13

## [1.6.6] - 2026-03-19

### Added
Expand Down
53 changes: 48 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ OpenWhispr is an Electron-based desktop dictation application that uses whisper.
- **whisper.js**: Local whisper.cpp integration and model management
- **parakeet.js**: NVIDIA Parakeet model management via sherpa-onnx
- **parakeetServer.js**: sherpa-onnx CLI wrapper for transcription
- **qdrantManager.js**: Qdrant vector DB sidecar process lifecycle (spawn, health check, shutdown)
- **localEmbeddings.js**: Local text embedding via ONNX Runtime + all-MiniLM-L6-v2 (384-dim vectors)
- **vectorIndex.js**: Qdrant collection management — upsert, delete, search, batch reindex
- **windowConfig.js**: Centralized window configuration
- **windowManager.js**: Window creation and lifecycle management

Expand Down Expand Up @@ -161,6 +164,32 @@ OpenWhispr is an Electron-based desktop dictation application that uses whisper.

- **Download URLs**: Models from sherpa-onnx ASR models release on GitHub

### Local Semantic Search (Qdrant + MiniLM)

Always-on offline semantic search that finds notes by meaning, not just keywords. Used by the AI agent's `search_notes` tool. Qdrant starts automatically on app launch; embedding model auto-downloads on first run if missing.

**Architecture**:
- **Qdrant sidecar**: Rust binary spawned as child process (`qdrantManager.js`), port 6333–6350
- **Embedding model**: `all-MiniLM-L6-v2` via ONNX Runtime (`localEmbeddings.js`), 384-dim vectors
- **Vector index**: Qdrant collection management (`vectorIndex.js`), cosine distance
- **Hybrid search**: FTS5 + Qdrant in parallel → Reciprocal Rank Fusion (K=60) with 0.3 cosine score threshold

**Pipeline**:
1. App launches → Qdrant binary starts → collection created. Embedding model auto-downloads if missing (~22MB)
2. Note create/update/delete → SQLite write → background vector upsert/delete via `_asyncVectorUpsert()`/`_asyncVectorDelete()`
3. Agent searches → `db-semantic-search-notes` IPC → parallel FTS5 + vector search → RRF merge → ranked results

**Search fallback chain** (in `searchNotesTool.ts`): cloud search → local semantic → FTS5 keyword

**Storage**:
- Qdrant data: `~/.cache/openwhispr/qdrant-data/`
- Qdrant binary: `resources/bin/qdrant-{platform}-{arch}` (bundled — downloaded during `prebuild` / `predev`)
- Embedding model: `~/.cache/openwhispr/embedding-models/all-MiniLM-L6-v2/` (auto-downloaded on first launch)

**Dependencies**: `@qdrant/js-client-rest`, `onnxruntime-node`

**Dev setup**: The Qdrant binary downloads automatically via `predev`/`prestart`. The embedding model auto-downloads on first app launch. To manually download: `npm run download:qdrant` and `npm run download:embedding-model`.

### Build Scripts (scripts/)

- **download-whisper-cpp.js**: Downloads whisper.cpp binaries from GitHub releases
Expand All @@ -169,6 +198,8 @@ OpenWhispr is an Electron-based desktop dictation application that uses whisper.
- **download-windows-key-listener.js**: Downloads prebuilt Windows key listener binary
- **download-windows-mic-listener.js**: Downloads prebuilt Windows mic listener binary
- **download-sherpa-onnx.js**: Downloads sherpa-onnx binaries for Parakeet support
- **download-qdrant.js**: Downloads Qdrant vector DB binary for local semantic search
- **download-minilm.js**: Downloads all-MiniLM-L6-v2 ONNX model + tokenizer for local embeddings
- **build-globe-listener.js**: Compiles macOS Globe key listener from Swift source
- **build-macos-mic-listener.js**: Compiles macOS mic listener from Swift source
- **build-windows-key-listener.js**: Compiles Windows key listener (for local development)
Expand Down Expand Up @@ -230,9 +261,9 @@ CREATE TABLE transcriptions (
Settings stored in localStorage with these keys:
- `whisperModel`: Selected Whisper model
- `useLocalWhisper`: Boolean for local vs cloud
- `openaiApiKey`: Encrypted API key
- `anthropicApiKey`: Encrypted API key
- `geminiApiKey`: Encrypted API key
- `openaiApiKey`: API key (plaintext)
- `anthropicApiKey`: API key (plaintext)
- `geminiApiKey`: API key (plaintext)
- `language`: Selected language code
- `agentName`: User's custom agent name
- `reasoningModel`: Selected AI model for processing
Expand Down Expand Up @@ -520,7 +551,8 @@ const { t } = useTranslation();
2. **New Setting**: Update useSettings.ts and SettingsPage.tsx
3. **New UI Component**: Follow shadcn/ui patterns in src/components/ui
4. **New Manager**: Create in src/helpers/, initialize in main.js
5. **New UI Strings**: Add translation keys to all 9 language files (see i18n section above)
5. **New UI Strings**: Add translation keys to all 10 language files (see i18n section above)
6. **New Sidecar Binary**: Add download script in `scripts/`, add to `prebuild*` scripts in package.json, add manager in `src/helpers/`, initialize in `main.js`, shutdown in `will-quit` handler

### Testing Checklist

Expand All @@ -539,6 +571,9 @@ const { t } = useTranslation();
- [ ] Verify meeting detection works with event-driven mode (check debug logs for "event-driven")
- [ ] Test meeting notification suppression during recording
- [ ] Test post-recording cooldown (notifications shouldn't flash immediately)
- [ ] Create a note about "quarterly revenue projections", search via agent for "financial forecast" — should match semantically
- [ ] Verify Qdrant starts on app launch (check debug logs for "qdrant started successfully")
- [ ] Kill Qdrant process manually — verify FTS5 keyword search still works as fallback

### Common Issues and Solutions

Expand Down Expand Up @@ -583,6 +618,14 @@ const { t } = useTranslation();
- Linux: Verify `pactl` is installed (`pulseaudio-utils` or `pipewire-pulse` package)
- If event-driven binary is missing, detection falls back to polling automatically

7. **Local Semantic Search Not Working**:
- Qdrant binary should be in `resources/bin/qdrant-{platform}-{arch}` (auto-downloaded during `predev`/`prebuild`)
- Embedding model should be in `~/.cache/openwhispr/embedding-models/all-MiniLM-L6-v2/model.onnx` (auto-downloaded on first app launch)
- Run `npm run download:qdrant` and `npm run download:embedding-model` manually if missing
- Check debug logs for "qdrant" entries (port, health check, errors)
- If Qdrant fails to start, search still works via FTS5 keyword fallback
- Semantic search is only available through the AI agent's `search_notes` tool, not the manual search UI

### Platform-Specific Notes

**macOS**:
Expand Down Expand Up @@ -650,7 +693,7 @@ const { t } = useTranslation();

## Security Considerations

- API keys stored in system keychain when possible
- API keys stored in plaintext in userData `.env` and localStorage (not yet encrypted — see #532)
- Context isolation enabled
- No remote code execution
- Sanitized file paths
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
- **Google**: Gemini 3.1 Pro, Gemini 3 Flash, Gemini 2.5 Flash Lite
- **Groq**: Ultra-fast inference with Llama and Mixtral models
- **Local**: Qwen, LLaMA, Mistral, Gemma models via llama.cpp
- 🛠️ **Agent Tool Calling**: Agentic tools for searching, creating, and updating notes — with RAG context injection for local models
- 🤖 **AI Actions**: Apply AI-powered actions to notes with customizable processing templates

### Meeting Transcription
Expand All @@ -59,8 +60,11 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file

- 📝 **Notes System**: Create, edit, and organize notes with folders, audio upload, and real-time dictation
- 🔎 **Full-Text Search**: FTS5-powered search across all note content with Cmd+K command palette
- 🧠 **Local Semantic Search**: Always-on Qdrant vector DB with MiniLM embeddings for offline meaning-based search across notes
- ☁️ **Cloud Sync**: Local-first storage with cloud backup and semantic search
- 💬 **Embedded Chat**: Chat panel in the note editor with floating and sidebar modes
- 📁 **Folder Organization**: Organize notes into custom folders with drag-and-drop
- 💾 **Save Notes as Files**: Export notes to the local filesystem as Markdown files, mirroring your folder hierarchy

### Cloud & Account

Expand All @@ -73,6 +77,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file

- 🌐 **Cross-Platform**: Works on macOS, Windows, and Linux
- 🎨 **Modern UI**: Built with React 19, TypeScript, and Tailwind CSS v4
- 📱 **Responsive Settings**: Settings dialog adapts to narrow windows with collapsible icon-rail sidebar and stacked layouts
- 🖱️ **Draggable Interface**: Move the dictation panel anywhere on your screen with configurable start position
- 🌐 **Globe Key Toggle (macOS)**: Optional Fn/Globe key listener for a hardware-level dictation trigger — no Input Monitoring permission required
- ⌨️ **Compound Hotkeys**: Support for multi-key combinations like `Cmd+Shift+K`
Expand Down Expand Up @@ -849,7 +854,7 @@ A: No. As of v1.6.0, OpenWhispr uses NSEvent monitors instead of CGEvent taps, e

## Project Status

OpenWhispr is actively maintained and ready for production use. Current version: 1.6.6
OpenWhispr is actively maintained and ready for production use. Current version: 1.6.7

- ✅ Core dictation with local and cloud processing
- ✅ Cross-platform support (macOS, Windows, Linux)
Expand Down
7 changes: 5 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ Out of scope:
- **Local-first audio processing** — Audio is transcribed on-device using
whisper.cpp or nvidia parakeet. Recordings are not sent to external servers unless explicitly
configured by the user.
- **Credential storage** — Sensitive credentials are stored using Electron's
`safeStorage` API where available.
- **Credential storage** — API keys provided by users (BYOK) are stored in
plaintext in the app's `userData` directory (`.env` file and Electron
`localStorage`). They are readable by any process running as the current OS
user. Migrating to Electron's `safeStorage` API for platform-native
encryption is tracked in [#532](https://github.com/OpenWhispr/openwhispr/issues/532).
- **Native binaries** — Platform-specific helpers (key listeners, paste
utilities) are compiled from source during the build process.
- **Context isolation** — The Electron renderer runs with context isolation
Expand Down
Loading
Loading