agent: dev launcher — own Linux env-var contract, add dev:tauri, doc sweep

The 2026-05-12 engine-slop pass removed runtime std::env::set_var mutation from src-tauri/src/lib.rs and replaced it with warn_if_x11_env_unset_on_wayland. With no launcher owning the contract, Linux Wayland dogfood was about to regress.

run.sh:
- now owns Linux launcher env defaults via case "$(uname -s)"
  LIBCLANG_PATH=/usr/lib64/llvm21/lib64 (user-set wins)
  WEBKIT_DISABLE_DMABUF_RENDERER=1 (always on Linux; user-set wins)
  GDK_BACKEND=x11, WINIT_UNIX_BACKEND=x11 (Wayland only; user-set wins)
- 60s Vite readiness timeout
- detects early Vite exit (kill -0 + wait) instead of hanging forever
- trap installed before wait so Ctrl-C cleans up
- args forwarded: ./run.sh --release etc.
- non-exec final Tauri launch preserved so cleanup trap fires

package.json:
- "dev:tauri": "./run.sh" — canonical discoverable dev command

Docs:
- README, dev-setup, architecture-map runtime + launcher pages updated with the new contract; canonical command is npm run dev:tauri (./run.sh as direct equivalent)
- dev-launcher-and-scripts.md replaces the incorrect "kills process group" claim with honest "kills the spawned npm process"
- dev-setup.md path /CORBEL-Projects/magnotia → /CORBEL-Projects/transcription-app
- gpu-tuning/plan.md gets a superseded note rather than rewriting the original rationale
- engine-slop-residuals.md gains Area F (packaged-binary launcher contract) with honest wrapper-vs-.desktop trade-off documented

Verification: bash -n run.sh; shellcheck clean; cargo check -p magnotia green; npm pkg get 'scripts.dev:tauri' returns "./run.sh"; stale-ref sweep clean across living docs.
This commit is contained in:
2026-05-12 22:05:33 +01:00
parent db654deecc
commit 792fb5ea08
11 changed files with 227 additions and 73 deletions

View File

@@ -2,7 +2,7 @@
name: Slice 02 — Tauri runtime
type: architecture-map-page
slice: 02-tauri-runtime
last_verified: 2026/05/09
last_verified: 2026/05/12
---
# Slice 02 — Tauri runtime
@@ -29,7 +29,7 @@ last_verified: 2026/05/09
App boot, config, tests:
- [App lifecycle](app-lifecycle.md). `src-tauri/src/main.rs` and `src-tauri/src/lib.rs`. Run entry, AppState construction, plugin wiring, preferences injection, X11-on-Wayland workaround, panic hook, error-log pruning, command registration.
- [App lifecycle](app-lifecycle.md). `src-tauri/src/main.rs` and `src-tauri/src/lib.rs`. Run entry, AppState construction, plugin wiring, preferences injection, Linux launcher-env warning, panic hook, error-log pruning, command registration.
- [System tray](system-tray.md). Desktop-only tray icon and menu (`src-tauri/src/tray.rs`).
- [Tauri config](tauri-config.md). `tauri.conf.json` plus the Linux native-decorations overlay; CSP, window defaults, bundle settings.
- [Capabilities and ACL](capabilities-and-acl.md). The two ACL files in `capabilities/`, what each scopes, and the Phase 9 high-risk-permission firewall.
@@ -57,7 +57,7 @@ Individual command pages (linked from the commands index):
- `commands::update::install_update` returns a hard-coded "Updates are disabled until release signing is configured." (`src-tauri/src/commands/update.rs:15`). The integration test `updater_is_signed_or_absent` (`src-tauri/tests/config_hardening.rs:35`) only asserts that *if* an updater config ships, it carries a non-empty pubkey. There is currently no updater config in `tauri.conf.json`, so the test is an empty no-op.
- `commands::power::PowerAssertion` is a no-op on Linux and Windows (`src-tauri/src/commands/power.rs:90`). Only macOS has a real implementation via `objc2`. The doc comment promises `SetThreadExecutionState` (Windows) and logind inhibitors (Linux), but neither is wired up. Symptom: long live-dictation sessions on Linux can be idled by the compositor.
- `src-tauri/.cargo/config.toml` hard-codes `LIBCLANG_PATH = "C:\\Program Files\\LLVM\\bin"` (Windows). It is harmless on non-Windows hosts (env var is just unused) but it is a foot-gun if someone moves Clang elsewhere on Windows. See [Cargo and features](cargo-and-features.md).
- The Linux Wayland workaround in `lib.rs` (`ensure_x11_on_wayland`) sets env vars before any threads spawn. This is the right pattern, but it ships even when the user is on a working DMA-BUF stack. The override knob is `WEBKIT_DISABLE_DMABUF_RENDERER=0` set by the user; documented in the function header but not surfaced anywhere user-visible.
- The Linux rendering workaround in `lib.rs` (`warn_if_x11_env_unset_on_wayland`) now warns when the launcher has not set the expected env vars; it no longer mutates the process environment. In development, `run.sh` / `npm run dev:tauri` owns the defaults (`WEBKIT_DISABLE_DMABUF_RENDERER=1` on Linux; `GDK_BACKEND=x11` and `WINIT_UNIX_BACKEND=x11` on Wayland). The user opt-out remains `WEBKIT_DISABLE_DMABUF_RENDERER=0`, set before launching.
- `commands::diagnostics::install_panic_hook` writes a "minimal text dump" without backtraces unless the user has `RUST_BACKTRACE=1` set (`src-tauri/src/commands/diagnostics.rs:42`). The packaged binary does not set it, so production crash dumps will lack stack traces. Document or default-enable.
- `commands::audio::list_audio_devices` is gated `ensure_main_window` but the `secondary-windows` capability does not invoke it, which is correct. The `clipboard::copy_to_clipboard` command, by contrast, has no main-window guard and any window with the `core:default` permission can call it; intentional, but worth flagging.

View File

@@ -2,19 +2,19 @@
name: App lifecycle
type: architecture-map-page
slice: 02-tauri-runtime
last_verified: 2026/05/09
last_verified: 2026/05/12
---
# App lifecycle
> **Where you are:** [Architecture map](../README.md) → [Tauri runtime](README.md) → App lifecycle
**Plain English summary.** This is the entry point. `main.rs` calls `magnotia_lib::run()` and `lib.rs::run` does everything that has to happen before the user sees a window: sets a Linux Wayland workaround, installs the Rust panic hook, registers Tauri plugins, opens the SQLite database, prunes the error log, builds a JS preferences-injection script, configures the WebKit media-permission grant on Linux, wires close-to-tray, populates `AppState` and the per-domain managed states, emits any runtime warnings, sets up the system tray, and finally registers all 71 Tauri commands.
**Plain English summary.** This is the entry point. `main.rs` calls `magnotia_lib::run()` and `lib.rs::run` does everything that has to happen before the user sees a window: initialises tracing, checks the Linux launcher env-var contract, installs the Rust panic hook, registers Tauri plugins, opens the SQLite database, prunes the error log, builds a JS preferences-injection script, configures the WebKit media-permission grant on Linux, wires close-to-tray, populates `AppState` and the per-domain managed states, emits any runtime warnings, sets up the system tray, and finally registers all 71 Tauri commands.
## At a glance
- Path: `src-tauri/src/main.rs`, `src-tauri/src/lib.rs`.
- LOC: 5 (main) + 448 (lib).
- LOC: 5 (main) + 491 (lib).
- Tauri commands exposed directly here: `save_preferences` (string preferences -> SQLite settings table). All other commands live under `commands::*` and are registered via `tauri::generate_handler!`.
- Events emitted directly here: none (runtime warnings are emitted by `commands::models::emit_runtime_warnings`, called from setup).
- Depends on: `tauri`, `sqlx::SqlitePool`, `magnotia_core::types::EngineName`, `magnotia_llm::LlmEngine`, `magnotia_storage::{init, database_path, get_setting, set_setting, prune_error_log}`, `magnotia_transcription::LocalEngine`, plus the `commands::*` and `tray` modules.
@@ -46,16 +46,18 @@ Functions:
- `build_preferences_script(prefs_json: Option<String>) -> String` (`src-tauri/src/lib.rs:38`). Builds an IIFE that reads saved preferences (theme, zone, accessibility settings: font family, font size, letter spacing, line height, transcript size, bionic reading, reduce motion) and applies them to `<html>` before the rest of the document loads. Embeds the JSON via `serde_json::to_string` to keep it safe.
- `save_preferences(state, preferences) -> Result<(), String>` (`src-tauri/src/lib.rs:73`). The single command in `lib.rs`. Persists the preferences blob to the SQLite settings table under key `magnotia_preferences`.
- `ensure_x11_on_wayland()` (`src-tauri/src/lib.rs:99`, Linux only). Sets `WEBKIT_DISABLE_DMABUF_RENDERER=1` unconditionally on Linux (iGPU idle-cost workaround), and additionally sets `GDK_BACKEND=x11` plus `WINIT_UNIX_BACKEND=x11` when `XDG_SESSION_TYPE=wayland`. Idempotent: if a value is already set, the function leaves it alone. Must run before any threads spawn — uses `unsafe { std::env::set_var(...) }`.
- `run()` (`src-tauri/src/lib.rs:135`). The Tauri builder pipeline.
- `init_tracing()` (Linux/macOS/Windows). Initialises the process-wide tracing subscriber once, honours `RUST_LOG`, and writes structured startup/runtime logs to stderr.
- `warn_if_x11_env_unset_on_wayland()` (Linux only). Emits a `magnotia_startup` warning when the launcher has not pre-set `WEBKIT_DISABLE_DMABUF_RENDERER` (always expected on Linux), or `GDK_BACKEND=x11` / `WINIT_UNIX_BACKEND=x11` when `XDG_SESSION_TYPE=wayland`. It does not mutate the process environment; `run.sh` owns the dev-time contract and package wrappers/.desktop files must own the distribution-time contract.
- `run()`. The Tauri builder pipeline.
### `run()` step-by-step
1. **Linux env-var prelude.** Calls `ensure_x11_on_wayland()` on Linux (`src-tauri/src/lib.rs:137`).
2. **Panic hook.** Calls `commands::diagnostics::install_panic_hook()` to dump panic info to `crashes_dir()` (`src-tauri/src/lib.rs:141`).
3. **Plugin wiring (always-on).** `tauri_plugin_opener`, `tauri_plugin_dialog`, `tauri_plugin_notification` (`src-tauri/src/lib.rs:144`).
4. **Plugin wiring (desktop-only).** `tauri_plugin_global_shortcut`, `tauri_plugin_autostart` (LaunchAgent on macOS), `tauri_plugin_window_state` (`src-tauri/src/lib.rs:158`).
5. **Setup hook.** This is where the bulk of startup work lives:
1. **Tracing init.** Calls `init_tracing()` before any startup warnings/logs are emitted.
2. **Linux launcher contract check.** Calls `warn_if_x11_env_unset_on_wayland()` on Linux. Missing env vars produce warnings only; runtime env-var mutation was removed because Rust 2024 treats environment mutation in multi-threaded programs as unsafe.
3. **Panic hook.** Calls `commands::diagnostics::install_panic_hook()` to dump panic info to `crashes_dir()`.
4. **Plugin wiring (always-on).** `tauri_plugin_opener`, `tauri_plugin_dialog`, `tauri_plugin_notification` (`src-tauri/src/lib.rs:144`).
5. **Plugin wiring (desktop-only).** `tauri_plugin_global_shortcut`, `tauri_plugin_autostart` (LaunchAgent on macOS), `tauri_plugin_window_state` (`src-tauri/src/lib.rs:158`).
6. **Setup hook.** This is where the bulk of startup work lives:
- Initialise SQLite via `magnotia_storage::init(&database_path()).await` using `tauri::async_runtime::block_on` (`src-tauri/src/lib.rs:180`). The `Instant::now()` timing is logged.
- Prune `error_log` rows older than 90 days (`src-tauri/src/lib.rs:189`). Best-effort: a failure logs but does not block startup.
- Load saved preferences from the settings table; build the JS injection script (`src-tauri/src/lib.rs:204`).
@@ -66,8 +68,8 @@ Functions:
- Build the `AppState` itself: fresh `LocalEngine`s for whisper and parakeet, the open `SqlitePool`, a fresh `LlmEngine` (`src-tauri/src/lib.rs:302`).
- Emit runtime warnings (CPU baseline, Vulkan loader) via `commands::models::emit_runtime_warnings` (`src-tauri/src/lib.rs:312`).
- Setup the system tray on desktop (`src-tauri/src/lib.rs:314`).
6. **Command registration.** `tauri::generate_handler![...]` lists 71 commands (`src-tauri/src/lib.rs:321`). The order in the macro is grouped by domain (preferences, models, LLM, transcription, audio, tasks, feedback, TTS, rituals, nudges, intentions, profiles, transcripts, diagnostics, live, windows, clipboard, fs, paste, meeting, hardware, hotkey, updater).
7. **Run.** `.run(tauri::generate_context!())` blocks the main thread until the app exits. Panics are wrapped with `expect("error while running Magnotia")`.
7. **Command registration.** `tauri::generate_handler![...]` lists 71 commands (`src-tauri/src/lib.rs:321`). The order in the macro is grouped by domain (preferences, models, LLM, transcription, audio, tasks, feedback, TTS, rituals, nudges, intentions, profiles, transcripts, diagnostics, live, windows, clipboard, fs, paste, meeting, hardware, hotkey, updater).
8. **Run.** `.run(tauri::generate_context!())` blocks the main thread until the app exits. Panics are wrapped with `expect("error while running Magnotia")`.
## Data flow
@@ -79,8 +81,8 @@ Functions:
## Watch-outs
- `tauri::async_runtime::block_on` inside `setup` blocks startup. The DB init and prefs read are explicitly timed and logged so regressions show up. Adding more synchronous async work here directly pushes the time-to-first-paint up.
- The Linux media-permission wire-up is non-fatal: if `with_webview` fails the app still boots, but `getUserMedia` will be silently denied or fall back to a prompt the user cannot answer (no UI). The error path logs `[startup] failed to configure webview media permissions: ...` to stderr.
- The `unsafe std::env::set_var` calls in `ensure_x11_on_wayland` are sound only because nothing else in the binary has spawned a thread yet at that point. Do not introduce another startup-time env mutation outside this function unless the same invariant is preserved.
- The Linux media-permission wire-up is non-fatal: if `with_webview` fails the app still boots, but `getUserMedia` will be silently denied or fall back to a prompt the user cannot answer (no UI). The error path logs a `magnotia_startup` warning.
- Linux rendering env vars are a launcher contract, not a runtime mutation. In development, use `npm run dev:tauri` / `./run.sh`; packaged Linux builds need an equivalent wrapper or `.desktop` `Exec=env` policy. `WEBKIT_DISABLE_DMABUF_RENDERER=0` remains the user opt-out for the DMA-BUF workaround.
- Close-to-tray works only on desktop (the `cfg!(not(target_os = "android"))` block). On Android, closing the activity terminates the process, which is the expected platform behaviour.
- The `prewarm_default_model` call is *not* wired here. `commands::models::prewarm_default_model` exists, but `setup` does not invoke it. The frontend invokes the matching `prewarm_default_model_cmd` command after the main page mounts. If you ever want to shift pre-warm into setup, watch the spawn_blocking ordering against the engine `Arc` clones.

View File

@@ -2,65 +2,107 @@
name: Dev launcher and scripts
type: architecture-map-page
slice: 05-core-storage-hotkey-build
last_verified: 2026/05/09
last_verified: 2026/05/12
---
# Dev launcher and scripts
> **Where you are:** [Architecture map](../README.md) → [Core, Storage, Hotkey, Build](README.md) → Dev launcher and scripts
**Plain English summary.** Two ways to start Magnotia in development. `run.sh` is the bespoke launcher that starts Vite first and then Tauri (avoiding a Tauri-spawned-second-Vite mess). The `package.json` scripts are the canonical npm-run interface — the same scripts CI uses for the frontend gate.
**Plain English summary.** `run.sh` is the canonical full-stack development launcher and is exposed through `npm run dev:tauri`. It starts Vite first, waits for it to bind port 1420, then runs Tauri with Tauri's own `beforeDevCommand` disabled so a second Vite instance does not race the first one. On Linux it also owns the rendering env-var contract that `src-tauri/src/lib.rs::warn_if_x11_env_unset_on_wayland` checks.
## At a glance
- Files: `run.sh` (636 bytes, +x), `package.json` (1,211 bytes), `package-lock.json` (109 KB).
- External tools: `npm`, `npx`, `curl`, `bash` (run.sh); the Node toolchain (package.json scripts).
- Consumers: `run.sh` is invoked by Jake on his Monolith. The `package.json` scripts are invoked by both CI (`npm run build`) and developers (`npm run dev`).
- Files: `run.sh` (+x), `package.json`, `package-lock.json`.
- External tools: `npm`, `npx`, `curl`, `bash` (`run.sh`); the Node toolchain (`package.json` scripts).
- Consumers: developers use `npm run dev:tauri` (canonical) or `./run.sh` (direct shell equivalent). CI uses package scripts such as `npm run build` and `npm run check`.
## `run.sh` — the local launcher
## `run.sh` — the full-stack dev launcher
```bash
#!/usr/bin/env bash
# Magnotia dev launcher. Starts Vite first, waits for it to bind port 1420,
# then runs Tauri without triggering a second Vite instance.
# Sets the Linux rendering env vars that warn_if_x11_env_unset_on_wayland
# (src-tauri/src/lib.rs) expects the launcher to own.
# For performance testing use: npm run tauri build
set -euo pipefail
cd "$(dirname "$0")"
export LIBCLANG_PATH=/usr/lib64/llvm21/lib64
case "$(uname -s)" in
Linux)
# Bindgen libclang path. Fedora 41/LLVM 21 default; user-set wins.
export LIBCLANG_PATH="${LIBCLANG_PATH:-/usr/lib64/llvm21/lib64}"
# iGPU idle-cost workaround. Set to 0 explicitly to opt out.
export WEBKIT_DISABLE_DMABUF_RENDERER="${WEBKIT_DISABLE_DMABUF_RENDERER:-1}"
if [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then
export GDK_BACKEND="${GDK_BACKEND:-x11}"
export WINIT_UNIX_BACKEND="${WINIT_UNIX_BACKEND:-x11}"
fi
;;
esac
printf 'Starting Vite dev server...\n' >&2
npm run dev:frontend &
VITE_PID=$!
until curl -sf http://localhost:1420 > /dev/null 2>&1; do sleep 0.5; done
printf 'Vite ready. Launching Tauri...\n' >&2
cleanup() {
kill "$VITE_PID" 2>/dev/null || true
}
trap cleanup EXIT INT TERM
npx tauri dev --config '{"build":{"beforeDevCommand":""}}'
# Wait up to 60s for Vite, bailing if it exits early.
for _ in $(seq 1 120); do
if curl -sf http://localhost:1420 > /dev/null 2>&1; then
break
fi
if ! kill -0 "$VITE_PID" 2>/dev/null; then
printf 'Vite dev server exited before becoming ready.\n' >&2
wait "$VITE_PID"
exit 1
fi
sleep 0.5
done
if ! curl -sf http://localhost:1420 > /dev/null 2>&1; then
printf 'Timed out waiting for Vite on http://localhost:1420\n' >&2
exit 1
fi
printf 'Vite ready. Launching Tauri...\n' >&2
npx tauri dev --config '{"build":{"beforeDevCommand":""}}' "$@"
```
### Why this exists
The default `npm run tauri dev` invokes `tauri dev`, which honours `beforeDevCommand` from `tauri.conf.json` and spawns its own Vite. If Vite is already running (eg during interactive iteration), you get two instances racing for port 1420. The launcher solves it by starting Vite explicitly and disabling Tauri's spawn via `--config '{"build":{"beforeDevCommand":""}}'`.
The default `tauri dev` path honours `beforeDevCommand` from `tauri.conf.json` and spawns Vite itself. That is convenient for the simple path, but during interactive iteration it can create a second Vite instance racing for port 1420. The launcher solves this by starting Vite explicitly and disabling Tauri's spawn via `--config '{"build":{"beforeDevCommand":""}}'`.
The launcher is also the dev-time owner of Linux rendering defaults. Rust startup no longer calls `std::env::set_var`; it only warns when the launcher contract was missed.
### Steps
1. `set -euo pipefail` — early exit on any command failure or unset variable.
2. `cd "$(dirname "$0")"` — anchor to the repo root.
3. **Hard-codes `LIBCLANG_PATH=/usr/lib64/llvm21/lib64`** — Fedora 41 default LLVM 21 path. **Breaks on Debian / Ubuntu / macOS.** Worth softening to `LIBCLANG_PATH=${LIBCLANG_PATH:-/usr/lib64/llvm21/lib64}` so a developer-set value wins.
4. Spawn `npm run dev:frontend &`; capture PID in `VITE_PID`.
5. Poll `curl -sf http://localhost:1420` every 500 ms until 200 OK.
6. Trap `EXIT INT TERM` to kill the Vite process group on script exit.
7. `npx tauri dev` with `beforeDevCommand` disabled.
3. On Linux, default `LIBCLANG_PATH` to Fedora's LLVM path only if the user has not set it already.
4. On Linux, default `WEBKIT_DISABLE_DMABUF_RENDERER=1`; users can opt out with `WEBKIT_DISABLE_DMABUF_RENDERER=0 ./run.sh`.
5. On Wayland sessions, default `GDK_BACKEND=x11` and `WINIT_UNIX_BACKEND=x11`; user-set values win.
6. Spawn `npm run dev:frontend &`; capture its PID.
7. Install a trap that kills the spawned `npm run dev:frontend` process on launcher exit/interrupt.
8. Poll `curl -sf http://localhost:1420` every 500 ms for up to 60 seconds; if Vite exits early or never becomes ready, fail instead of hanging forever.
9. Run `npx tauri dev` with `beforeDevCommand` disabled and forward any extra args (`./run.sh --release`).
### Linux rendering env-var contract
`src-tauri/src/lib.rs::warn_if_x11_env_unset_on_wayland` is a safety net. It warns when the process starts without env vars that must be set before WebKitGTK/WINIT initialise:
- `WEBKIT_DISABLE_DMABUF_RENDERER=1` — Linux-wide iGPU idle-cost workaround. Set `WEBKIT_DISABLE_DMABUF_RENDERER=0` before launching to opt out.
- `GDK_BACKEND=x11` and `WINIT_UNIX_BACKEND=x11` — only expected when `XDG_SESSION_TYPE=wayland`.
Development uses `run.sh` for that contract. Packaged Linux builds need an equivalent wrapper or `.desktop` `Exec=env` policy; see the residual packaging plan.
### `LIBCLANG_PATH` rationale
Bindgen (pulled by `whisper-rs-sys` and `llama-cpp-sys-2`) needs a `libclang.so` at build time. On Fedora's LLVM 21 packaging, the canonical location is `/usr/lib64/llvm21/lib64`. On Debian-family the path is `/usr/lib/llvm-N/lib`; on macOS Homebrew it's `$(brew --prefix llvm)/lib`. The hard-coded value means a clean `git clone` on a non-Fedora machine fails the first build until the developer sets `LIBCLANG_PATH` themselves.
Bindgen (pulled by `whisper-rs-sys` and `llama-cpp-sys-2`) needs a `libclang.so` at build time. On Fedora's LLVM 21 packaging, the canonical location is `/usr/lib64/llvm21/lib64`. On Debian-family the path is `/usr/lib/llvm-N/lib`; on macOS Homebrew it's `$(brew --prefix llvm)/lib`. `run.sh` now uses `LIBCLANG_PATH=${LIBCLANG_PATH:-/usr/lib64/llvm21/lib64}` on Linux so Fedora works out of the box while developer-set values win.
## `package.json` — npm scripts and deps
@@ -70,6 +112,7 @@ Bindgen (pulled by `whisper-rs-sys` and `llama-cpp-sys-2`) needs a `libclang.so`
"scripts": {
"dev": "npm run dev:frontend",
"dev:frontend": "svelte-kit sync && vite dev",
"dev:tauri": "./run.sh",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
@@ -79,9 +122,10 @@ Bindgen (pulled by `whisper-rs-sys` and `llama-cpp-sys-2`) needs a `libclang.so`
```
- `npm run dev` — frontend only (no Tauri). Useful for pure-UI iteration.
- `npm run dev:tauri` — canonical full-stack dev launcher; calls `./run.sh`.
- `npm run build` — Vite production build. CI gate.
- `npm run check``svelte-check` against `jsconfig.json`. CI gate.
- `npm run tauri` — passthrough. `npm run tauri dev`, `npm run tauri build`, etc.
- `npm run tauri` — passthrough for non-dev Tauri commands such as `npm run tauri build`.
### Runtime dependencies
@@ -104,8 +148,7 @@ Bindgen (pulled by `whisper-rs-sys` and `llama-cpp-sys-2`) needs a `libclang.so`
## Watch-outs
- **`run.sh` `LIBCLANG_PATH` is Fedora-specific.** A new developer on Ubuntu / macOS hits a build failure on first run and has to either edit `run.sh` or pre-set the env var. Worth the conditional default.
- **No `dev:fullstack` script.** The Tauri dev path goes through `npx tauri dev` (or `run.sh`), not through an npm script. A `npm run dev:fullstack` shortcut would make discovery easier.
- **The trap kills the spawned npm process, not a full process group.** If Vite-orphan leaks become a real dev annoyance, switch to starting a process group (`setsid`) and killing `-- -$VITE_PID` on Linux.
- **Tailwind v4 is in flight.** Major version, no PostCSS config. Cross-link to slice 1 for the consumed surface.
- **`@tauri-apps/api` is pinned to `2.10.1` (no caret).** Intentional because Tauri's JS bridge can shift behaviour subtly between minors. Pinned ensures we test what we ship.
- **Plugin versions are caret-ranged.** Compatible-change updates land transparently. `npm audit` (CI) catches advisories.

View File

@@ -78,5 +78,5 @@ The `panic = "abort"` setting is a deliberate trade-off:
## See also
- [CI pipeline](ci-pipeline.md) — uses this profile for release builds.
- [Dev launcher and scripts](dev-launcher-and-scripts.md) — `npm run tauri dev` uses the default debug profile.
- [Dev launcher and scripts](dev-launcher-and-scripts.md) — `npm run dev:tauri` uses the default debug profile via the canonical `run.sh` launcher.
- [Storage Cargo configuration](storage-overview.md) — the per-crate sqlx feature stripping.