.claude/skills/tauri-2/tauri-syntax/tauri-syntax-permissions/SKILL.md
Use when configuring permissions, creating capability files, setting up plugin access control, or debugging permission denied errors. Prevents using v1 allowlist patterns and overly permissive wildcard capabilities that compromise security. Covers capability file structure, permission definitions in TOML, scope configuration, plugin and custom command permissions. Keywords: tauri permissions, capabilities, allow, deny, scope, TOML, plugin permissions, access control, ACL.
npx skillsauth add OpenAEC-Foundation/OpenAEC-Workspace-Composer tauri-syntax-permissionsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This system is NEW IN TAURI 2 — it replaces the v1 allowlist entirely. Claude frequently generates v1-style
allowlistconfig which does not exist in v2.
| Format | Example | Description |
|--------|---------|-------------|
| <plugin>:default | fs:default | Default safe permissions for a plugin |
| <plugin>:allow-<command> | fs:allow-read-file | Allow a specific command |
| <plugin>:deny-<command> | fs:deny-write-file | Deny a specific command |
| <plugin>:<custom-set> | fs:read-files | Custom permission set |
| core:<module>:default | core:window:default | Core module defaults |
| core:<module>:allow-<cmd> | core:window:allow-set-title | Allow specific core command |
| allow-<command> | allow-greet | Custom app command (no plugin prefix) |
| File | Location | Format | Purpose |
|------|----------|--------|---------|
| Capability files | src-tauri/capabilities/*.json | JSON or TOML | Assign permissions to windows |
| App permissions | src-tauri/permissions/*.toml | TOML only | Define custom command permissions |
| Generated schemas | src-tauri/gen/schemas/ | JSON | IDE autocompletion |
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| $schema | string | No | Path to generated schema for IDE support |
| identifier | string | Yes | Unique capability name |
| description | string | No | Purpose description |
| windows | string[] | Yes | Window labels ("*" for all) |
| permissions | string[] | Yes | Permission identifiers |
| platforms | string[] | No | "linux", "macOS", "windows", "iOS", "android" |
| remote | object | No | Remote URL access config |
NEVER use Tauri v1 allowlist syntax in tauri.conf.json — the allowlist was completely removed in v2. Use capability files instead.
NEVER assume plugins have permissions by default — installing a plugin crate and npm package does NOT grant any permissions. You MUST add permissions to a capability file or commands will fail with "command not allowed".
NEVER use "windows": ["*"] with broad permissions in production — this grants every window the same access. Use specific window labels.
NEVER write application permission definitions in JSON format — app-level permissions in src-tauri/permissions/ MUST be TOML. Only capability files support JSON.
ALWAYS add core:default or the specific core:*:default permissions your app needs — core features (window management, events, paths, menus) require explicit permissions in v2.
ALWAYS run cargo build after modifying permission/capability files — permissions are validated and compiled at build time.
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Default capabilities for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"core:window:default",
"core:app:default"
]
}
Save as src-tauri/capabilities/default.json. Files in the capabilities/ directory are automatically enabled.
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Main window with plugin access",
"windows": ["main"],
"permissions": [
"core:default",
"core:window:default",
"core:app:default",
"core:event:default",
"core:path:default",
"fs:default",
"fs:allow-read-file",
"dialog:default",
"dialog:allow-open",
"shell:default",
"http:default",
"notification:default",
"clipboard-manager:allow-read",
"clipboard-manager:allow-write"
]
}
Step 1 — Define the Rust command:
#[tauri::command]
fn save_document(title: String, content: String) -> Result<(), String> {
// ... save logic
Ok(())
}
// Register in builder:
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![save_document])
Step 2 — Create permission file (src-tauri/permissions/my-commands.toml):
[[permission]]
identifier = "allow-save-document"
description = "Allows invoking the save_document command"
commands.allow = ["save_document"]
[[permission]]
identifier = "deny-save-document"
description = "Denies the save_document command"
commands.deny = ["save_document"]
Step 3 — Add to capability file (src-tauri/capabilities/default.json):
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"windows": ["main"],
"permissions": [
"core:default",
"allow-save-document"
]
}
Note: Custom app command permissions do NOT use a plugin prefix.
# src-tauri/permissions/file-access.toml
[[permission]]
identifier = "scope-documents"
description = "Access to user documents directory"
[[scope.allow]]
path = "$DOCUMENT/*"
[[scope.deny]]
path = "$DOCUMENT/.secret/*"
{
"permissions": [
"fs:default",
"fs:allow-read-file",
"scope-documents"
]
}
Bundle multiple permissions under a single identifier:
# src-tauri/permissions/document-editor.toml
[[set]]
identifier = "document-editor-full"
description = "All permissions for the document editor feature"
permissions = [
"fs:default",
"fs:allow-read-file",
"fs:allow-write-file",
"dialog:allow-open",
"dialog:allow-save",
"allow-save-document",
"allow-load-document"
]
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "desktop-only",
"windows": ["main"],
"platforms": ["linux", "macOS", "windows"],
"permissions": [
"global-shortcut:allow-register",
"global-shortcut:allow-unregister"
]
}
{
"$schema": "../gen/schemas/mobile-schema.json",
"identifier": "mobile-only",
"windows": ["main"],
"platforms": ["iOS", "android"],
"permissions": [
"nfc:allow-scan",
"biometric:allow-authenticate",
"barcode-scanner:allow-scan"
]
}
{
"$schema": "../gen/schemas/remote-schema.json",
"identifier": "remote-capability",
"windows": ["main"],
"remote": {
"urls": ["https://*.example.com"]
},
"platforms": ["iOS", "android"],
"permissions": [
"nfc:allow-scan",
"barcode-scanner:allow-scan"
]
}
| Plugin | Default | Common Allow | Common Deny |
|--------|---------|-------------|-------------|
| fs | fs:default | fs:allow-read-file, fs:allow-write-file, fs:allow-mkdir | fs:deny-write-file |
| dialog | dialog:default | dialog:allow-open, dialog:allow-save, dialog:allow-message | — |
| shell | shell:default | shell:allow-open, shell:allow-execute | — |
| http | http:default | http:allow-fetch | — |
| notification | notification:default | notification:allow-notify | — |
| clipboard-manager | — | clipboard-manager:allow-read, clipboard-manager:allow-write | — |
| process | — | process:allow-restart, process:allow-exit | — |
| updater | updater:default | updater:allow-check, updater:allow-download-and-install | — |
| os | os:default | os:allow-platform | — |
| global-shortcut | — | global-shortcut:allow-register | — |
| Module | Default | Example Allow |
|--------|---------|---------------|
| core:app | core:app:default | core:app:allow-version |
| core:window | core:window:default | core:window:allow-set-title, core:window:allow-close |
| core:event | core:event:default | core:event:allow-listen, core:event:allow-emit |
| core:path | core:path:default | core:path:allow-resolve |
| core:menu | core:menu:default | — |
| core:tray | core:tray:default | — |
| core:resources | core:resources:default | — |
When a window appears in multiple capability files, all permissions from all capabilities are merged additively. There is no override or conflict resolution — permissions accumulate.
Tauri generates JSON schemas in src-tauri/gen/schemas/:
desktop-schema.jsonmobile-schema.jsonremote-schema.jsonReference via $schema for IDE autocompletion. These schemas are regenerated on build.
Capabilities can also be defined inline (less common):
{
"app": {
"security": {
"capabilities": [
{
"identifier": "inline-capability",
"windows": ["*"],
"permissions": ["fs:default"]
},
"my-external-capability"
]
}
}
}
development
Use when integrating Vite with a backend framework, rendering Vite assets from server-side templates, or setting up dev/production HTML serving. Prevents incorrect manifest.json traversal and missing CSS chunk resolution in production. Covers build.manifest configuration, .vite/manifest.json structure, ManifestChunk properties, dev mode HTML setup, production rendering, CSS/JS chunk resolution, and modulepreload polyfill. Keywords: backend integration, manifest.json, ManifestChunk, Django, Laravel, Rails, modulepreload.
development
Use when encountering dev server startup failures, HMR issues, proxy errors, CORS blocks, or module not found errors during development. Prevents misconfiguring server.hmr behind reverse proxies and forgetting appType: 'custom' in middleware mode. Covers HMR full-reload debugging, proxy configuration, CORS setup, HTTPS certificates, server.fs.strict violations, port conflicts, WebSocket failures, file watcher issues, and middleware mode. Keywords: dev server, HMR, proxy, CORS, HTTPS, WebSocket, port conflict, server.fs.strict, middleware mode, file watcher.
development
Use when encountering pre-bundling errors, dependency resolution failures, stale cache issues, or slow development server startup. Prevents excluding CJS dependencies from pre-bundling (which breaks runtime module resolution) and misconfiguring optimizeDeps. Covers CJS/ESM conversion failures, missing dependency auto-discovery, optimizeDeps configuration, monorepo linked dependencies, cache invalidation, browser cache staleness, and large dependency tree performance. Keywords: pre-bundling, optimizeDeps, CJS, ESM, cache, dependency resolution, monorepo, node_modules/.vite.
development
Use when encountering Vite build failures, chunk size warnings, or version-specific build errors. Prevents the common mistake of using deprecated rollupOptions in v8 or misconfiguring build targets and minifiers. Covers Rolldown/Rollup bundling failures, CSS minification errors, sourcemap problems, library mode build failures, BundleError handling, and asset processing errors. Keywords: build error, Rolldown, chunk size, sourcemap, library mode, minify, BundleError, rollupOptions, build.target.