/desktop-backend-tauri
Tauri 2.x Rust command patterns, state management, error handling, events, channels, testing
$ npx -y skills add agents-inc/skills --skill desktop-backend-tauri --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/desktop-backend-tauri
Context preview
The summary Claude sees to decide when to auto-load this skill.
Tauri 2.x Rust command patterns, state management, error handling, events, channels, testing
SKILL.md
desktop-backend-tauri.SKILL.mdname: desktop-backend-tauri
description: Tauri 2.x Rust command patterns, state management, error handling, events, channels, testing
Tauri Rust Backend Patterns
> **Quick Guide:** Define commands with `#[tauri::command]`, register in `generate_handler![]`. Use `State<T>` for shared state (wrap mutable fields in `Mutex`). Error types must implement both `serde::Serialize` and `Display` -- use `thiserror` for ergonomic error enums. Async commands run on Tokio -- borrowed args (`&str`, `State<'_, T>`) require `Result<T, E>` return type. Stream data to frontend via `Channel<T>` (not events) for high throughput. Emit events with `app.emit()` for fire-and-forget notifications. > > **Current version:** Tauri 2.x (stable). Async runtime is Tokio.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST register every command in `tauri::generate_handler![]` -- unregistered commands compile fine but silently fail at runtime)**
**(You MUST implement `serde::Serialize` on all error types returned from commands -- Tauri serializes errors across the IPC boundary)**
**(You MUST wrap mutable managed state in `Mutex` or `RwLock` -- commands run concurrently and `State<T>` requires `Send + Sync`)**
**(You MUST return `Result<T, E>` from async commands that use borrowed args (`&str`, `State<'_, T>`) -- Rust lifetime rules require it)**
**(You MUST use `Channel<T>` for streaming data to frontend -- events are designed for small payloads, not high-throughput streaming)**
</critical_requirements>
---
**Auto-detection:** #[tauri::command], tauri::command, tauri::State, AppHandle, app.manage, generate_handler, tauri::ipc::Channel, Emitter, Listener, thiserror, tauri::test, mock_builder, async tauri command, tauri error handling, tauri state management
**When to use:**
- Defining Rust command handlers (sync and async) for frontend invocation
- Managing application state across commands with `app.manage()` and `State<T>`
- Implementing error types that serialize across the IPC boundary
- Emitting events from Rust to frontend (progress, notifications, background updates)
- Streaming data from Rust to frontend via channels
- Testing Rust commands with Tauri's mock runtime
- Organizing commands into modules as the backend grows
**When NOT to use:**
- Frontend invoke patterns and TypeScript types (see the framework-level Tauri skill)
- Permission/capability configuration (see the framework-level Tauri skill)
- Plugin installation and configuration (see the framework-level Tauri skill)
- Window management, system tray, menus (see the framework-level Tauri skill)
- Packaging and distribution (see the framework-level Tauri skill)
- General Rust programming not specific to Tauri APIs
**Key patterns covered:**
- Sync and async commands with `#[tauri::command]` ([examples/core.md](examples/core.md))
- Error handling with `thiserror` + manual `Serialize` impl ([examples/core.md](examples/core.md))
- Managed state with `Mutex`/`RwLock` and `State<T>` injection ([examples/core.md](examples/core.md))
- `AppHandle` for accessing app resources from commands ([examples/core.md](examples/core.md))
- Channels for streaming data to frontend ([examples/core.md](examples/core.md))
- Emitting events from Rust ([examples/events.md](examples/events.md))
- Listening for frontend events in Rust ([examples/events.md](examples/events.md))
- Testing commands with mock runtime ([examples/testing.md](examples/testing.md))
- Command organization in modules ([examples/core.md](examples/core.md))
**Detailed resources:**
- [examples/core.md](examples/core.md) - Commands, error handling, state, AppHandle, channels, modules
- [examples/events.md](examples/events.md) - Emitting and listening for events from Rust
- [examples/testing.md](examples/testing.md) - Mock runtime, testing commands with state
- [reference.md](reference.md) - Decision frameworks, quick-lookup tables, lifetime rules
---
<philosophy>
Philosophy
The Tauri Rust backend is the **trust boundary** between the untrusted webview frontend and the operating system. Every sensitive operation -- file I/O, network requests, shell commands, state mutations -- flows through Rust commands. The backend is responsible for validation, authorization, and safe execution.
**Design principles:**
- **Commands are the API surface.** Each command is a well-defined endpoint with typed arguments, typed return values, and explicit error handling. Treat them like HTTP handlers.
- **State is managed, not global.** Use `app.manage(T)` to register singletons. Commands request state via `State<T>` injection -- no global statics, no lazy_static.
- **Errors are data, not panics.** Never `unwrap()` in commands. Return `Result<T, E>` where `E` implements `Serialize`. The frontend receives structured error information.
- **Async by default for I/O.** Sync commands block the main thread. Use async for anything involving files, network, or long computation. Tokio is the runtime.
- **Channels for streaming, events for notifications.** `Channel<T>` is optimized for ordered, high-throughput data delivery. Events are pub-sub fire-and-forget for small payloads.
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Sync and Async Commands
Sync commands execute on the main thread. Async commands run on Tokio's thread pool.
// Sync -- blocks main thread, use only for fast operations
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
// Async -- runs on Tokio, use for I/O and long operations
#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
tokio::fs::read_to_string(&path)
.await
.map_err(|e| e.to_string())
}**Key rule:** Async commands cannot use `&str` arguments unless the return type is `Result<T, E>`. Use `String` for o
Read more
name: desktop-backend-tauri description: Tauri 2.x Rust command patterns, state management, error handling, events, channels, testing
Tauri Rust Backend Patterns
> **Quick Guide:** Define commands with `#[tauri::command]`, register in `generate_handler![]`. Use `State<T>` for shared state (wrap mutable fields in `Mutex`). Error types must implement both `serde::Serialize` and `Display` -- use `thiserror` for ergonomic error enums. Async commands run on Tokio -- borrowed args (`&str`, `State<'_, T>`) require `Result<T, E>` return type. Stream data to frontend via `Channel<T>` (not events) for high throughput. Emit events with `app.emit()` for fire-and-forget notifications. > > **Current version:** Tauri 2.x (stable). Async runtime is Tokio.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST register every command in `tauri::generate_handler![]` -- unregistered commands compile fine but silently fail at runtime)**
**(You MUST implement `serde::Serialize` on all error types returned from commands -- Tauri serializes errors across the IPC boundary)**
**(You MUST wrap mutable managed state in `Mutex` or `RwLock` -- commands run concurrently and `State<T>` requires `Send + Sync`)**
**(You MUST return `Result<T, E>` from async commands that use borrowed args (`&str`, `State<'_, T>`) -- Rust lifetime rules require it)**
**(You MUST use `Channel<T>` for streaming data to frontend -- events are designed for small payloads, not high-throughput streaming)**
</critical_requirements>
---
**Auto-detection:** #[tauri::command], tauri::command, tauri::State, AppHandle, app.manage, generate_handler, tauri::ipc::Channel, Emitter, Listener, thiserror, tauri::test, mock_builder, async tauri command, tauri error handling, tauri state management
**When to use:**
- Defining Rust command handlers (sync and async) for frontend invocation
- Managing application state across commands with `app.manage()` and `State<T>`
- Implementing error types that serialize across the IPC boundary
- Emitting events from Rust to frontend (progress, notifications, background updates)
- Streaming data from Rust to frontend via channels
- Testing Rust commands with Tauri's mock runtime
- Organizing commands into modules as the backend grows
**When NOT to use:**
- Frontend invoke patterns and TypeScript types (see the framework-level Tauri skill)
- Permission/capability configuration (see the framework-level Tauri skill)
- Plugin installation and configuration (see the framework-level Tauri skill)
- Window management, system tray, menus (see the framework-level Tauri skill)
- Packaging and distribution (see the framework-level Tauri skill)
- General Rust programming not specific to Tauri APIs
**Key patterns covered:**
- Sync and async commands with `#[tauri::command]` ([examples/core.md](examples/core.md))
- Error handling with `thiserror` + manual `Serialize` impl ([examples/core.md](examples/core.md))
- Managed state with `Mutex`/`RwLock` and `State<T>` injection ([examples/core.md](examples/core.md))
- `AppHandle` for accessing app resources from commands ([examples/core.md](examples/core.md))
- Channels for streaming data to frontend ([examples/core.md](examples/core.md))
- Emitting events from Rust ([examples/events.md](examples/events.md))
- Listening for frontend events in Rust ([examples/events.md](examples/events.md))
- Testing commands with mock runtime ([examples/testing.md](examples/testing.md))
- Command organization in modules ([examples/core.md](examples/core.md))
**Detailed resources:**
- [examples/core.md](examples/core.md) - Commands, error handling, state, AppHandle, channels, modules
- [examples/events.md](examples/events.md) - Emitting and listening for events from Rust
- [examples/testing.md](examples/testing.md) - Mock runtime, testing commands with state
- [reference.md](reference.md) - Decision frameworks, quick-lookup tables, lifetime rules
---
<philosophy>
Philosophy
The Tauri Rust backend is the **trust boundary** between the untrusted webview frontend and the operating system. Every sensitive operation -- file I/O, network requests, shell commands, state mutations -- flows through Rust commands. The backend is responsible for validation, authorization, and safe execution.
**Design principles:**
- **Commands are the API surface.** Each command is a well-defined endpoint with typed arguments, typed return values, and explicit error handling. Treat them like HTTP handlers.
- **State is managed, not global.** Use `app.manage(T)` to register singletons. Commands request state via `State<T>` injection -- no global statics, no lazy_static.
- **Errors are data, not panics.** Never `unwrap()` in commands. Return `Result<T, E>` where `E` implements `Serialize`. The frontend receives structured error information.
- **Async by default for I/O.** Sync commands block the main thread. Use async for anything involving files, network, or long computation. Tokio is the runtime.
- **Channels for streaming, events for notifications.** `Channel<T>` is optimized for ordered, high-throughput data delivery. Events are pub-sub fire-and-forget for small payloads.
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Sync and Async Commands
Sync commands execute on the main thread. Async commands run on Tokio's thread pool.
// Sync -- blocks main thread, use only for fast operations
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
// Async -- runs on Tokio, use for I/O and long operations
#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
tokio::fs::read_to_string(&path)
.await
.map_err(|e| e.to_string())
}**Key rule:** Async commands cannot use `&str` arguments unless the return type is `Result<T, E>`. Use `String` for o
Showing the first part of this file.
The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Repo: agents-inc/skills
Other skills on agents-inc-skills.
- /ai-infrastructure-huggingface-inference
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints
Open skill - /ai-infrastructure-litellm
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment
Open skill - /ai-infrastructure-modal
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns
Open skill - /ai-infrastructure-ollama
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint
Open skill - /ai-infrastructure-replicate
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training
Open skill - /ai-infrastructure-together-ai
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints
Open skill

