TypeScript Tauri Agent Rules
Project Context
- Use Tauri v2 for cross-platform desktop apps. The frontend is TypeScript/HTML; the backend is Rust.
- Tauri v2 uses a capability-based permission system — every OS API access must be declared in `capabilities/`.
- Target Windows, macOS, and Linux. Test on all three platforms in CI before releasing.
- Use `@tauri-apps/plugin-*` packages for common OS integrations (fs, dialog, store, shell).
Code Style & Structure
- Follow Tauri's default layout: `src/` for frontend, `src-tauri/` for Rust backend code.
- Organize Rust commands by domain in `src-tauri/src/commands/` — one module per domain.
- Keep Rust command functions thin: validate input, delegate to service modules, return results.
- Place TypeScript API wrappers and type definitions in `src/lib/tauri/` — centralize all IPC calls.
- Store app icons and tray icons in `src-tauri/icons/`.
Rust Commands & IPC
- Define commands with `#[tauri::command]` and register them in `tauri::Builder::invoke_handler`.
- Use typed parameters and return types — Tauri auto-serializes via `serde` and `serde_json`.
- Return `Result<T, String>` or a custom serializable error type from all commands.
- Use `tauri::State<T>` for dependency injection of shared state (database handles, config, channels).
- Never perform blocking I/O in Tauri commands — use `tokio::spawn` or `tokio::task::spawn_blocking`.
- Create TypeScript wrapper functions for every Rust command to centralize type safety and error handling.
Frontend Integration
- Use `invoke<ReturnType>('command_name', { ...args })` to call Rust commands from TypeScript.
- Use `listen<Payload>('event-name', handler)` for Rust-to-frontend event subscriptions.
- Clean up event listeners in component cleanup functions (useEffect return, onUnmounted).
- Use `Window.getCurrent()` API for window management (minimize, maximize, fullscreen).
- Use `feature_detection: window.__TAURI__` to support running as both web app and desktop app.
Security
- Define minimum required permissions in `src-tauri/capabilities/` — never grant `all` permissions.
- Use `allowlist` scoping in capabilities: scope file system access to `appDataDir` only.
- Set a strict Content Security Policy in `tauri.conf.json` — no `unsafe-inline` or `unsafe-eval`.
- Validate all data received from the frontend in Rust commands before processing.
- Store secrets in the system keychain via `tauri-plugin-store` — never in config files or frontend code.
- Sanitize all file paths in Rust to prevent path traversal attacks.
File System Access
- Use `tauri-plugin-fs` with scoped permissions — never grant blanket read/write access.
- Resolve standard directories via `appDataDir()`, `appConfigDir()`, `desktopDir()` from `@tauri-apps/api/path`.
- Perform atomic writes by writing to a temp file then renaming to prevent data corruption.
- Handle file system errors gracefully with user-friendly messages and recovery actions.
Window Management
- Use `WebviewWindow` from `@tauri-apps/api/webviewWindow` to create and manage additional windows.
- Set window properties (title, size, decoration, transparency) in `tauri.conf.json` rather than programmatically.
- Use `Window.setFocus()` to bring a window to the foreground after a background operation completes.
- Use `Window.onCloseRequested()` to intercept close events and prompt for unsaved changes.
Auto-Updates & Distribution
- Configure Tauri's built-in updater with a signed update manifest endpoint.
- Sign releases with a private key — distribute only the public key in `tauri.conf.json`.
- Build platform-specific bundles: `.dmg`/`.app` for macOS, `.msi`/`.exe` for Windows, `.deb`/`.AppImage` for Linux.
- Use GitHub Actions or CI/CD to cross-compile and sign releases for all platforms on tagged commits.
Error Handling
- Define a custom Rust error enum implementing `serde::Serialize` for typed error responses.
- Map all Rust `anyhow::Error` values to user-facing error types before returning from commands.
- Display native error dialogs for unrecoverable errors using `tauri-plugin-dialog`.
- Log errors to a local file using `tauri-plugin-log` with appropriate log levels.
Performance
- Keep the production frontend bundle under 2 MB — use code splitting and tree-shaking.
- Prefer Rust for CPU-intensive tasks (parsing, encryption, compression) over JavaScript.
- Batch related data into single command invocations to minimize IPC round trips.
- Profile Rust code with `cargo flamegraph` to identify hot paths in command handlers.
Testing
- Test Rust command logic as plain functions using `#[cfg(test)]` modules with `cargo test`.
- Mock `@tauri-apps/api` modules in frontend tests using Vitest module mocking.
- Use Playwright with `@tauri-apps/plugin-autostart` for end-to-end desktop integration tests.