Development
#mobile
tauri-v2
Tauri v2+ cross-platform app development with Rust backend. Use when configuring tauri.conf.json, implementing Rust commands (#[tauri::command]), setting up IPC patterns (invoke, emit, channels), configuring permissions/capabilities, troubleshooting build issues, or deploying desktop/mobile apps. Triggers on Tauri, src-tauri, invoke, emit, capabilities.json.
DeepseekModel
Curated skill
Quality Excellent · 90
v1.0.0
Get
https://deepseekmodel.com/api/download.php?id=midudev-autoskills-packages-autoskills-skills-registry-tauri-v2-skill-md&format=skill
Download .skill
Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name tauri-v2 description Tauri v2+ cross-platform app development with Rust backend. Use when configuring tauri.conf.json, implementing Rust commands (#[tauri::command]), setting up IPC patterns (invoke, emit, channels), configuring permissions/capabilities, troubleshooting build issues, or deploying desktop/mobile apps. Triggers on Tauri, src-tauri, invoke, emit, capabilities.json. version 1.0.1 Tauri v2+ Development Skill Build cross-platform desktop and mobile apps with web frontends and Rust backends. Before You Start This skill prevents 8+ common errors and saves ~60% tokens. Metric Without Skill With Skill Setup Time ~2 hours ~30 min Common Errors 8+ 0 Token Usage High (exploration) Low (direct patterns) Known Issues This Skill Prevents Permission denied errors from missing capabilities IPC failures from unregistered commands in generate_handler! State management panics from type mismatches Mobile build failures from missing Rust targets White screen issues from misconfigured dev URLs Quick Start Step 1: Create a Tauri Command // src-tauri/src/lib.rs #[tauri::command] fn greet (name: String ) -> String { format! ( "Hello, {}!" , name) } #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run () { tauri::Builder:: default () . invoke_handler (tauri::generate_handler![greet]) . run (tauri::generate_context!()) . expect ( "error while running tauri application" ); } Why this matters: Commands not in generate_handler![] silently fail when invoked from frontend. main.rs stays thin: src-tauri/src/main.rs should only be a thin passthrough — all application logic lives in lib.rs : // src-tauri/src/main.rs #![cfg_attr(not(debug_assertions), windows_subsystem = "windows" )] fn main () { app_lib:: run (); } This split is required for mobile builds — Tauri replaces main() with mobile_entry_point on mobile targets. Step 2: Call from Frontend import { invoke } from '@tauri-apps/api/core' ; const greeting = await invoke< string >( 'greet' , { name : 'World' }); console . log (greeting); // "Hello, World!" Why this matters: Use @tauri-apps/api/core (not @tauri-apps/api/tauri - that's v1 API). Step 3: Add Required Permissions // src-tauri/capabilities/default.json { "$schema" : "../gen/schemas/desktop-schema.json" , "identifier" : "default" , "windows" : [ "main" ] , "permissions" : [ "core:default" ] } Why this matters: Tauri v2 denies everything by default - explicit permissions required for all operations. Critical Rules Always Do Register every command in tauri::generate_handler![cmd1, cmd2, ...] Return Result<T, E> from commands for proper error handling Use Mutex<T> for shared state accessed from multiple commands Add capabilities before using any plugin features Use lib.rs for shared code (required for mobile builds) Use #[cfg_attr(mobile, tauri::mobile_entry_point)] on pub fn run() in lib.rs for mobile compatibility Never Do Never use borrowed types ( &str ) in async commands - use owned types Never block the main thread - use async for I/O operations Never hardcode paths - use Tauri path APIs ( app.path() ) Never skip capability setup - even "safe" operations need permissions Common Mistakes Wrong - Borrowed type in async: #[tauri::command] async fn bad (name: & str ) -> String { // Compile error! name. to_string () } Correct - Owned type: #[tauri::command] async fn good (name: String ) -> String { name } Why: Async commands cannot borrow data across await points; Tauri requires owned types for async command parameters. Known Issues Prevention Issue Root Cause Solution "Command not found" Missing from generate_handler! Add command to handler macro "Permission denied" Missing capability Add to capabilities/default.json Plugin feature silently fails Plugin installed but permission not in capability Add plugin permission string to capabilities/default.json Updater fails in production Unsigned artifacts or HTTP endpoint Generate keys with cargo tauri signer generate , use HTTPS endpoint only Sidecar not found externalBin not in tauri.conf.json or missing executable Add path to bundle.externalBin , ensure binary is bundled Feature works on desktop, breaks on mobile Desktop-only API used Check if API has mobile support — some plugins are desktop-only State panic on access Type mismatch in State<T> Use exact type from .manage() White screen on launch Frontend not building Check beforeDevCommand in config IPC timeout Blocking async command Remove blocking code or use spawn Mobile build fails Missing Rust targets Run rustup target add <target> Deep-Dive References Security & permissions → references/capabilities-reference.md IPC decision guide → references/ipc-patterns.md Official plugins → references/plugin-reference.md Updater & distribution → references/updater-distribution-reference.md Tray, sidecars, deep links → references/advanced-runtime-reference.md Configuration Reference tauri.conf.json { "$schema" : "./gen/schemas/desktop-schema.json" , "productName" : "my-app" , "version" : "1.0.0" , "identifier" : "com.example.myapp" , "build" : { "devUrl" : "http://localhost:5173" , "frontendDist" : "../dist" , "beforeDevCommand" : "npm run dev" , "beforeBuildCommand" : "npm run build" } , "app" : { "windows" : [ { "label" : "main" , "title" : "My App" , "width" : 800 , "height" : 600 } ] , "security" : { "csp" : "default-src 'self'; img-src 'self' data:" , "capabilities" : [ "default" ] } } , "bundle" : { "active" : true , "targets" : "all" , "icon" : [ "icons/icon.icns" , "icons/icon.ico" , "icons/icon.png" ] } } Key settings: build.devUrl : Must match your frontend dev server port app.security.capabilities : Array of capability file identifiers Plugin configuration — Some plugins require additional tauri.conf.json blocks (e.g., store , updater ). Always check the specific plugin docs at v2.tauri.app/plugin/<plugin-name>/ for required config keys. Project Structure my-tauri-app/ ├── src/ # Frontend source ├── src-tauri/ │ ├── src/ │ │ ├── main.rs # Thin passthrough — calls lib::run() │ │ └── lib.rs # ALL application logic lives here │ ├── capabilities/ │ │ └── default.json # Capability definitions (grant permissions here) │ ├── tauri.conf.json # App configuration (devUrl, bundle, security) │ ├── Cargo.toml # Rust dependencies │ └── build.rs # Build script (required for tauri-build) └── package.json Why lib.rs owns all logic: Tauri replaces main() with #[cfg_attr(mobile, tauri::mobile_entry_point)] on mobile. All commands, state, and builder setup must live in lib.rs::run() . Cargo.toml [package] name = "app" version = "0.1.0" edition = "2021" [lib] name = "app_lib" crate-type = [ "staticlib" , "cdylib" , "rlib" ] [build-dependencies] tauri-build = { version = "2" , features = [] } [dependencies] tauri = { version = "2" , features = [] } serde = { version = "1" , features = [ "derive" ] } serde_json = "1" Key settings: [lib] section: Required for mobile builds crate-type : Must include all three types for cross-platform Common Patterns Error Handling Pattern Use Result<T, E> and thiserror for type-safe error propagation across the IPC boundary. See references/ipc-patterns.md for full implementation details. use thiserror::Error; #[derive(Debug, Error)] enum AppError { #[error( "IO error: {0}" )] Io ( #[from] std::io::Error), #[error( "Not found: {0}" )] NotFound ( String ), } impl serde ::Serialize for AppError { fn serialize <S>(& self , serializer: S) -> Result <S:: Ok , S::Error> where S: serde::ser::Serializer { serializer. serialize_str ( self . to_string (). as_ref ()) } } #[tauri::command] fn risky_operation () -> Result < String , AppError> { Ok ( "success" . into ()) } Serde Boundary Rules All command arguments must implement serde::Deserialize , and return types must implement serde::Serialize . This is how Tauri bridges JSON over the IPC boundary. use serde::{Deserialize, Serialize}; #[derive(Deserialize)] struct CreateUserArgs { name: String , email: String , role: Option < String >, // Optional fields use Option<T> } #[derive(Serialize)] struct User { id: u64 , name: String , } #[tauri::command] fn create_user (args: CreateUserArgs) -> Result <User, String > { Ok (User { id: 1 , name: args.name }) } Common serde pitfalls: Field names are camelCase in JS, snake_case in Rust — Tauri automatically converts between them Option<T> maps to optional JS arguments (can be undefined or null ) Complex enums need #[serde(tag = "type")] or similar to be JSON-safe Error types must also implement Serialize (see Error Handling Pattern above) State Management Pattern Tauri state manages application data across commands. See references/ipc-patterns.md for more complex state patterns. use std::sync::Mutex; use tauri::State; struct AppState { counter: u32 , } #[tauri::command] fn increment (state: State< '_ , Mutex<AppState>>) -> u32 { let mut s = state. lock (). unwrap (); s.counter += 1 ; s.counter } // In builder: tauri::Builder:: default () . manage (Mutex:: new (AppState { counter: 0 })) Event Emission Pattern Events are fire-and-forget notifications. See references/ipc-patterns.md for bidirectional examples. use tauri::Emitter; #[tauri::command] fn start_task (app: tauri::AppHandle) { std::thread:: spawn ( move || { app. emit ( "task-progress" , 50 ). unwrap (); app. emit ( "task-complete" , "done" ). unwrap (); }); } import { listen } from '@tauri-apps/api/event' ; const unlisten = await listen ( 'task-progress' , ( e ) => { console . log ( 'Progress:' , e. payload ); }); // Call unlisten() when done Channel Streaming Pattern Channels provide high-frequency, typed streaming from Rust to Frontend. See references/ipc-patterns.md for full implementation details. use tauri::ipc::Channel; #[derive(Clone, serde::Serialize)]
Keywords that activate this skill. Click one to copy it.
This skill does not provide trigger words.
The downloaded .skill package contains the following fields.
| Field | Description |
|---|---|
| format | Format tag (skill/v1) |
| skill_id | Unique skill ID |
| name | Skill name |
| version | Version |
| description | Description |
| category | Categories (array) |
| trigger_words | Trigger words |
| tags | Tags |
| source | Source |
| source_url | Source URL (this page) |
| exported_at | Exported at (set per download) |
| system_prompt | System prompt body |
| model_config | Model config: provider / model / temperature / max_tokens / top_p |
| examples | Examples |
| install_guide | Import guide for Coze / Dify / Claude / custom frameworks |
The same skill can be exported in different platform formats.