···551. **Network search**: server-side search via Bluesky APIs - no local indexing. Always available.
662. **Local search**: full-text + semantic search over the **authenticated user's own** liked and bookmarked/saved posts, stored locally in SQLite.
7788-Local semantic search (embeddings) is **opt-out**: enabled by default, but can be disabled in settings. When disabled, only local keyword (FTS) search is available and the embedding model is not downloaded.
88+Local semantic search (embeddings) is **opt-in** and **off by default**. Keyword search remains available without setup. When embeddings are enabled, Lazurite downloads the model locally and unlocks semantic and hybrid search for synced posts.
991010## Network Search (not indexed)
1111···77771. **Sync**: on login and periodically, fetch the authenticated user's own likes (`app.bsky.feed.getActorLikes`) and bookmarks. Paginate using the API cursor, store posts in SQLite.
78782. **Cursor persistence**: store the last-seen API cursor per `(did, source)` in the `sync_state` table. On subsequent syncs, resume from the stored cursor so we only fetch new posts - never re-fetch the full history.
79793. **Index FTS**: insert post text into SQLite FTS5 virtual table for keyword search (always active).
8080-4. **Embed** _(opt-out)_: run post text through `fastembed` with `nomic-embed-text-v1.5` (768-dim). Store vectors in `sqlite-vec` virtual table. Skipped when embeddings are disabled.
8080+4. **Embed** _(optional)_: run post text through `fastembed` with `nomic-embed-text-v1.5` (768-dim). Store vectors in `sqlite-vec` virtual table. Skipped unless the user opts in.
81815. **Reindex**: a manual "Reindex" action clears all embeddings from `posts_vec` and re-embeds every post. Useful after model updates or if the index becomes corrupted.
82828383## SQLite Schema
···108108-- Full-text search (always active)
109109CREATE VIRTUAL TABLE posts_fts USING fts5(text, uri UNINDEXED, content=posts, content_rowid=rowid);
110110111111--- Vector embeddings (opt-out - only populated when embeddings enabled)
111111+-- Vector embeddings (optional - only populated when embeddings enabled)
112112CREATE VIRTUAL TABLE posts_vec USING vec0(
113113 uri TEXT PRIMARY KEY,
114114 embedding float[768]
···129129- Model: `nomic-embed-text-v1.5` via `fastembed` (ONNX runtime, no GPU required)
130130- Dimensions: 768 (or 256 with Matryoshka truncation for speed)
131131- Batch embedding on sync; single embedding on search query
132132-- Model downloaded on first use, cached in Tauri app data dir (skipped entirely when embeddings disabled)
132132+- Model downloaded after the user explicitly enables semantic search, cached in Tauri app data dir
133133134134## Tauri Commands
135135···155155sync_posts(did: String, source: "like"|"bookmark") -> SyncStatus // resumes from stored cursor
156156get_sync_status(did: String) -> SyncStatus
157157reindex_embeddings() -> () // clears & re-embeds all posts
158158-set_embeddings_enabled(enabled: bool) -> () // opt-out toggle
158158+set_embeddings_enabled(enabled: bool) -> () // explicit opt-in toggle
159159+set_embeddings_preflight_seen(seen: bool) -> () // dismiss first-run semantic-search setup
159160```
160161161162## Keyboard Shortcuts
···172173- Mode switcher: `Motion` sliding indicator underline between tabs
173174- Sync status: animated progress bar during sync, `Presence` fade-out when complete
174175- Highlighted keyword matches in result text
175175-- Model download: progress bar on first launch with percentage + ETA
176176+- First Search visit can open a dedicated semantic-search preflight when embeddings are still off
177177+- Preflight explains that keyword/network search already work, embeddings are optional, and enabling downloads the model locally
178178+- Model download: progress bar with percentage + ETA while the local model is being prepared
176179- Empty state: illustration with prompt when no posts synced yet
+3-3
docs/specs/settings.md
···2424| `notifications_desktop` | boolean | `true` | Show OS desktop notifications |
2525| `notifications_badge` | boolean | `true` | Show unread badge on app icon / tray |
2626| `notifications_sound` | boolean | `false` | Play sound on new notification |
2727-| `embeddings_enabled` | boolean | `true` | Enable semantic search (already exists) |
2727+| `embeddings_enabled` | boolean | `false` | Enable optional semantic search |
2828| `constellation_url` | string | `"https://constellation.microcosm.blue"` | Constellation instance base URL |
2929| `spacedust_url` | string | `"https://spacedust.microcosm.blue"` | Spacedust instance base URL |
3030| `spacedust_instant` | boolean | `false` | Bypass Spacedust 21-second debounce buffer |
···86868787### 5. Search & Embeddings
88888989-- **Embeddings toggle**: opt-out of semantic search. When disabled, the embedding model is not downloaded and only keyword search is available. Toggling off does not delete existing embeddings — a separate "Clear embeddings" action handles that.
9090-- **Model status**: shows whether `nomic-embed-text-v1.5` is downloaded, its size on disk, and a "Download now" / "Remove model" action
8989+- **Embeddings toggle**: opt in to semantic search. It is off by default. When disabled, the embedding model is not downloaded and only keyword search is available. Toggling off does not delete existing embeddings — a separate "Clear embeddings" action handles that.
9090+- **Model status**: shows whether `nomic-embed-text-v1.5` is downloaded, its size/download cost, and retry state if setup fails
9191- **Reindex**: triggers a full re-embed of all synced posts. Shows progress bar during operation.
92929393### 6. Services
+9-9
docs/tasks/07-search.md
···5656 - `semantic`: embed query string → vec similarity search (requires embeddings enabled)
5757 - `hybrid`: run both, merge via reciprocal rank fusion (falls back to keyword-only if embeddings disabled)
5858- [x] `get_sync_status(did)` → last sync time, post counts, cursor state
5959-- [x] Model management: download `nomic-embed-text-v1.5` ONNX on first use to `<app_data_dir>/models/` (skipped when embeddings disabled)
5959+- [x] Model management: download `nomic-embed-text-v1.5` ONNX after explicit opt-in to `<app_data_dir>/models/` (skipped when embeddings disabled)
6060- [x] Background sync: trigger after login, then every 15 min
61616262### Frontend
···68686969#### Embeddings
70707171-- [ ] embeddings opt-out toggle in settings (disables semantic search, skips model download)
7272-- [ ] model download progress bar (percentage + ETA) on first launch
7373- - Enabled by default (opt-out)
7474- - Splash/Preflight route should explain what semantic search provides
7171+- [x] embeddings opt-in toggle in settings/search UI (keeps semantic search off by default, skips model download until enabled)
7272+- [x] model download progress bar (percentage + ETA) during first semantic-search setup
7373+ - Semantic search is off by default
7474+ - Dedicated preflight route explains what semantic search provides before download starts
75757676#### Sync Indexing
77777878-- [ ] sync status indicator with animated progress bar, `Presence` fade-out on complete
7979-- [ ] reindex button: triggers `reindex_embeddings()`, shown in search settings or sync status area
8080-- [ ] empty state illustration when no posts synced yet
8181-- [ ] `Tab` cycles search mode (network → keyword → semantic → hybrid), `Escape` clears
7878+- [x] sync status indicator with animated progress bar, `Presence` fade-out on complete
7979+- [x] reindex button: triggers `reindex_embeddings()`, shown in search settings or sync status area
8080+- [x] empty state illustration when no posts synced yet
8181+- [x] `Tab` cycles search mode (network → keyword → semantic → hybrid), `Escape` clears