Grove is a local-first semantic desktop search app built with Tauri v2, Rust, React, Vite, and TypeScript. It indexes files from folders you choose, generates Gemini embeddings for their contents, and lets you search them with natural language instead of exact filenames or keywords.
The app is designed for documents, code, PDFs, images, and small media files. Index data stays on the local machine; file content is only sent to Gemini when embeddings are generated.
- Open the GitHub Releases page for Grove.
- Download the installer or app bundle for your OS.
- Install and launch Grove.
- On first launch, choose one or more folders to index.
- Wait for the initial indexing pass to finish.
- Start searching with natural language in the main search view.
What to expect on first use:
- Grove will crawl only the folders you select.
- It builds embeddings locally with Gemini and stores the index on your machine.
- After indexing finishes, the app keeps watching those folders for changes.
- Clicking a result shows an in-app preview;
Openlaunches the file andRevealshows it in your system file explorer.
If you are using an official GitHub release build that was created with the GROVE_API_KEY GitHub Actions secret, the app can work without manual API key setup. If your downloaded build does not include a baked-in key, open Settings in the app and add your Gemini API key there.
- Pick a small test folder first so the first indexing run is fast.
- Include a mix of text files, code, images, and PDFs if you want to see the strongest demo cases.
- PDF preview and extraction may depend on
pdftotextbeing present on Linux. - Binary files over 10 MB are skipped on the multimodal path.
- If you see "No Gemini API key found", the release build was likely created without a baked-in key. Add a key in Settings or use a newer official build.
- If indexing is slow, start with fewer folders and avoid very large media-heavy trees.
- If Linux launch fails, install the native Tauri dependencies listed below.
- Indexes selected folders recursively.
- Supports semantic search across text, code, PDFs, images, audio, and video.
- Uses Gemini Embedding 2 for both document embeddings and query embeddings.
- Keeps a live filesystem watcher running after indexing so changes can be synced automatically.
- Opens files directly from search results or reveals them in the system file explorer.
- Frontend: React 19, Vite 7, TypeScript, Tailwind CSS
- Desktop shell: Tauri v2
- Backend: Rust + Tokio
- Embeddings: Gemini Embedding 2
- Local storage:
vectors.jsonfor vector payloadsindexed-roots.jsonfor watched folders- there is also a SQLite metadata layer in the repo, but the active search flow currently uses the JSON vector store
src/: React UI, search UX, setup flow, indexing status screens, settings panelsrc-tauri/src/commands.rs: Tauri commands, indexing orchestration, search pipeline, watcher bootstrap, API key resolutionsrc-tauri/src/indexer/: crawling, extraction, chunking, media/PDF helpers, filesystem watchersrc-tauri/src/embedding/: Gemini request builders and HTTP client logicsrc-tauri/src/store/vector.rs: in-memory vector store with JSON persistence, dense search, lexical search, and pruning helpers.github/workflows/release.yml: tagged release builds for Linux, Windows, and macOS
Allowed extensions currently include:
- Text and code:
txt,md,rs,py,js,ts,jsx,tsx,go,c,cpp,h,java,cs,json,yaml,yml,toml - Documents:
pdf,docx,pptx - Images:
png,jpg,jpeg,webp - Media:
mp4,mov,mp3,wav,m4a
Ignored directories include common large/generated folders such as node_modules, .git, target, dist, build, .cache, .next, .svelte-kit, and virtual environments.
- The app recursively crawls the selected root folders.
- Files are processed with up to 8 concurrent workers.
- Text/code files are extracted and chunked into 512-token chunks with 64-token overlap.
- Text chunks are embedded in batches of up to 100 requests.
- PDFs/images/audio/video use Gemini's native multimodal embedding path.
- Binary files larger than 10 MB are skipped.
- Vectors are normalized and stored in a local JSON-backed vector store.
- After indexing, a filesystem watcher keeps the index in sync for watched roots.
Important implementation detail: a full re-index clears the existing vector store and rebuilds it. Live watcher updates handle subsequent file creates, edits, renames, and deletes.
Search is currently hybrid:
- Dense semantic retrieval using a Gemini query embedding with
taskType: RETRIEVAL_QUERY - Lexical retrieval over filename, path, file type, and stored text excerpts
- Reciprocal-rank fusion plus a small reranking bonus for filename, path, snippet, code intent, and file-type hints
Other current search behavior:
- Dense vector threshold is
0.35 - The backend works from up to 100 chunk candidates
- Results are merged to file-level results and truncated to the top 20 files
- Image results can include inline base64 thumbnails
The app stores data under the OS local app data directory in a grove folder.
On Linux this resolves to:
~/.local/share/grove
Key files:
vectors/vectors.json: persisted vector storeindexed-roots.json: watched/indexed root folders
Gemini API keys are resolved in this order:
GROVE_API_KEYbaked in at compile timeVISH_API_KEYbaked in at compile time for backward compatibilityGEMINI_API_KEYbaked in at compile time- Runtime
GEMINI_API_KEY GEMINI_API_KEYfrom a root.envfile- Empty value, which means the user must set a key in the app
Example .env:
GEMINI_API_KEY=your_key_here- Node.js 18+ with
npm - Rust stable toolchain
- Tauri system dependencies for your platform
- A Gemini API key unless you are building with a baked-in key
npm installnpm run tauri devnpm run devnpm run tauri buildTauri on Linux typically needs WebKitGTK and related native packages. The CI workflow installs:
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libsqlite3-devIf npm run tauri dev or npm run tauri build fails on Linux, missing native Tauri dependencies are the first thing to check.
# desktop app dev
npm run tauri dev
# frontend only
npm run dev
# frontend production build
npm run build
# tauri CLI passthrough
npm run tauriWhen bumping versions, keep these three files in sync:
package.jsonsrc-tauri/Cargo.tomlsrc-tauri/tauri.conf.json
Use the helper script:
./scripts/bump-version.sh 1.0.0Releases are built by GitHub Actions on pushed tags matching v*.
Example:
git tag v1.0.0
git push origin v1.0.0The workflow in .github/workflows/release.yml builds for:
- Linux
- Windows
- macOS Apple Silicon
- macOS Intel
The release workflow currently injects the compile-time key through GROVE_API_KEY.
.
├── src/ # React frontend
├── src-tauri/ # Rust backend and Tauri config
├── scripts/ # repo scripts, including version bump helper
├── .github/workflows/ # CI and release automation
├── docs/ # project docs and planning notes
└── .claude/ # Claude-specific product, design, and mockup context
The .claude/ directory is support material for repository context, not runtime app code. It currently contains:
CLAUDE.md: repo guidance and architecture summary for Claude Codedocs/prd.md: product requirements and original product framingdocs/architecture_deep_dive.md: a long-form explanation of indexing, embedding, search, and watchingdocs/eng_design.md,docs/implementation_plan.md,docs/soul.md: planning, design direction, and product intentdocs/SHIPPING.md: release/distribution notesmockups/: visual references for setup/search/results screenssettings.local.json: local Claude tool settings
Those docs are useful for intent and planning, but the Rust and React code are the source of truth for current behavior.
docxandpptxare allowed by the crawler, but extraction is still placeholder-based rather than full structured parsing.- The repo includes a SQLite metadata store module, but the active search path is powered by the JSON vector store.
- Full rebuild indexing clears previous vectors first.
- Files over 10 MB on the multimodal path are skipped.
If you are new to the codebase, start here:
src/App.tsxsrc/hooks/useAppState.tssrc/hooks/useSearch.tssrc-tauri/src/commands.rssrc-tauri/src/store/vector.rssrc-tauri/src/indexer/crawler.rssrc-tauri/src/indexer/extractor.rssrc-tauri/src/indexer/watcher.rs
Current version in the repo:
- App version:
1.0.0
This README documents the codebase as it exists in the repository now, not just the older planning docs.