# AGENTS.md - Coding Agent Guide This file provides essential information for AI coding agents working in this repository. ## 📋 Project Overview **Tech Stack**: Tauri 2.x Desktop Application - **Frontend**: Vanilla TypeScript + Vite 6.0.3 - **Backend**: Rust (edition 2021) - **Package Manager**: Bun (preferred) or npm - **Build Tool**: Vite + Tauri CLI - **Runtime**: mise (for Rust toolchain management) **Project Structure**: ``` tauri-demo/ ├── src/ # Frontend TypeScript/HTML/CSS │ ├── main.ts # Application entry point │ ├── styles.css # Global styles │ └── assets/ # Static resources ├── src-tauri/ # Rust backend │ ├── src/ # Rust source code │ │ ├── main.rs # Rust entry │ │ └── lib.rs # Tauri commands │ ├── Cargo.toml # Rust dependencies │ ├── tauri.conf.json # Tauri configuration │ ├── capabilities/ # Permission configs │ └── icons/ # Multi-platform icons ├── index.html # HTML entry ├── package.json # Node.js config ├── tsconfig.json # TypeScript config └── vite.config.ts # Vite config ``` ## 🔧 Build/Lint/Test Commands ### Development ```bash # Start frontend dev server (port 1420) bun run dev # Start Tauri in dev mode (recommended for full app testing) bun run tauri dev # Preview production build bun run preview ``` ### Building ```bash # Build frontend only (TypeScript compile + Vite bundle) bun run build # Build complete Tauri application (all platforms) bun run tauri build # Build for specific platform bun run tauri build --target x86_64-pc-windows-msvc # Windows bun run tauri build --target x86_64-apple-darwin # macOS bun run tauri build --target x86_64-unknown-linux-gnu # Linux ``` ### Type Checking ```bash # TypeScript type check (run before build) tsc --noEmit # Watch mode for continuous type checking tsc --noEmit --watch ``` ### Rust Commands ```bash # Check Rust code (fast compile check) cd src-tauri && cargo check # Format Rust code cd src-tauri && cargo fmt # Lint Rust code cd src-tauri && cargo clippy # Run Rust tests cd src-tauri && cargo test # Run a specific Rust test cd src-tauri && cargo test test_name # Run tests with output cd src-tauri && cargo test -- --nocapture ``` ### Testing **Note**: No test framework is currently configured. To add testing: **Frontend Testing** (recommended: Vitest): ```bash bun add -D vitest @vitest/ui # Run all tests: bun run vitest # Run single test: bun run vitest path/to/test.test.ts ``` **Rust Testing**: Use built-in `cargo test` (see above) ## 📐 Code Style Guidelines ### TypeScript/JavaScript #### Imports - Use ES6 imports: `import { foo } from "bar"` - Tauri API imports: `import { invoke } from "@tauri-apps/api/core"` - Group imports: external packages first, then local modules - No unused imports (enforced by `noUnusedLocals`) Example: ```typescript import { invoke } from "@tauri-apps/api/core"; import { open } from "@tauri-apps/plugin-opener"; import { helperFunction } from "./utils"; ``` #### Types - **Always use explicit types** for function parameters and return values - Use type inference for simple variable assignments - Prefer `interface` for object shapes, `type` for unions/intersections - Enable all strict mode checks (already configured in tsconfig.json) Example: ```typescript // Good ✅ async function greet(name: string): Promise { return await invoke("greet", { name }); } // Bad ❌ async function greet(name) { return await invoke("greet", { name }); } ``` #### Naming Conventions - **Variables/Functions**: camelCase (`greetUser`, `userName`) - **Constants**: UPPER_SNAKE_CASE (`MAX_RETRIES`, `API_URL`) - **Types/Interfaces**: PascalCase (`UserData`, `AppConfig`) - **Private members**: prefix with underscore (`_internalState`) #### Error Handling - Always handle promises with `async/await` or `.catch()` - Use try-catch for critical operations - Provide meaningful error messages Example: ```typescript async function callRustCommand(): Promise { try { const result = await invoke("greet", { name: "World" }); console.log(result); } catch (error) { console.error("Failed to call Rust command:", error); } } ``` ### Rust #### Formatting - Use `cargo fmt` (rustfmt) for automatic formatting - 4 spaces for indentation (standard Rust) - Line length: 100 characters (rustfmt default) #### Naming Conventions - **Functions/Variables**: snake_case (`greet_user`, `user_name`) - **Types/Structs/Enums**: PascalCase (`UserData`, `AppState`) - **Constants**: SCREAMING_SNAKE_CASE (`MAX_CONNECTIONS`) - **Lifetimes**: lowercase single letter (`'a`, `'static`) #### Tauri Commands - Mark with `#[tauri::command]` attribute - Use `&str` for string parameters (efficient) - Return owned types (`String`, not `&str`) - Register in `invoke_handler!` macro Example: ```rust #[tauri::command] fn process_data(input: &str, count: i32) -> Result { if count < 0 { return Err("Count must be non-negative".to_string()); } Ok(format!("Processed {} with count {}", input, count)) } // Register in lib.rs: .invoke_handler(tauri::generate_handler![process_data]) ``` #### Error Handling - Use `Result` for fallible operations - Prefer `?` operator for error propagation - Use `expect()` only when panic is acceptable - Return descriptive error messages Example: ```rust #[tauri::command] fn read_config() -> Result { let data = std::fs::read_to_string("config.json") .map_err(|e| format!("Failed to read config: {}", e))?; serde_json::from_str(&data) .map_err(|e| format!("Invalid JSON: {}", e)) } ``` ## 🔌 Tauri-Specific Patterns ### Frontend → Rust Communication ```typescript import { invoke } from "@tauri-apps/api/core"; // Simple command const result = await invoke("command_name", { param: value }); // With error handling try { const data = await invoke("command", args); } catch (error) { console.error("Command failed:", error); } ``` ### Adding New Commands 1. Define in `src-tauri/src/lib.rs`: ```rust #[tauri::command] fn new_command(param: &str) -> String { // implementation } ``` 2. Register in `invoke_handler`: ```rust .invoke_handler(tauri::generate_handler![greet, new_command]) ``` 3. Call from frontend: ```typescript await invoke("new_command", { param: "value" }); ``` ## 📦 Dependencies ### Adding Dependencies **Frontend**: ```bash bun add package-name # Production dependency bun add -D package-name # Dev dependency ``` **Rust**: ```bash cd src-tauri cargo add package-name # Production dependency cargo add --dev package-name # Dev dependency ``` ## ⚠️ Common Pitfalls 1. **Port conflicts**: Dev server uses port 1420, HMR uses 1421 2. **Type mismatches**: Ensure Rust return types match TypeScript expectations 3. **Missing command registration**: New Tauri commands must be added to `generate_handler!` 4. **Permission issues**: Update `src-tauri/capabilities/default.json` for new capabilities 5. **Build errors**: Run `tsc` before `vite build` (automated in build script) ## 🚀 Workflow Tips - Always run `tsc --noEmit` before committing to catch type errors - Test Tauri commands with `bun run tauri dev`, not just `bun run dev` - Use `cargo clippy` to catch common Rust mistakes - Check both frontend and Rust console for errors during development - Clear Vite cache if seeing stale builds: `rm -rf node_modules/.vite`