Skip to content
Back to skills

Tauri V2

ASecurity

Use when building, migrating (v1→v2), or debugging a Tauri 2.x desktop app — adding a `#[tauri::command]`, fixing "command not allowed"/capabilities/ACL errors, wiring plugins, bundling per-OS, configuring the auto-updater, or attaching a heavy native/Python sidecar. Produces a verified Rust+webview app whose IPC round-trip and bundle target are exercised. Grounded in official Tauri v2 docs (v2.tauri.app); extends with opinionated patterns from 8syncdev's open-musik/zus/sidex and omp-native t...

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 17, 2026
developmentpythonrustgoshellreactvuedebuggingapifrontend

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 17, 2026

npx -y skills add 8-Sync-Dev/8sync --skill tauri-v2 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Tauri V2?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Tauri V2
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/8-sync-dev-tauri-v2/badge)](https://www.skillsdirectory.com/skills/8-sync-dev-tauri-v2)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: tauri-v2
description: Use when building, migrating (v1→v2), or debugging a Tauri 2.x desktop app — adding a `#[tauri::command]`, fixing "command not allowed"/capabilities/ACL errors, wiring plugins, bundling per-OS, configuring the auto-updater, or attaching a heavy native/Python sidecar. Produces a verified Rust+webview app whose IPC round-trip and bundle target are exercised. Grounded in official Tauri v2 docs (v2.tauri.app); extends with opinionated patterns from 8syncdev's open-musik/zus/sidex and omp-native tooling (codegraph, codebase-memory, serena, engine_*, browser).
locked: true
---

# tauri-v2 — build & verify Tauri 2 desktop apps

Canonical base: [`references/base.md`](references/base.md) (Tauri **2.11.5** /
`tauri-build` **2.6.3**, v1→v2 deltas, capabilities/ACL, IPC, plugins, bundling,
updater, sidecar, webview debugging). Opinionated extension:
[`references/patterns.md`](references/patterns.md) (11 patterns mined, cited
`repo:path`, from `8syncdev/open-musik`, `8syncdev/zus`, `8syncdev/sidex`).

## When to use

- "add a Tauri command", "call Rust from the frontend", "events aren't reaching
  the webview", "`invoke` returns command not found / not allowed".
- Migrating a v1 app, or a capabilities/ACL permission error after a plugin add.
- Wiring a plugin, bundling for an OS, setting up the auto-updater + signing.
- Attaching a heavy native/Python/Go engine as a sidecar or external binary.
- "the webview is blank/black on Linux", CSP violations, asset-protocol paths.

## When NOT to use

- Mobile (iOS/Android) targets unless the project already targets them — base §1
  notes the lib/main split, but mobile toolchains are out of scope here.
- Maintaining a v1-only app with no migration intent.
- Choosing or rewriting the frontend framework — Tauri is framework-agnostic.
- Electron/CEF or pure-browser PWA work (no Tauri involved).

## Procedure

Every step names a real tool. Prefer omp primitives over reinvention — when omp
upgrades a primitive, a step that only references it inherits the upgrade.

### 0. Ground the change before editing
- If `.codegraph/` exists: `codegraph query "<command_or_fn>"` and
  `codegraph context "tauri ipc"` to map commands/events/state. Else
  `codegraph init -i .` once. After edits: `codegraph sync`.
- If cbm/serena are enabled (opt-in: `8sync harness cbm|serena on`), cross-check structure with `mcp__codebase_memory_mcp__search_graph` /
  `trace_path` (calls) if the project is indexed, and
  `mcp__serena__get_symbols_overview` on the `src-tauri/src/*.rs` file you'll
  touch; `mcp__serena__get_diagnostics_for_file` to see type errors live.
- Read the exact slices you need with `read` (`src-tauri/tauri.conf.json`,
  `src-tauri/Cargo.toml`, `capabilities/*.json`) — never whole-file a >200-line
  Rust file blind; `codegraph`/serena locate first, `read` the narrow range.

### 1. Scaffolding / migration checks
- New app: `cargo tauri init` (or the create-tauri-app template). Confirm
  `"$schema": "https://schema.tauri.app/config/2"`.
- v1→v2: run `pnpm tauri migrate` (or `cargo tauri migrate`), then hand-verify
  the breaking list in base §1 — allowlist→capabilities, `tauri`→`app` key,
  `distDir`→`frontendDist`, plugins extraction, `createUpdaterArtifacts`,
  Windows origin scheme, `Window`→`WebviewWindow`. Use `grep` on the old config
  for `allowlist`/`tauri.updater`/`distDir` to find every site to fix.

### 2. Capabilities / ACL (the #1 error source)
- "command/plugin not allowed" → the runtime error names the missing permission
  verbatim. Open the capability file bound to the emitting window
  (`capabilities/default.json`), append that identifier to `permissions`. Prefer
  granular `plugin:allow-<cmd>` over `plugin:default`. See patterns P5/P11.
- The authoritative identifier list is the build-generated
  `src-tauri/gen/schemas/desktop-schema.json` — `read` it when unsure of the
  exact string. Add a capability file per window when windows diverge.

### 3. IPC — commands, state, events
- Define `#[tauri::command]` with **flat** args returning `Result<T, String>`
  (patterns P2). Inject `AppHandle`/`State<'_, T>` by type.
- Register every command in
  `.invoke_handler(tauri::generate_handler![mod::cmd, …])` — a missing entry is
  "command not found".
- Manage state in `.setup(|app| { app.manage(your_state); Ok(()) })`; in async
  commands, clone owned data out of `State` **before** the `.await` (P4).
- Push progress with `app.emit("name", &payload)`; frontend
  `listen("name", …)`. Pick events over `ipc::Channel` when state must survive a
  webview reload (P4/P8).
- Frontend: wrap `invoke`/`listen`/`convertFileSrc` from
  `@tauri-apps/api/core` + `/event` behind an `inTauri` guard (P8).

### 4. Plugins
- Add `tauri-plugin-<name> = "2"` (Cargo) + `@tauri-apps/plugin-<name>` (JS),
  register `.plugin(tauri_plugin_name::init())`, grant permission (step 2).
- Official plugins: `tauri-apps/plugins-workspace`. Shell plugin also owns the
  sidecar mechanism (step 6, model a).

### 5. Sidecar / external binary
- Light, one-shot external program → Tauri shell-plugin sidecar: declare in
  `plugins.shell` + `bundle`, spawn scoped via `app.shell().sidecar(...)`.
- Heavy long-lived engine (Python/Go/ML) → hand-rolled `tokio::process::Command`
  speaking a JSON-lines protocol with id-correlation + generation stamps + an
  `EventSink` trait, exactly as `8syncdev/open-musik:src-tauri/src/sidecar.rs`
  (pattern P1). `.kill_on_drop(true)`; clean up in `RunEvent::Exit` (P3).

### 6. Bundling + signing + auto-updater
- `bundle.targets`: subset (`["deb","appimage"]`) or `"all"`. Per-OS in
  `bundle.{macOS,windows,linux}`. Linux needs `webkit2gtk-4.1` deps (P6).
- Updater: `plugins.updater = {pubkey, endpoints[]}` **and**
  `bundle.createUpdaterArtifacts: true`. `tauri signer generate` →
  `TAURI_SIGNING_PRIVATE_KEY`; pubkey in config. Full production reference:
  `8syncdev/zus:src-tauri/tauri.conf.json` (P10); per-profile overlays via
  `tauri build --config tauri.<profile>.conf.json` (`8syncdev/sidex`, P10).
- macOS: `signingIdentity`, `entitlements` plist, notarization env. Windows:
  `webviewInstallMode`, optional authenticode.

### 7. Run + UI VERIFY (never claim a UI works unseen)
- `cargo tauri dev` (or `pnpm tauri dev`) to launch. Run it as a managed process
  via `hub` `op:"start"` (name `"tauri-dev"`, `ready.log` matching the dev URL,
  `ready.port` = your `devUrl` port) so the webview stays alive across calls.
- Drive the webview with the `browser` tool (`xd://browser`): `open` the
  `devUrl`, `run` `tab.observe()`/`tab.screenshot()` to confirm rendering, then
  exercise the actual IPC round-trip a user depends on (click the button → assert
  the `invoke` result / `listen` event landed). For visual regression use
  `8sync shot <url> -o /tmp/x.png` and `8sync diff-img` against a baseline.
- Blank/black Linux window → apply the WebKitGTK env hardening from P9 before the
  webview is built; `WEBKIT_DISABLE_DMABUF_RENDERER=1` is the usual fix.
- DevTools auto-on in debug; `tauri = { features = ["devtools"] }` for release.

### 8. Build loop with engine_* (verify = real build/test)
- Record the work: `engine_plan` — one slice per capability, each task's
  `verify` = the project's real gate, e.g. `cargo tauri build` (bundle target),
  `cargo test` (the `src-tauri` Rust tests), and/or `pnpm -C app build` (frontend).
- `engine_next` → do the task → `engine_verify` runs its verify commands (ALL
  must pass) → `engine_advance` marks it done (and commits if asked).
- `engine_status` shows per-slice progress / blockers across the batch. Delegate
  independent slices (e.g. "frontend wrapper", "macOS signing") to `task`
  subagents — but keep capability/IPC changes in one slice; they share a schema.
- After a Rust change, `mcp__serena__get_diagnostics_for_file` re-checks the file
  before you spend a `cargo tauri build` cycle.

### 9. Capture durable decisions
- `retain` project-specific facts the next session needs: the sidecar protocol
  shape, the capability layout, the updater endpoint, the bundle target set.
  `recall`/`reflect` them at the start of the next Tauri task on this repo.

## Acceptance check (all must hold before "done")

1. `cargo tauri dev` launches the window (managed `hub` process reaches ready);
   no "command not allowed" / "command not found" in the console.
2. Capabilities validate: every command/plugin the app invokes has a granted
   permission in the window's capability file (verified against
   `gen/schemas/desktop-schema.json`).
3. The IPC round-trip a user depends on is **exercised**, not asserted: drive the
   webview via `browser`/`8sync shot`, fire the real `invoke`, observe the real
   result or `listen` event. Screenshot evidence saved for any visual claim.
4. The target bundle builds: `cargo tauri build` succeeds for the configured
   `bundle.targets`; if the updater is configured, signature artifacts
   (`*.sig`) + `latest.json` are emitted (`createUpdaterArtifacts: true`).
5. `engine_verify` (verify = the build/test above) is green for the changed slice.

## Non-goals

- Mobile (iOS/Android) unless the project already targets it — only the
  lib/main split + `crate-type` note from base §1 apply.
- Maintaining a v1-only app with no v2 migration intent.
- Rewriting or swapping the frontend framework (React/Vue/Svelte/bun — Tauri is
  agnostic; this skill treats the webview as a black box you `invoke`/`listen`).
- Vendoring upstream docs — `references/base.md` distils and links; always defer
  to <https://v2.tauri.app/> for the full, current surface.

Files in this skill

  • SKILL.md9.4 KB
  • references/base.md8.9 KB
  • references/patterns.md12.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.