diff --git a/AGENTS.md b/AGENTS.md index 1b07190..0dbab9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,9 +2,7 @@ ## Project Overview -Heimgeist is a local desktop chat app for Ollama. It uses a React/Vite renderer, an Electron desktop shell, a FastAPI backend, SQLite chat storage, Whisper transcription, optional SearXNG web search, and local RAG libraries under the backend. - -A future migration to Tauri is planned, but do not begin that migration unless the task explicitly asks for it. Electron support must remain intact until Tauri reaches feature parity. +Heimgeist is a local desktop chat app for Ollama. It uses a React/Vite renderer, a Tauri desktop shell, a FastAPI backend, SQLite chat storage, Whisper transcription, optional SearXNG web search, and local RAG libraries under the backend. ## Important Directories and Entry Points @@ -14,11 +12,8 @@ A future migration to Tauri is planned, but do not begin that migration unless t - `src/chatApi.js`, `src/chatGeneration.js`, and `src/backendApi.js` contain backend request and streaming helpers. - `src/desktop/desktopApi.js` is the renderer platform abstraction for desktop APIs. - `src/styles.css` contains the main UI styling. -- `electron/` - Electron desktop shell. - - `electron/main.cjs` creates windows, stores settings, handles updates, and implements IPC handlers. - - `electron/preload.cjs` exposes the Electron IPC surface as `window.electronAPI`. -- `src-tauri/` - isolated Tauri migration scaffold. - - `src-tauri/src/main.rs` owns Tauri commands for the renderer `desktopApi` surface. +- `src-tauri/` - Tauri desktop shell. + - `src-tauri/src/main.rs` owns Tauri commands for the renderer `desktopApi` surface, settings persistence, dialogs, path opening, external links, focus events, and update placeholders. - `src-tauri/tauri.conf.json` points Tauri at the existing Vite renderer. - `src-tauri/capabilities/` contains Tauri permission grants for enabled plugins. - `backend/` - FastAPI backend and local processing. @@ -29,33 +24,28 @@ A future migration to Tauri is planned, but do not begin that migration unless t - `backend/database.py` points SQLite at `backend/app.db`. - `scripts/` - development wrappers used by npm scripts. - `scripts/run-backend.cjs` starts Uvicorn from `backend/.venv`. - - `scripts/run-electron-dev.cjs` waits for Vite and FastAPI, then launches Electron. - `scripts/run-tauri-dev.cjs` starts or reuses FastAPI, then launches the Tauri dev shell. - `run.sh` - bootstrap script for local development dependencies and dev startup. -- `vite.config.js` - Vite dev/build configuration. Electron dev uses `127.0.0.1:5173`; Tauri dev uses an additive strict Vite port at `127.0.0.1:5174`. +- `vite.config.js` - Vite dev/build configuration. Tauri dev uses the strict Vite port `127.0.0.1:5174`. ## Run and Build Commands - `./run.sh` - bootstrap/update Python and npm dependencies, then start the full dev stack. -- `npm run dev` - start backend, Vite renderer, and Electron together. +- `npm run dev` - start or reuse FastAPI on `127.0.0.1:8000`, start the Vite renderer on `127.0.0.1:5174`, then launch Tauri. +- `npm run dev:tauri` - alias for the primary Tauri development workflow. - `npm run dev:backend` - start FastAPI on `127.0.0.1:8000` with reload. Requires `backend/.venv`. -- `npm run dev:renderer` - start Vite on `127.0.0.1:5173`. -- `npm run dev:renderer:tauri` - start Vite on `127.0.0.1:5174` for Tauri. -- `npm run dev:electron` - wait for Vite and backend health, then start Electron. -- `npm run dev:tauri` - start or reuse FastAPI on `127.0.0.1:8000`, start the Tauri Vite renderer on `127.0.0.1:5174`, then launch the Tauri shell. +- `npm run dev:renderer` - start Vite on `127.0.0.1:5174` for Tauri. - `npm run dev:tauri:shell` - launch the raw Tauri shell when backend lifecycle is managed separately. - `npm run build` - build the renderer into `dist/`. -- `npm start` - start Electron against the current app files. +- `npm start` - alias for `npm run dev`. There are currently no npm `test` or `lint` scripts in `package.json`. ## Architectural Boundaries -- Renderer code should remain platform-neutral where practical. It may call backend HTTP APIs and may call `desktopApi`, but it should not call `window.electronAPI` directly. -- `src/desktop/desktopApi.js` is the renderer's platform abstraction. Add desktop capabilities there first, then back them with Electron IPC. This keeps the future Tauri migration bounded. -- `electron/preload.cjs` is the only file that should expose raw Electron IPC to the renderer. -- `electron/main.cjs` owns desktop concerns: windows, dialogs, shell opening, settings persistence, update checks, and IPC implementations. -- `src-tauri/src/main.rs` owns the Tauri implementation of the same renderer `desktopApi` surface during migration. Keep it additive and do not remove Electron behavior until Tauri reaches parity. +- Renderer code should remain platform-neutral where practical. It may call backend HTTP APIs and may call `desktopApi`, but it should not import or call Tauri APIs directly. +- `src/desktop/desktopApi.js` is the renderer's platform abstraction. Add desktop capabilities there first, then back them with Tauri commands/events. +- `src-tauri/src/main.rs` owns desktop concerns: windows, menus, dialogs, shell opening, settings persistence, update placeholders, focus events, and Tauri command implementations. - Backend code owns chat/session persistence, Ollama integration, Whisper transcription, web search enrichment, and RAG library processing. - Backend API contracts should stay stable unless intentionally coordinated with renderer changes. If a response/request shape changes in `backend/schemas.py` or route handlers, update the renderer callers in the same change. - Keep local RAG job orchestration and generated library state in the backend. Renderer code should use backend endpoints rather than reading library files directly. @@ -70,28 +60,27 @@ Do not edit or commit generated/runtime data unless the task explicitly requires - `node_modules/` - npm dependencies. - `dist/` - Vite build output. - `__pycache__/`, `*.pyc`, `.DS_Store`, and similar machine-generated files. -- Local app settings files under the Electron user data directory, the Tauri app config directory, or `HEIMGEIST_SETTINGS_FILE`. +- Local app settings files under the Tauri app config directory or `HEIMGEIST_SETTINGS_FILE`. - Tauri-generated `src-tauri/target/`, `src-tauri/gen/`, and local `src-tauri/Cargo.lock` if generated by local verification. Avoid broad file operations that traverse these directories. Use ignore patterns with search tools when inspecting the repo. ## Verification Expectations -- Frontend changes: run `npm run build` at minimum. For UI or interaction changes, also run the dev stack and exercise the affected flow in Electron. +- Frontend changes: run `npm run build` at minimum. For UI or interaction changes, also run the dev stack and exercise the affected flow in Tauri. - Backend changes: run a targeted syntax/import check such as `backend/.venv/bin/python -m py_compile backend/main.py backend/local_rag.py` for touched modules, then start `npm run dev:backend` or the full dev stack and check `GET /health`. -- Desktop bridge/Electron changes: run the full dev stack with `npm run dev` and verify Electron launches, settings load/save, dialogs or shell actions work, and no renderer code bypasses `src/desktop/desktopApi.js`. -- Tauri desktop bridge changes: run `cargo check --manifest-path src-tauri/Cargo.toml` with a temp `CARGO_TARGET_DIR` when useful, run `npm run build`, and if practical run `npm run dev:tauri`. Use a temporary `HEIMGEIST_SETTINGS_FILE` when testing ordinary shared settings behavior; use a temporary `HOME` with a fake Electron settings file when testing first-run import, because `HEIMGEIST_SETTINGS_FILE` intentionally bypasses import. +- Desktop bridge/Tauri changes: run `cargo check --manifest-path src-tauri/Cargo.toml` with a temp `CARGO_TARGET_DIR` when useful, run `npm run build`, and if practical run `npm run dev`. Use a temporary `HEIMGEIST_SETTINGS_FILE` when testing ordinary shared settings behavior; use a temporary `HOME` with a fake legacy settings file when testing first-run import, because `HEIMGEIST_SETTINGS_FILE` intentionally bypasses import. - API contract changes: verify both sides together. Update backend schemas/routes and renderer callers in the same change, then exercise the affected request path. - RAG, Whisper, Ollama, or SearXNG changes: note any external services or local models required for verification, and test graceful failure paths when those services are unavailable. -## Future Tauri Migration Guidance +## Tauri Guidance -- Do not start a Tauri migration opportunistically. -- Keep new renderer desktop calls behind `src/desktop/desktopApi.js`; do not spread Electron-specific assumptions through React components. -- Keep Tauri renderer calls behind `src/desktop/desktopApi.js`; do not import Tauri APIs directly in React components. -- When adding desktop capabilities, prefer method names and payloads that could map cleanly to either Electron IPC or Tauri commands. -- Maintain Electron behavior while any Tauri work is incomplete. Electron remains the supported desktop shell until Tauri reaches feature parity for settings, file picking/opening, external links, update flow, window events, backend startup expectations, and packaging. -- During migration, Tauri settings should import Electron settings only on first run when Tauri settings do not already exist. Preserve `HEIMGEIST_SETTINGS_FILE` as an explicit shared override and do not move or rewrite `backend/app.db` or `backend/libraries`. +- Keep renderer desktop calls behind `src/desktop/desktopApi.js`; do not import Tauri APIs directly in React components. +- When adding desktop capabilities, prefer method names and payloads that stay stable for renderer callers. +- Preserve `HEIMGEIST_SETTINGS_FILE` as an explicit shared settings override. +- Keep first-run legacy settings import available when Tauri settings do not already exist. +- Do not move or rewrite `backend/app.db` or `backend/libraries`; the development backend must keep using the existing backend working directory. +- Production-release work still needs backend sidecar packaging, signed updater/changelog parity, bundle metadata, signing/notarization, and installer behavior. - Avoid refactors that mix migration prep with unrelated feature work. Migration work should be explicit and reviewable. ## Coding and Refactor Guidelines @@ -107,7 +96,7 @@ Avoid broad file operations that traverse these directories. Use ignore patterns ## Known Fragile Areas -- The Electron bridge is intentionally narrow. Direct `window.electronAPI` use in renderer files will make Tauri migration harder. +- The Tauri bridge is intentionally narrow. Direct `window.__TAURI__` use outside `src/desktop/desktopApi.js` makes desktop behavior harder to reason about. - `src/App.jsx`, `src/chatGeneration.js`, and backend chat routes share assumptions about streaming, regeneration, attachments, source metadata, and session state. - `backend/main.py` creates/migrates SQLite tables at import/startup. Schema changes need care because they run against local user data. - `backend/local_rag.py` coordinates asynchronous jobs, file registration, generated artifacts, and per-library locks. Avoid changes that can start duplicate jobs or corrupt `backend/libraries/`. diff --git a/README.md b/README.md index 364fbfb..478e1a9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Heimgeist -Heimgeist is a local desktop chat client for Ollama. It combines an Electron + React renderer with a FastAPI backend, stores chat history in SQLite, supports optional SearXNG-backed web search, and can enrich prompts with context from local library indexes. +Heimgeist is a local desktop chat client for Ollama. It combines a Tauri + React renderer with a FastAPI backend, stores chat history in SQLite, supports optional SearXNG-backed web search, and can enrich prompts with context from local library indexes. ## Features -- Local desktop chat UI with Electron +- Local desktop chat UI with Tauri - Ollama-backed chat with streaming and non-streaming replies - Persistent chat sessions and automatic title generation - Edit-and-regenerate flow for earlier user messages @@ -25,7 +25,7 @@ When files are added or removed, Heimgeist automatically rebuilds the local RAG ## Stack -- Frontend: Electron, React, Vite +- Frontend: Tauri, React, Vite - Backend: FastAPI, SQLAlchemy, SQLite - Search enrichment: SearXNG + page fetching/reranking - Local RAG pipeline: corpus build, enrichment, embedding, and retrieval helpers under `backend/rag/` @@ -80,9 +80,10 @@ npm run dev │ ├── database.py │ ├── schemas.py │ └── requirements.txt -├── electron/ -│ ├── main.cjs -│ └── preload.cjs +├── src-tauri/ +│ ├── src/main.rs +│ ├── tauri.conf.json +│ └── capabilities/ ├── src/ │ ├── App.jsx │ ├── LibraryManager.jsx diff --git a/docs/tauri-migration.md b/docs/tauri-migration.md index 13d4411..4ce0766 100644 --- a/docs/tauri-migration.md +++ b/docs/tauri-migration.md @@ -1,74 +1,63 @@ # Tauri Migration Notes -Tauri is now the primary experimental development shell for Heimgeist. Electron remains intact as a fallback until the remaining desktop and packaging gaps are closed. +Tauri is now Heimgeist's active desktop shell for local development. The former desktop shell runtime files and npm scripts have been removed from active development code. -References checked during the spike: +## Current Development Workflow -- Tauri Vite setup: https://v2.tauri.app/start/frontend/vite/ -- Tauri JavaScript API: https://v2.tauri.app/reference/javascript/api/ -- Tauri CLI: https://v2.tauri.app/reference/cli/ -- Tauri dialog plugin: https://v2.tauri.app/plugin/dialog/ -- Tauri opener plugin: https://v2.tauri.app/plugin/opener/ +- Primary dev command: `npm run dev`. +- Compatibility alias: `npm run dev:tauri`. +- The dev wrapper is `scripts/run-tauri-dev.cjs`. +- The wrapper starts or reuses FastAPI on `127.0.0.1:8000`, waits for `/health`, then launches Tauri. +- The Vite renderer runs on strict port `127.0.0.1:5174`. +- `npm run dev:tauri:shell` launches raw `tauri dev` when the backend lifecycle is managed separately. -## Current Desktop Responsibility Map - -| Area | Electron implementation | Tauri status | -| --- | --- | --- | -| Main app window | `BrowserWindow` in `electron/main.cjs`, loading Vite in dev and `dist/index.html` in production | Implemented through `src-tauri/tauri.conf.json`; dev loads the same React/Vite renderer on the Tauri-specific port `5174` | -| Settings window | Separate modal `BrowserWindow` routed to `#/settings` | Later phase: either a second Tauri webview window or the existing in-app settings route | -| Settings persistence | JSON under Electron `app.getPath('userData')`, or `HEIMGEIST_SETTINGS_FILE` when set | Implemented with persistent JSON under Tauri app config, with a first-run Electron settings import when safe | -| Renderer bridge | `electron/preload.cjs` exposes `window.electronAPI`; renderer uses `src/desktop/desktopApi.js` | Implemented: `desktopApi` still prefers Electron and falls back to Tauri commands/listeners | -| File picker | `dialog.showOpenDialog` via `pick-paths` IPC | Implemented through the official Tauri dialog plugin; supports the existing `title`, `filters`, and `multiple` option shape where practical | -| Open file/path | `shell.openPath` via `open-path` IPC | Implemented through the official Tauri opener plugin | -| External links | `shell.openExternal` and `setWindowOpenHandler` | Implemented through the official Tauri opener plugin for `http`, `https`, `mailto`, and `tel` URLs | -| Window focus events | Electron `focus` event forwarded to renderer | Implemented by emitting `window-focused` from Tauri and listening in `desktopApi` | -| App menu | Electron `Menu.buildFromTemplate` | Basic Tauri default menu implemented; detailed Electron menu parity remains later work | -| UI scale | Electron `webContents.setZoomFactor` | Implemented for Tauri/browser-like runtimes through `desktopApi.applyUiScale`, which applies renderer CSS zoom while leaving Electron native zoom unchanged | -| DevTools preference | Electron opens/closes DevTools in dev | Later phase: no clean stable Tauri equivalent is wired yet | -| Updates/changelog | Git-based update check, pull, restart, and local changelog | Later phase: replace with Tauri updater or another signed update flow | -| Backend lifecycle | External Node scripts start FastAPI in dev | Development parity implemented by `scripts/run-tauri-dev.cjs`, which starts or reuses the existing FastAPI dev backend; Python sidecar packaging remains later | -| Packaging | Electron starts from `main` and existing npm scripts | Later phase: Tauri bundle config, icons, signing/notarization, and Python backend sidecar | - -## Development Workflow - -- Electron development remains unchanged: `npm run dev`. -- Tauri development is now `npm run dev:tauri` or `npm run dev:tauri:full`. -- The Tauri wrapper starts or reuses FastAPI on `127.0.0.1:8000`, waits for `/health`, then launches Tauri. -- Tauri uses its own strict Vite dev port: `127.0.0.1:5174`. This avoids conflicts with the existing Electron renderer port `5173`. -- The raw Tauri shell remains available as `npm run dev:tauri:shell`; use it only when the backend lifecycle is managed separately. - -The Tauri dev backend is still the normal FastAPI backend started from the repository root through `scripts/run-backend.cjs`. That keeps chat history and local RAG data in the existing backend locations. +The development backend is still the normal FastAPI backend started from the repository root through `scripts/run-backend.cjs`. ## User Data Continuity -- Chats continue to use `backend/app.db` through the existing FastAPI backend. No database move, rewrite, or migration is part of this step. -- Local RAG libraries continue to use `backend/libraries` through the existing FastAPI backend. No library state is moved or rewritten. -- `HEIMGEIST_SETTINGS_FILE` remains an explicit shared settings override for both Electron and Tauri. When it is set, Tauri reads and writes that file directly and does not perform first-run import. +- Chats continue to use `backend/app.db` through the existing FastAPI backend. +- Local RAG libraries continue to use `backend/libraries` through the existing FastAPI backend. +- No database or library state is moved, rewritten, or migrated by the Tauri shell. +- `HEIMGEIST_SETTINGS_FILE` remains an explicit shared settings override. When set, Tauri reads and writes that file directly and skips first-run import. - Without `HEIMGEIST_SETTINGS_FILE`, Tauri stores settings in its app config `settings.json`. -- On first Tauri run only, when the Tauri settings file does not exist, Tauri attempts to read Electron settings from the platform config directory, including the existing `Heimgeist/settings.json` path used by Electron. -- If Electron settings are found, Tauri migrates and normalizes them into the Tauri settings path. -- Existing Tauri settings are not replaced by Electron settings. +- On first Tauri run only, when the Tauri settings file does not exist, Tauri attempts to import the historical Electron settings file from the platform config directory, including `Heimgeist/settings.json`. +- Existing Tauri settings are never overwritten by imported settings. -## Current Tauri Scaffold +## Desktop Bridge Surface -- `src-tauri/src/main.rs` registers Tauri commands for settings, dialogs, path opening, external links, focus events, and update placeholders. -- `src-tauri/capabilities/default.json` grants the main window core, dialog, and opener permissions used by the scaffold. -- `src-tauri/tauri.conf.json` points Tauri at the existing Vite renderer on `http://127.0.0.1:5174` in dev and `../dist` for build output. -- `scripts/run-tauri-dev.cjs` is the full Tauri dev wrapper. -- `src/desktop/desktopApi.js` remains the only renderer bridge layer for Electron/Tauri desktop functions. +Renderer code should continue to call only `src/desktop/desktopApi.js` for desktop functions. That bridge owns direct access to the Tauri global and maps the renderer API to Tauri commands/events. -## Intentional Non-Goals +Current Tauri-backed desktop methods: -- No Electron files, scripts, dependencies, or IPC behavior were removed. -- No backend API contracts changed. -- No Python backend sidecar, production backend packaging, or data relocation was added. -- No Tauri updater, changelog parity, or restart flow was implemented. +- `getSettings` +- `setSetting` +- `updateSettings` +- `pickPaths` +- `openPath` +- `openExternalLink` +- `onWindowFocus` +- `offWindowFocus` +- `applyUiScale` +- update/changelog placeholders -## Remaining Gaps Before Electron Removal +## Historical Removal Notes -- Update flow: startup/manual update checks, changelog, restart, and signed release strategy. -- Production backend lifecycle: package the FastAPI backend, set ffmpeg/ffprobe paths, health gate startup, and shut down cleanly. -- DevTools preference: Electron honors `openDevToolsOnStartup`; Tauri currently documents this as an Electron-only setting. -- Settings window parity: Electron still has a separate settings modal; Tauri currently uses the existing renderer route. -- App menu parity: Tauri has a basic default menu, not the full Electron template. -- Packaging: bundle metadata, final icons, signing/notarization, updater channel, and installer behavior. +This pass removed the former Electron runtime and development entry points: + +- `electron/main.cjs` +- `electron/preload.cjs` +- `scripts/run-electron-dev.cjs` +- Electron npm metadata, dependencies, and scripts from `package.json` +- Electron-specific branches from `src/desktop/desktopApi.js` + +The only remaining Electron references should be historical migration documentation or the Tauri first-run settings import note. + +## Remaining Production-Release Tasks + +- Replace update/changelog placeholders with a signed Tauri update flow or another release strategy. +- Package the FastAPI backend as a sidecar or equivalent production process. +- Preserve ffmpeg/ffprobe environment handling for packaged audio transcription. +- Add production backend startup health gating and shutdown behavior. +- Finalize bundle metadata, icons, signing, notarization, and installer behavior. +- Decide whether the settings route needs a dedicated Tauri window for production parity. +- Expand the basic Tauri menu if product-specific app menu actions are needed.