tauri-agents-review · v1.0 · 2026-03-19 · sha256 9ecb056e91f55c3b

tauri-agents-review v1.0A

Immutable. This exact content is served forever at /api/v1/blob/9ecb056e91f55c3b.

---
name: tauri-agents-review
description: "Provides a comprehensive validation checklist for reviewing Tauri 2 code including command signature correctness, permission coverage verification, state management patterns, error handling completeness, IPC bridge completeness (Rust+TypeScript pairing), security audit, and anti-pattern detection across all Tauri domains. Activates when reviewing Tauri code, auditing permissions, or validating a Tauri project before deployment."
license: MIT
compatibility: "Designed for Claude Code. Requires Tauri 2.x."
metadata:
  author: Impertio
  version: "1.0"
---

# tauri-agents-review

## Review Workflow

Execute these checklists in order. Each section is independent -- report all findings, do not stop at the first issue.

```
Review Order:
1. Commands & IPC Bridge    --> Rust signatures + JS invoke pairing
2. Permissions & Capabilities --> ACL coverage
3. State Management         --> Thread safety + correctness
4. Error Handling           --> Result types + frontend catching
5. Security                 --> CSP + scopes + dangerous settings
6. Build Configuration      --> Config completeness
7. Anti-Pattern Scan        --> Known mistakes
```

---

## Checklist 1: Commands & IPC Bridge

### 1A: Rust Command Signatures

For every `#[tauri::command]` function, verify:

```
[ ] Function is NOT pub if defined directly in lib.rs
[ ] Function IS pub if defined in a separate module
[ ] Async commands use owned types (String, not &str) for parameters
    Exception: &str allowed if return type is Result<T, E>
[ ] Return type is Result<T, E> for any fallible operation
[ ] E implements serde::Serialize
[ ] All custom types in parameters implement serde::Deserialize
[ ] All custom types in return values implement serde::Serialize
[ ] Event payload types implement both Serialize AND Clone
```

### 1B: Command Registration

```
[ ] All commands listed in a SINGLE generate_handler![] call
    FAIL if multiple .invoke_handler() calls found on Builder
[ ] Every #[tauri::command] function is registered
    Cross-reference: grep for #[tauri::command] and compare with generate_handler![]
[ ] Module paths are correct (e.g., commands::greet, not just greet)
```

### 1C: IPC Bridge Completeness

For every Rust command, verify a matching frontend invoke exists:

```
[ ] invoke('command_name', ...) call exists in TypeScript/JavaScript
[ ] Argument keys use camelCase (NOT snake_case)
[ ] Argument types match Rust parameter types:
    - Rust String <-> JS string
    - Rust i32/u32/u64/f64 <-> JS number
    - Rust bool <-> JS boolean
    - Rust Vec<T> <-> JS array
    - Rust Option<T> <-> JS null/undefined
[ ] Return type generic matches: invoke<ExpectedType>('...')
[ ] Error case handled with try/catch
```

### 1D: Channel Usage (if applicable)

```
[ ] Channel<T> parameter in Rust has matching new Channel<T>() in JS
[ ] Channel.onmessage is set before invoke() call
[ ] Channel type parameter matches Rust send() type
```

---

## Checklist 2: Permissions & Capabilities

### 2A: Plugin Permissions

For every plugin in Cargo.toml dependencies:

```
[ ] Plugin initialized in Builder: .plugin(tauri_plugin_X::init())
[ ] Corresponding npm package installed: @tauri-apps/plugin-X
[ ] Permission entry exists in capabilities file(s)
[ ] Default permission or specific allow-* permissions granted
```

### 2B: Custom Command Permissions

For every `#[tauri::command]`:

```
[ ] Permission defined in src-tauri/permissions/*.toml
    Format: commands.allow = ["command_name"]
[ ] Permission referenced in capabilities file
[ ] No custom command is callable without explicit permission
```

### 2C: Capability File Validation

For every file in `src-tauri/capabilities/`:

```
[ ] Has valid $schema reference
[ ] Has unique identifier
[ ] windows[] array targets specific labels (NOT ["*"] without justification)
[ ] permissions[] array contains all needed permissions
[ ] Platform-specific capabilities use correct platforms[] values
[ ] No duplicate permission entries across capability files
```

### 2D: Scope Verification

```
[ ] fs plugin scopes restrict to needed directories only
[ ] http plugin scopes restrict to needed URLs only
[ ] shell plugin scopes whitelist specific commands only
[ ] Asset protocol scope is minimal ($APPDATA/**, $RESOURCE/**)
[ ] Deny rules used to exclude sensitive paths/URLs
```

---

## Checklist 3: State Management

### 3A: Registration

```
[ ] All State<'_, T> types used in commands have matching manage() calls
[ ] manage() called BEFORE any command that uses the state can execute
    (i.e., in Builder chain or early in setup())
[ ] No duplicate manage() calls for the same type (returns false)
[ ] State types are Send + Sync + 'static
```

### 3B: Thread Safety

```
[ ] Mutable state wrapped in Mutex, RwLock, or atomic types
[ ] std::sync::Mutex used by default (NOT tokio::sync::Mutex)
[ ] tokio::sync::Mutex used ONLY when lock held across .await
[ ] No Arc wrapping (Tauri manages Arc internally)
[ ] No nested locking of the same Mutex (deadlock risk)
```

### 3C: Lock Discipline

```
[ ] Mutex guards are dropped before calling other functions that may lock
[ ] Lock scopes are minimal (lock, operate, drop)
[ ] RwLock used for read-heavy state (multiple concurrent readers)
[ ] No lock held during I/O or network operations (unless tokio Mutex)
```

---

## Checklist 4: Error Handling

### 4A: Rust Side

```
[ ] All commands returning data use Result<T, E>
[ ] Error type uses thiserror (not manual Display impl)
[ ] Error type implements Serialize (manual impl, not derive)
[ ] No unwrap() or expect() in command handlers
[ ] I/O errors converted via #[from] or manual From impl
[ ] Error messages are user-friendly (no raw debug output)
```

### 4B: Frontend Side

```
[ ] Every invoke() call wrapped in try/catch
[ ] Error catch blocks handle the error (log, display, recover)
[ ] Structured errors parsed correctly (if using tagged enum pattern)
[ ] No unhandled Promise rejections from invoke()
```

---

## Checklist 5: Security Audit

### 5A: Content Security Policy

```
[ ] CSP is NOT null in production
[ ] default-src set to 'self'
[ ] script-src does NOT include 'unsafe-eval'
[ ] connect-src includes ipc: and http://ipc.localhost
[ ] img-src includes asset: and https://asset.localhost if needed
[ ] No wildcard (*) domains without justification
```

### 5B: Dangerous Settings

```
[ ] freezePrototype set to true (prevents prototype pollution)
[ ] dangerousDisableAssetCspModification is false or absent
[ ] withGlobalTauri is false in production
[ ] No shell:default without scope restrictions
[ ] No fs permissions without scope restrictions
[ ] No http permissions without URL scope
```

### 5C: Capability Scope

```
[ ] No capability uses windows: ["*"] with broad permissions
[ ] Platform-specific capabilities correctly scoped
[ ] Remote capabilities (if any) have minimal permissions
[ ] Core permissions are explicit (core:default, core:window:default)
```

---

## Checklist 6: Build Configuration

### 6A: tauri.conf.json

```
[ ] identifier is unique reverse-domain format
[ ] build.frontendDist points to correct output directory
[ ] build.beforeBuildCommand builds frontend assets
[ ] build.beforeDevCommand starts dev server
[ ] build.devUrl matches dev server port
[ ] app.windows[] has at least one window configured
[ ] bundle.icon includes all required formats (.ico, .icns, .png)
```

### 6B: Cargo.toml

```
[ ] tauri dependency version is 2.x
[ ] tauri-build in build-dependencies
[ ] build.rs exists and calls tauri_build::build()
[ ] crate-type includes ["staticlib", "cdylib", "rlib"] if targeting mobile
[ ] All plugin crates versioned at "2"
```

### 6C: Package.json

```
[ ] @tauri-apps/cli in devDependencies
[ ] @tauri-apps/api in dependencies
[ ] All plugin npm packages installed (@tauri-apps/plugin-*)
[ ] Versions aligned (all ^2)
```

### 6D: Source Control

```
[ ] Cargo.lock committed (NOT in .gitignore)
[ ] src-tauri/target/ in .gitignore
[ ] No secrets in committed files (.env, API keys, signing keys)
```

---

## Checklist 7: Anti-Pattern Scan

Scan the codebase for these known issues:

```
[ ] No multiple .invoke_handler() calls
[ ] No pub commands in lib.rs
[ ] No Arc wrapping of managed state
[ ] No &str in async command parameters (without Result return)
[ ] No .unwrap() in command handlers
[ ] No snake_case keys in frontend invoke() calls
[ ] No event listeners without cleanup
[ ] No event names with dots, spaces, or special characters
[ ] No CSP set to null
[ ] No missing Serialize on error types
[ ] No missing Clone on event payloads
[ ] No sync I/O operations in command handlers (use async)
[ ] No missing permissions for installed plugins
[ ] No relative paths without BaseDirectory in fs calls
```

---

## Review Report Template

After completing all checklists, produce a report:

```
## Tauri 2 Code Review Report

### Summary
- Total issues found: X
- Critical (blocks deployment): X
- Warning (should fix): X
- Info (improvement suggestion): X

### Critical Issues
1. [CRIT-001] Description -- Location -- Fix

### Warnings
1. [WARN-001] Description -- Location -- Fix

### Passed Checks
- Commands & IPC Bridge: PASS/FAIL (X/Y checks passed)
- Permissions: PASS/FAIL
- State Management: PASS/FAIL
- Error Handling: PASS/FAIL
- Security: PASS/FAIL
- Build Config: PASS/FAIL
- Anti-Patterns: PASS/FAIL
```

---

## Decision Trees

### Is a command correctly wired?

```
Does #[tauri::command] exist on the function?
+-- No --> Add the macro
+-- Yes
    |
    Is it in generate_handler![]?
    +-- No --> Add it
    +-- Yes
        |
        Does a permission exist in src-tauri/permissions/?
        +-- No --> Create permission TOML
        +-- Yes
            |
            Is it referenced in a capability file?
            +-- No --> Add to capabilities
            +-- Yes
                |
                Does a matching invoke() call exist in JS?
                +-- No --> Add frontend invoke
                +-- Yes --> PASS
```

### Is state correctly managed?

```
Is State<'_, T> used in a command?
+-- No --> Skip
+-- Yes
    |
    Does manage(T) exist on Builder or in setup()?
    +-- No --> CRITICAL: Add manage() call
    +-- Yes
        |
        Does the generic type match exactly?
        +-- No --> CRITICAL: Fix type mismatch
        +-- Yes
            |
            Is T mutable?
            +-- No --> PASS
            +-- Yes
                |
                Is T wrapped in Mutex/RwLock?
                +-- No --> CRITICAL: Add interior mutability
                +-- Yes --> PASS (verify no deadlocks)
```

---

## Reference Links

- [references/methods.md](references/methods.md) -- Review commands, grep patterns, validation rules
- [references/examples.md](references/examples.md) -- Example review findings and reports
- [references/anti-patterns.md](references/anti-patterns.md) -- Complete anti-pattern catalog with detection patterns

### Official Sources

- https://v2.tauri.app/security/
- https://v2.tauri.app/develop/calling-rust/
- https://v2.tauri.app/security/capabilities/