tauri2-guide/tauri2-guide/agent-prompts.md
Z User 04c128f509 Add definitive Tauri 2.0 guide, agent prompts, and WebSocket docs
- tauri2-guide/definitive-guide.md: Comprehensive Tauri 2.0 reference covering project structure, configuration, capabilities/permissions, commands/IPC, events/channels, window management, plugin ecosystem, WebSocket server, script injection, state management, v1->v2 migration, anti-patterns, and quick reference cheat sheet.

- tauri2-guide/agent-prompts.md: Copy-paste ready prompts for instructing AI agents to build Tauri 2.0 apps. Includes universal system prompt with sandbox constraints, 10 task-specific prompts, verification checklist, and v1->v2 API map.

- tauri2-docs/ws_server_client_inject_guide.md: Complete WebSocket server/client/script injection guide based on the moxie-app reference implementation. Covers the native Tokio WebSocket server pattern, frontend client connections, and script injection into external webview windows.

All code validated against Tauri 2.0 official docs (https://v2.tauri.app).
2026-05-30 19:24:21 +00:00

22 KiB

Tauri 2.0 Agent Prompts — Definitive Collection

Purpose: Copy-paste ready prompts for instructing AI agents to build Tauri 2.0 applications. Constraint: These prompts are designed for sandbox environments where code compilation is NOT available. Agents must verify correctness using logic, API references, and pattern matching.


Table of Contents

  1. Universal System Prompt (Required Prefix)
  2. Prompt: Scaffold a New Tauri 2.0 Project
  3. Prompt: Add a Tauri Plugin
  4. Prompt: Create a Custom Command (IPC)
  5. Prompt: Add State Management
  6. Prompt: Implement Event-Based Communication
  7. Prompt: Create Multi-Window App
  8. Prompt: Build a WebSocket Server in Rust
  9. Prompt: Implement Script Injection
  10. Prompt: Set Up Capabilities & Permissions
  11. Prompt: Migrate a v1 App to v2
  12. Prompt: Full App Build (End-to-End)
  13. Verification Checklist for Agents
  14. Quick Reference: v1 vs v2 API Map

1. Universal System Prompt (Required Prefix)

Always include this as the system context before any task-specific prompt.

You are a Tauri 2.0 expert developer. You build desktop and mobile applications using the Tauri 2.0 framework (Rust backend + web frontend).

CRITICAL ENVIRONMENT CONSTRAINTS:
- You CANNOT compile or run code in this sandbox. Do NOT attempt compilation.
- Verify correctness using logic, API pattern matching, and reference knowledge only.
- Cross-reference every code snippet against known Tauri 2.0 API patterns before outputting.
- If you are uncertain about an API or pattern, say so explicitly rather than guessing.

MANDATORY TAURI 2.0 RULES — NEVER VIOLATE:
1. This is Tauri 2.0 (NOT v1). The APIs are fundamentally different.
2. Use `tauri::WebviewWindow` (NOT `tauri::Window`).
3. Use `tauri::WebviewWindowBuilder` (NOT `tauri::WindowBuilder`).
4. Use `tauri::WebviewUrl` (NOT `tauri::WindowUrl`).
5. Use `Manager::get_webview_window()` (NOT `Manager::get_window()`).
6. Use `tauri::Emitter` trait for `emit()` and `emit_to()` (NOT the old window-only emit).
7. Use `tauri::Listener` trait for `listen()` and `once()` on the Rust side.
8. JS import `invoke` from `@tauri-apps/api/core` (NOT `@tauri-apps/api/tauri`).
9. JS import window utilities from `@tauri-apps/api/webviewWindow` (NOT `@tauri-apps/api/window`).
10. JS plugins import from `@tauri-apps/plugin-<name>` (NOT `@tauri-apps/api/<name>`).
11. Config uses `app` section (NOT `tauri` section), `build.frontendDist` (NOT `build.distDir`).
12. Security uses Capabilities + Permissions (NOT `allowlist`).
13. Every plugin requires: (a) Rust crate in Cargo.toml, (b) `.plugin()` registration in Builder, (c) npm package, (d) permissions in capabilities.
14. Use the `lib.rs` + `main.rs` pattern. Core logic goes in `lib.rs`. `main.rs` only calls `lib::run()`.
15. `#[cfg_attr(mobile, tauri::mobile_entry_point)]` attribute is REQUIRED on the `pub fn run()` function.
16. `invoke_handler` can only be called ONCE — all commands go in a single `tauri::generate_handler![]`.
17. Async commands cannot use borrowed references (`&str`, `&Path`) directly — use owned types or wrap return in `Result`.
18. Window creation from async contexts MUST use `app_handle.run_on_main_thread()`.
19. Always clean up event listeners (call `unlisten()`) on the frontend.
20. Use `tauri = { version = "2" }` and `tauri-build = { version = "2" }` (NOT version 1).

FILE STRUCTURE:
- Frontend source: `src/`
- Rust backend: `src-tauri/`
- Rust entry-point: `src-tauri/src/main.rs` (minimal)
- Core app logic: `src-tauri/src/lib.rs`
- Extra modules: `src-tauri/src/<module>.rs`
- Capabilities: `src-tauri/capabilities/default.json`
- Config: `src-tauri/tauri.conf.json`
- Rust deps: `src-tauri/Cargo.toml`
- Build script: `src-tauri/build.rs`

OFFICIAL DOCUMENTATION:
- Main docs: https://v2.tauri.app
- Rust API: https://docs.rs/tauri/latest/tauri/
- Migration guide: https://v2.tauri.app/start/migrate/from-tauri-1/
- Capabilities: https://v2.tauri.app/security/capabilities/
- Permissions: https://v2.tauri.app/security/permissions/
- Configuration: https://v2.tauri.app/develop/configuration-files/
- Calling Rust: https://v2.tauri.app/develop/calling-rust/
- Calling Frontend: https://v2.tauri.app/develop/calling-frontend/
- Plugin index: https://v2.tauri.app/plugin/

2. Prompt: Scaffold a New Tauri 2.0 Project

Create a new Tauri 2.0 project from scratch with vanilla JavaScript (no frontend framework).

Requirements:
- App name: [APP_NAME]
- Window title: [WINDOW_TITLE]
- Default window size: [WIDTH]x[HEIGHT]
- withGlobalTauri enabled (for window.__TAURI__ access without npm package)

Generate ALL of the following files with complete, correct Tauri 2.0 code:

1. `package.json` — with @tauri-apps/cli v2 devDependency and scripts (dev, build, tauri)
2. `src/index.html` — basic HTML5 boilerplate
3. `src/main.js` — demonstrate invoking a Rust command
4. `src/styles.css` — basic styling
5. `src-tauri/tauri.conf.json` — correct v2 structure (app section, build section, bundle section)
6. `src-tauri/Cargo.toml` — with tauri v2, tauri-build v2, serde, serde_json. Include [lib] with crate-type ["staticlib", "cdylib", "rlib"]
7. `src-tauri/build.rs` — standard tauri_build::build()
8. `src-tauri/capabilities/default.json` — with core:default permission
9. `src-tauri/src/main.rs` — minimal entry-point calling lib::run()
10. `src-tauri/src/lib.rs` — with Builder pattern, mobile_entry_point attribute, a sample "greet" command, and the command registered in invoke_handler

Verify every line follows Tauri 2.0 conventions. Cross-check config structure against the v2 schema.

3. Prompt: Add a Tauri Plugin

Add the [PLUGIN_NAME] plugin to an existing Tauri 2.0 project.

Plugin to add: [tauri-plugin-STORE/turi-plugin-FS/etc.]
JS package name: [@tauri-apps/plugin-store/etc.]

Instructions:
1. Add the Rust crate to `src-tauri/Cargo.toml` as `tauri-plugin-[name] = "2"`
2. Register the plugin in `src-tauri/src/lib.rs` using `.plugin(tauri_plugin_[name]::init())` or the Builder pattern if the plugin requires configuration
3. Add the npm package: `@tauri-apps/plugin-[name]`
4. Update `src-tauri/capabilities/default.json` to add the appropriate permission (usually `[name]:default` or specific allow permissions)
5. Provide a frontend usage example showing the correct v2 import from `@tauri-apps/plugin-[name]`

Show the exact changes needed for each file. Do NOT use v1 import paths or API patterns.

4. Prompt: Create a Custom Command (IPC)

Create a Tauri 2.0 command called "[COMMAND_NAME]" that [DESCRIBE WHAT IT DOES].

Requirements:
- Define the command using `#[tauri::command]` in a separate module file `src-tauri/src/commands.rs`
- The command must be `pub` (required for separate modules)
- Include proper error handling with `Result<T, String>` or a custom error type
- Register the command in `src-tauri/src/lib.rs` using `mod commands;` and including it in `generate_handler![commands::COMMAND_NAME]`
- Provide the frontend JavaScript code to invoke the command using `invoke()` from `@tauri-apps/api/core` or `window.__TAURI__.core`
- If the command is async, ensure all arguments are owned types (not borrowed references)

Show complete, correct code for both the Rust side and the JS side.

5. Prompt: Add State Management

Add shared state management to an existing Tauri 2.0 application.

Requirements:
1. Define a state struct in `src-tauri/src/lib.rs` using `std::sync::Mutex` for thread safety
2. Manage the state in the Builder using `.manage(MyState { ... })`
3. Create at least two commands that read and write the managed state using `tauri::State<'_, MyState>`
4. Show the frontend code for invoking these commands

If persistent storage is also needed:
- Add `tauri-plugin-store = "2"` to Cargo.toml
- Register the plugin
- Add `store:default` to capabilities
- Show frontend usage with `@tauri-apps/plugin-store`

6. Prompt: Implement Event-Based Communication

Implement bidirectional event communication in a Tauri 2.0 application.

Requirements:

Rust side:
- Use `use tauri::{Emitter, AppHandle}` to emit events from Rust
- Demonstrate both global emit (`app.emit()`) and targeted emit (`app.emit_to()`)
- If listening for events on the Rust side, use `use tauri::Listener` and `app.listen()` or `app.once()`

Frontend side:
- Import from `@tauri-apps/api/event` (NOT `@tauri-apps/api/tauri`)
- Show `listen()`, `once()`, `emit()`, and `emitTo()` usage
- Demonstrate proper cleanup with `unlisten()`
- Show targeted listening using `getCurrentWebviewWindow().listen()`

Show complete code for:
1. A Rust command that emits a progress event
2. A Rust command that emits a completion event to a specific window
3. Frontend listeners that handle these events
4. Frontend emitting an event back to Rust

Make sure `core:event:default` (or specific `core:event:allow-*` permissions) is included in capabilities.

7. Prompt: Create Multi-Window App

Create a Tauri 2.0 application with multiple windows.

Requirements:
1. Main window defined in `tauri.conf.json` with label "main"
2. A command `open_secondary` that creates a new window dynamically using `WebviewWindowBuilder`
3. The secondary window should load a local HTML file (`WebviewUrl::App("secondary.html".into())`)
4. If creating the window from an async context, use `app_handle.run_on_main_thread()`
5. Check for existing windows with the same label using `app_handle.get_webview_window(label)` and focus it if it exists
6. Show frontend code for creating windows using `new WebviewWindow(label, options)` from `@tauri-apps/api/webviewWindow`

CRITICAL: Use `tauri::WebviewWindowBuilder` and `tauri::WebviewUrl` (NOT the v1 `WindowBuilder`/`WindowUrl`).
CRITICAL: Use `app_handle.get_webview_window()` (NOT `app_handle.get_window()`).

8. Prompt: Build a WebSocket Server in Rust

Build a native WebSocket server that runs inside a Tauri 2.0 application using the Tokio async runtime.

Requirements:

Dependencies (Cargo.toml):
- `tokio = { version = "1", features = ["net", "rt", "sync", "macros"] }`
- `tokio-tungstenite = "0.24"`
- `futures-util = "0.3"`

Server implementation (`src-tauri/src/server.rs`):
- Bind a TcpListener to `127.0.0.1:[PORT]`
- Use `tokio::sync::broadcast` channel for message fan-out to all connected clients
- Accept WebSocket connections using `tokio_tungstenite::accept_async`
- Use `tokio::select!` to handle both incoming messages from clients AND broadcast messages from other clients
- Handle disconnections gracefully
- Spawn the server in `src-tauri/src/lib.rs` using `tauri::async_runtime::spawn(server::start_websocket_server())` inside the `.setup()` closure

Frontend client:
- Connect using standard `new WebSocket('ws://127.0.0.1:[PORT]')`
- Show send and receive handlers

Key pattern: Each client connection gets its own broadcast receiver via `tx.subscribe()`, enabling fan-out to all connected clients.

9. Prompt: Implement Script Injection

Implement JavaScript injection into a Tauri 2.0 WebviewWindow.

Requirements:
1. Create a JavaScript file (e.g., `src-tauri/inject.js`) that will be injected into webview windows
2. The injected script should:
   - Connect to a local WebSocket server (ws://127.0.0.1:[PORT])
   - Send data from the webview page (e.g., localStorage contents) back to the server
   - Receive data from the server and process it
   - Expose the socket connection on `window.localAppSocket` for the page's own code to use
3. Use `include_str!("../inject.js")` to load the script at compile time
4. Inject it using `WebviewWindowBuilder::initialization_script(script_content)`
5. Show a complete working example of creating a window with an external URL and injecting the script

IMPORTANT: Set `"csp": null` in the app security config if injecting scripts into external URLs, otherwise CSP may block the injection.

Show both the Rust window creation code with injection and the JavaScript injection script.

10. Prompt: Set Up Capabilities & Permissions

Set up the Tauri 2.0 Capabilities and Permissions system for an application.

The application needs access to:
- [LIST REQUIRED FEATURES: file system, dialogs, HTTP requests, clipboard, notifications, etc.]

Requirements:
1. Create `src-tauri/capabilities/default.json` with proper v2 structure
2. Include the `$schema` pointing to `../gen/schemas/desktop-schema.json`
3. Set the `identifier`, `description`, `windows` (list of window labels), and `platforms` fields
4. Add the correct permission identifiers for each required feature:
   - File system: `fs:default` or specific `fs:allow-*`
   - Dialogs: `dialog:default` or specific `dialog:allow-*`
   - HTTP: `http:default` or specific `http:allow-*`
   - Events: `core:event:default`
   - Window management: `core:window:default`
5. If fine-grained scopes are needed (e.g., restricting file access to specific directories), show scoped permissions with `allow` and `deny` arrays using path variables like `$APPDATA`, `$HOME`, `$RESOURCE`

CRITICAL: Do NOT use the v1 `allowlist` in `tauri.conf.json`. In v2, all permissions are defined via capability files.

11. Prompt: Migrate a v1 App to v2

Migrate the following Tauri v1 code to Tauri 2.0.

[PASTE v1 CODE HERE]

Migration checklist — verify ALL of these changes:

Config (tauri.conf.json):
- [ ] `tauri` section renamed to `app`
- [ ] `build.distDir` renamed to `build.frontendDist`
- [ ] `build.devPath` renamed to `build.devUrl`
- [ ] `build.withGlobalTauri` moved to `app.withGlobalTauri`
- [ ] `tauri.allowlist` REMOVED → replaced by capabilities
- [ ] `tauri.bundle` promoted to top-level `bundle`
- [ ] `bundle.identifier` promoted to top-level `identifier`
- [ ] `tauri.updater` moved to `plugins.updater`

Project structure:
- [ ] `main.rs` logic moved to `lib.rs` with `pub fn run()`
- [ ] New minimal `main.rs` calling `lib::run()`
- [ ] `Cargo.toml` has `[lib]` section with `crate-type = ["staticlib", "cdylib", "rlib"]`
- [ ] `#[cfg_attr(mobile, tauri::mobile_entry_point)]` added to `run()`

Rust code:
- [ ] All `tauri::api::*` imports REMOVED (replaced by plugins)
- [ ] `tauri::Window` → `tauri::WebviewWindow`
- [ ] `tauri::WindowBuilder` → `tauri::WebviewWindowBuilder`
- [ ] `tauri::WindowUrl` → `tauri::WebviewUrl`
- [ ] `get_window()` → `get_webview_window()`
- [ ] `tauri::Emitter` trait imported for `emit()` / `emit_to()`
- [ ] `tauri::Listener` trait imported for `listen()` / `once()`
- [ ] All plugins registered with `.plugin()` in Builder
- [ ] `tauri` and `tauri-build` version set to "2"

JavaScript code:
- [ ] `@tauri-apps/api/tauri` → `@tauri-apps/api/core`
- [ ] `@tauri-apps/api/window` → `@tauri-apps/api/webviewWindow`
- [ ] All plugin imports → `@tauri-apps/plugin-<name>`
- [ ] `@tauri-apps/cli` version set to "^2"

Capabilities:
- [ ] Created `src-tauri/capabilities/default.json`
- [ ] All necessary permissions listed
- [ ] `core:default` included at minimum

Output the complete migrated code for every file that changed.

12. Prompt: Full App Build (End-to-End)

Build a complete Tauri 2.0 application with the following requirements:

App Name: [APP_NAME]
Purpose: [DESCRIBE APP PURPOSE]

Features needed:
- [FEATURE 1: e.g., File system read/write]
- [FEATURE 2: e.g., HTTP API client]
- [FEATURE 3: e.g., Persistent settings storage]
- [FEATURE 4: e.g., System tray icon]
- [FEATURE 5: e.g., Multi-window support]
- [FEATURE 6: e.g., Custom Rust commands]

Frontend: [Vanilla JS / React / Vue / Svelte / etc.]

Generate ALL files for a complete, working Tauri 2.0 application:
1. `package.json`
2. `src/index.html` (or appropriate entry point for the chosen framework)
3. Frontend source files (JavaScript/TypeScript/CSS)
4. `src-tauri/tauri.conf.json` — v2 structure with all necessary config
5. `src-tauri/Cargo.toml` — all dependencies including required plugins
6. `src-tauri/build.rs`
7. `src-tauri/capabilities/default.json` — all required permissions
8. `src-tauri/src/main.rs` — minimal entry-point
9. `src-tauri/src/lib.rs` — Builder with all plugins, commands, setup
10. Additional Rust module files as needed
11. Any injected scripts if required

For every file:
- Use ONLY valid Tauri 2.0 code
- Use the correct v2 import paths
- Use v2 type names (WebviewWindow, WebviewUrl, etc.)
- Include proper error handling
- Add appropriate comments explaining the v2 patterns used

Do NOT skip any file. Generate complete, production-ready code.

13. Verification Checklist for Agents

Agents should run through this checklist mentally for EVERY code snippet they generate.

Config Verification

  • tauri.conf.json uses app section (not tauri)
  • build.frontendDist (not build.distDir)
  • build.devUrl (not build.devPath)
  • withGlobalTauri is under app (not build)
  • identifier is at top level (not under bundle)
  • bundle is at top level (not under tauri)
  • No allowlist present anywhere

Rust Code Verification

  • tauri version is "2" (not "1")
  • tauri-build version is "2" (not "1")
  • Cargo.toml has [lib] with crate-type = ["staticlib", "cdylib", "rlib"]
  • main.rs only contains #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] and fn main() { lib_name::run() }
  • lib.rs has #[cfg_attr(mobile, tauri::mobile_entry_point)] on pub fn run()
  • No tauri::api::* imports anywhere
  • WebviewWindow used (not Window)
  • WebviewWindowBuilder used (not WindowBuilder)
  • WebviewUrl used (not WindowUrl)
  • get_webview_window() used (not get_window())
  • Emitter trait imported when using emit() or emit_to()
  • Listener trait imported when using listen() or once()
  • invoke_handler called only ONCE with ALL commands
  • Async commands use owned types or Result wrapping (not bare &str)
  • Window creation in async contexts uses run_on_main_thread()
  • All plugins registered with .plugin() before .run()

Frontend Code Verification

  • invoke imported from @tauri-apps/api/core (not @tauri-apps/api/tauri)
  • WebviewWindow imported from @tauri-apps/api/webviewWindow (not @tauri-apps/api/window)
  • Event functions from @tauri-apps/api/event (not core or tauri)
  • Plugin imports from @tauri-apps/plugin-<name> (not @tauri-apps/api/<name>)
  • @tauri-apps/cli is version ^2
  • Event listeners cleaned up with unlisten()
  • Argument names in invoke() calls match Rust command parameter names (camelCase by default)

Capabilities Verification

  • Capability files exist in src-tauri/capabilities/
  • $schema points to correct schema path
  • All used plugins have corresponding permissions
  • Window labels in capabilities match actual window labels
  • No allowlist in config files

Plugin Verification

  • Rust crate: tauri-plugin-<name> = "2" in Cargo.toml
  • Registration: .plugin(tauri_plugin_<name>::init()) in Builder
  • JS package: @tauri-apps/plugin-<name> in dependencies
  • Permissions: Listed in capabilities file

14. Quick Reference: v1 vs v2 API Map

Keep this table handy when migrating or reviewing code.

Rust Type Renames

v1 v2
tauri::Window tauri::WebviewWindow
tauri::WindowBuilder tauri::WebviewWindowBuilder
tauri::WindowUrl tauri::WebviewUrl
Manager::get_window() Manager::get_webview_window()
tauri::WindowEvent tauri::WebviewWindowEvent
tauri::Manager::fs_scope() tauri_plugin_fs::FsExt

Rust API Removals (replaced by plugins)

v1 v2 Plugin
tauri::api::dialog tauri-plugin-dialog
tauri::api::fs std::fs / tauri-plugin-fs
tauri::api::http tauri-plugin-http
tauri::api::path tauri::Manager::path()
tauri::api::process::Command tauri-plugin-shell
tauri::api::clipboard tauri-plugin-clipboard-manager
tauri::api::notification tauri-plugin-notification
tauri::api::global_shortcut tauri-plugin-global-shortcut
tauri::api::updater tauri-plugin-updater
tauri::api::cli tauri-plugin-cli
tauri::api::os tauri-plugin-os
tauri::api::version semver crate

JavaScript Import Path Changes

v1 v2
@tauri-apps/api/tauri @tauri-apps/api/core
@tauri-apps/api/window @tauri-apps/api/webviewWindow
@tauri-apps/api/dialog @tauri-apps/plugin-dialog
@tauri-apps/api/fs @tauri-apps/plugin-fs
@tauri-apps/api/http @tauri-apps/plugin-http
@tauri-apps/api/notification @tauri-apps/plugin-notification
@tauri-apps/api/clipboard @tauri-apps/plugin-clipboard-manager
@tauri-apps/api/shell @tauri-apps/plugin-shell
@tauri-apps/api/global-shortcut @tauri-apps/plugin-global-shortcut
@tauri-apps/api/updater @tauri-apps/plugin-updater
@tauri-apps/api/os @tauri-apps/plugin-os
@tauri-apps/api/process @tauri-apps/plugin-process
@tauri-apps/api/cli @tauri-apps/plugin-cli

Config Path Changes

v1 v2
build.distDir build.frontendDist
build.devPath build.devUrl
build.withGlobalTauri app.withGlobalTauri
tauri.* app.*
tauri.allowlist.* Capabilities system
tauri.windows.fileDropEnabled app.windows.dragDropEnabled
tauri.bundle bundle (top-level)
bundle.identifier identifier (top-level)
tauri.updater plugins.updater
tauri.systemTray app.trayIcon
tauri.cli plugins.cli