{
  "id": "tauri-2-api-guard",
  "type": "loadout",
  "title": "Tauri 2 guard for Tauri 1 imports, config and Rust APIs",
  "summary": "Stop agents writing @tauri-apps/api/tauri, appWindow, the allowlist, get_window and emit_all into Tauri 2 apps, and catch the snake_case invoke arguments Tauri 2 rejects.",
  "description": "Tauri 2 has been out since October 2024, but much of what agents learnt is Tauri 1. Tauri 2 moved invoke to @tauri-apps/api/core, replaced appWindow, split fs, dialog, shell and http into plugins, replaced the allowlist with capabilities, renamed tauri.conf.json keys (tauri to app, distDir to frontendDist, devPath to devUrl) and renamed core Rust APIs (get_window, emit_all, SystemTray, WindowBuilder). It also expects command arguments in camelCase from JavaScript, which catches out new Tauri 2 code too.\n\nThis loadout pairs a Cursor rule and AGENTS.md (a never/always table covering the front end, the config and Rust) with a skill that checks the work. A standard-library Python scanner reports Tauri 1 code as errors across .ts/.js, .rs, tauri.conf.json, Cargo.toml and package.json. Then tsc checks the front end, a Node test mocks the IPC to pin the argument names, and the config is validated against the schema shipped in the Tauri CLI. The verifier runs all of this on a Tauri 2 notes app and a Tauri 1 sample, and checks the Rust names against the published tauri 2.12.5 crate source. For least-privilege capabilities, pair it with the Tauri 2 desktop app loadout.\n",
  "highlights": [
    "Never/always table for the front end, tauri.conf.json and Rust",
    "Scanner flags Tauri 1 imports, config keys and Rust APIs as errors",
    "Warns on snake_case invoke arguments, which Tauri 2 doesn't map",
    "A Node test with @tauri-apps/api/mocks pins the camelCase argument names",
    "Validates tauri.conf.json against the schema shipped in the Tauri CLI"
  ],
  "version": "1.0.0",
  "license": "MIT",
  "author": {
    "name": "SetupBay",
    "url": "https://setupbay.com"
  },
  "credits": [
    {
      "title": "Tauri docs: upgrade from Tauri 1.0",
      "url": "https://v2.tauri.app/start/migrate/from-tauri-1/"
    },
    {
      "title": "Tauri docs: calling Rust from the front end",
      "url": "https://v2.tauri.app/develop/calling-rust/"
    },
    {
      "title": "Tauri docs: mocking Tauri APIs",
      "url": "https://v2.tauri.app/develop/tests/mocking/"
    },
    {
      "title": "@tauri-apps/api 2.12.4 on npm",
      "url": "https://www.npmjs.com/package/@tauri-apps/api/v/2.12.4"
    },
    {
      "title": "tauri 2.12.5 on crates.io",
      "url": "https://crates.io/crates/tauri/2.12.5"
    },
    {
      "title": "@iameythakur: Tauri v2 command arguments are camelCase by default",
      "url": "https://x.com/iameythakur/status/2115093332095377815"
    }
  ],
  "categories": [
    "web-app"
  ],
  "stacks": [
    "tauri",
    "typescript",
    "rust"
  ],
  "files": [
    {
      "path": "AGENTS.md",
      "role": "instructions",
      "description": "Tauri 2 version facts, rules and the done checklist.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": "AGENTS.md",
        "codex": "AGENTS.md",
        "cursor": "AGENTS.md",
        "gemini-cli": "AGENTS.md",
        "antigravity-cli": "AGENTS.md",
        "copilot": "AGENTS.md"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/AGENTS.md",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/AGENTS.md",
      "bytes": 3009,
      "lang": "markdown",
      "content": "# AGENTS.md: Tauri 2 app (Tauri 1 API guard)\n\nThis desktop app runs **Tauri 2** (`tauri` crate 2.12, `@tauri-apps/api` 2.12). Tauri 2 came out in October 2024,\nbut much of what you learnt is Tauri 1: `@tauri-apps/api/tauri`, `appWindow`, `@tauri-apps/api/fs`, the\n`allowlist`, `get_window`, `emit_all` and `SystemTray`. None of those work in Tauri 2.\n\n## Version facts\n- Check the pins first: `src-tauri/Cargo.toml` (`tauri = \"2...\"`) and `package.json` (`@tauri-apps/api` 2.x).\n  If either says 1.x, stop and ask; don't mix the two.\n- Front end: `invoke` comes from `@tauri-apps/api/core`. The current window is `getCurrentWebviewWindow()` from\n  `@tauri-apps/api/webviewWindow`. fs, dialog, shell, http, clipboard, notification, os, process and the updater are\n  plugins: a JS package `@tauri-apps/plugin-<name>`, a Rust crate `tauri-plugin-<name>` registered with\n  `.plugin(...)`, and a permission in `src-tauri/capabilities/`.\n- Opening URLs and files is `openUrl` / `openPath` from `@tauri-apps/plugin-opener`, not shell `open`.\n- **Command arguments are camelCase from JS.** A Rust `fn save_note(note_title: String)` is called with\n  `invoke(\"save_note\", { noteTitle })`. Sending `note_title` fails with a missing-argument error. (Return values and\n  struct fields keep their serde names.)\n- Config: there's no `tauri` or `package` key. `productName`, `version` and `identifier` are top level, the window\n  list and security settings live under `app`, `build.devPath` is `build.devUrl` and `build.distDir` is\n  `build.frontendDist`. Validate against the schema in `node_modules/@tauri-apps/cli/config.schema.json`.\n- Rust: `get_webview_window`, `emit` (the `Emitter` trait), `app.path()`, `tauri::tray::TrayIconBuilder`,\n  `tauri::menu::MenuBuilder`, `WebviewWindowBuilder`. The builder goes in `lib.rs` as `pub fn run()` with\n  `#[cfg_attr(mobile, tauri::mobile_entry_point)]`, and `main.rs` only calls it.\n- Docs for this version: https://v2.tauri.app/ (the migration guide is\n  https://v2.tauri.app/start/migrate/from-tauri-1/). Ignore tauri.app/v1 pages.\n\n## Rules\n- Write Tauri 2 code only. The `tauri-2-guard` skill has the full table.\n- Every plugin needs all three parts: the npm package, the crate plus `.plugin(...)`, and the narrowest permission\n  that works. Never add `\"fs:default\"`-style wide grants to make an error go away; ask.\n- Keep `app.security.csp`. Don't turn on `withGlobalTauri` to use `window.__TAURI__`; import from `@tauri-apps/api`.\n- Don't change the Tauri version without asking.\n\n## Before you say \"done\"\n1. Run the `tauri-2-guard` scanner on `src`, `src-tauri` and `package.json`. It must report `0 error(s)`.\n2. Type-check the front end (`npx tsc --noEmit`) and run its tests, mocking the IPC with `@tauri-apps/api/mocks`.\n3. Validate `src-tauri/tauri.conf.json` against the CLI's config schema.\n4. Run `cargo check --manifest-path src-tauri/Cargo.toml` where the system has the WebView libraries, and\n   `npm run tauri dev` if you changed windows, menus or the tray.\n"
    },
    {
      "path": "CLAUDE.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Claude Code.",
      "skill": null,
      "agent": "claude-code",
      "install_to": {
        "claude-code": "CLAUDE.md",
        "codex": null,
        "cursor": null,
        "gemini-cli": null,
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/CLAUDE.md",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/CLAUDE.md",
      "bytes": 392,
      "lang": "markdown",
      "content": "# CLAUDE.md\n\n@AGENTS.md\n\n## Claude Code notes\n\n- Skills from this loadout live in `.claude/skills/`: `tauri-2-guard`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From SetupBay \"Tauri 2 guard for Tauri 1 imports, config and Rust APIs\" v1.0.0 — https://setupbay.com/loadouts/tauri-2-api-guard/ -->\n"
    },
    {
      "path": "GEMINI.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Gemini CLI.",
      "skill": null,
      "agent": "gemini-cli",
      "install_to": {
        "claude-code": null,
        "codex": null,
        "cursor": null,
        "gemini-cli": "GEMINI.md",
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/GEMINI.md",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/GEMINI.md",
      "bytes": 393,
      "lang": "markdown",
      "content": "# GEMINI.md\n\n@./AGENTS.md\n\n## Gemini CLI notes\n\n- Skills from this loadout live in `.agents/skills/`: `tauri-2-guard`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From SetupBay \"Tauri 2 guard for Tauri 1 imports, config and Rust APIs\" v1.0.0 — https://setupbay.com/loadouts/tauri-2-api-guard/ -->\n"
    },
    {
      "path": ".cursor/rules/tauri-2-only.mdc",
      "role": "rules",
      "description": "Never/always table for the front end, Rust and tauri.conf.json.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": null,
        "codex": null,
        "cursor": ".cursor/rules/tauri-2-only.mdc",
        "gemini-cli": null,
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/.cursor/rules/tauri-2-only.mdc",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/.cursor/rules/tauri-2-only.mdc",
      "bytes": 1506,
      "lang": "markdown",
      "content": "---\ndescription: Tauri 2 only; no Tauri 1 imports, Rust APIs or config keys\nglobs: \"src/**/*.ts,src/**/*.js,src/**/*.tsx,src/**/*.vue,src/**/*.svelte,src-tauri/**/*.rs,src-tauri/tauri.conf.json\"\nalwaysApply: false\n---\n\nThis app uses Tauri 2. Never write Tauri 1 code.\n\n| Never (Tauri 1) | Always (Tauri 2) |\n|---|---|\n| `import { invoke } from \"@tauri-apps/api/tauri\"` | `import { invoke } from \"@tauri-apps/api/core\"` |\n| `appWindow.setTitle(...)` | `getCurrentWebviewWindow().setTitle(...)` (`@tauri-apps/api/webviewWindow`) |\n| `@tauri-apps/api/fs`, `/dialog`, `/shell`, `/http` | `@tauri-apps/plugin-fs`, `-dialog`, `-shell`, `-http` (+ crate + permission) |\n| shell `open(url)` | `openUrl(url)` from `@tauri-apps/plugin-opener` |\n| `invoke(\"save_note\", { note_title })` | `invoke(\"save_note\", { noteTitle })` (camelCase) |\n| `\"allowlist\"` | `src-tauri/capabilities/*.json` permissions |\n| `\"tauri\": {...}`, `\"package\": {...}` | `\"app\": {...}`; top-level `productName`, `version`, `identifier` |\n| `build.devPath`, `build.distDir` | `build.devUrl`, `build.frontendDist` |\n| `app.get_window(\"main\")` | `app.get_webview_window(\"main\")` |\n| `window.emit_all(...)` | `window.emit(...)` (`use tauri::Emitter`) |\n| `SystemTray`, `CustomMenuItem`, `WindowBuilder` | `TrayIconBuilder`, `MenuItemBuilder`, `WebviewWindowBuilder` |\n| `app.path_resolver()`, `tauri::api::*` | `app.path()`, the plugin crates |\n\n- After editing, run the `tauri-2-guard` skill's scanner, the type-check and the config schema check.\n"
    },
    {
      "path": "skills/tauri-2-guard/SKILL.md",
      "role": "skill",
      "description": "Scan for Tauri 1 code, then type-check, test with mocked IPC and validate the config schema.",
      "skill": "tauri-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/tauri-2-guard/SKILL.md",
        "codex": ".agents/skills/tauri-2-guard/SKILL.md",
        "cursor": ".agents/skills/tauri-2-guard/SKILL.md",
        "gemini-cli": ".agents/skills/tauri-2-guard/SKILL.md",
        "antigravity-cli": ".agents/skills/tauri-2-guard/SKILL.md",
        "copilot": ".agents/skills/tauri-2-guard/SKILL.md"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/SKILL.md",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/skills/tauri-2-guard/SKILL.md",
      "bytes": 2921,
      "lang": "markdown",
      "content": "---\nname: tauri-2-guard\ndescription: Check a Tauri 2 app for Tauri 1 code in the front end, the Rust side and tauri.conf.json (api/tauri imports, appWindow, the allowlist, get_window, emit_all, SystemTray) and for snake_case invoke arguments, then type-check, test with mocked IPC and validate the config schema. Use after writing or editing Tauri code, when invoke reports a missing argument, or when porting a Tauri 1 example.\n---\n\n# Tauri 2 guard\n\nMost Tauri examples online are Tauri 1, and Tauri 2 changed the import paths, moved fs/dialog/shell/http into\nplugins, replaced the allowlist with capabilities, renamed config keys and renamed core Rust APIs. One change bites\neven in pure Tauri 2 code: JS must send command arguments in camelCase.\n\n## 1. Confirm the version\n- `src-tauri/Cargo.toml` must say `tauri = \"2...\"` and `package.json` `@tauri-apps/api` 2.x. If not, stop and ask.\n\n## 2. Scan\n```bash\npython3 .agents/skills/tauri-2-guard/scripts/tauri2_guard.py src src-tauri package.json\n```\n(Use the path the skill was installed to: `.claude/skills/...` for Claude Code, `.agents/skills/...` for the others.)\n\n- Each `error` is Tauri 1 code. Fix it with the replacement on the line, or look it up in `references/v1-to-v2.md`.\n- `warn [invoke-snake-args]`: rename the keys to camelCase, unless the Rust command has\n  `#[tauri::command(rename_all = \"snake_case\")]`. Then add `// guard: ok rename_all` to the line.\n- `warn [global-tauri]`: import from `@tauri-apps/api` instead of using `window.__TAURI__`.\n- When a plugin import is reported, add all three parts: the npm package, the crate plus `.plugin(...)`, and a\n  narrow permission in `src-tauri/capabilities/`.\n\n## 3. Check the front end\n```bash\nnpx tsc --noEmit\n```\nTest calls to Rust without running the app, using the mocks that ship with `@tauri-apps/api`:\n```js\nglobalThis.window ??= globalThis; // only when the test runs in Node\nconst { mockIPC, mockWindows } = await import(\"@tauri-apps/api/mocks\");\nmockWindows(\"main\");\nmockIPC((cmd, args) => (cmd === \"save_note\" ? `saved ${args.noteTitle}` : null));\n```\nAssert on the command name and the argument keys, so a snake_case key fails the test.\n\n## 4. Validate the config\n`node_modules/@tauri-apps/cli/config.schema.json` is the schema for this exact CLI version, and it rejects unknown\nkeys. Validate `src-tauri/tauri.conf.json` against it with any JSON Schema (draft-07) validator. With Ajv, pass\n`unicodeRegExp: false`, because the schema has a pattern that isn't valid as a Unicode regex.\n\n## 5. Check the Rust side\n`cargo check --manifest-path src-tauri/Cargo.toml` needs the platform WebView libraries (on Linux, webkit2gtk-4.1).\nWhere they aren't installed, say so in your report rather than claiming the Rust side compiles.\n\n## 6. Report\nSay which Tauri 1 calls and keys you replaced, which plugins and permissions you added, and which checks ran\n(scanner, tsc, tests, schema, cargo check).\n"
    },
    {
      "path": "skills/tauri-2-guard/scripts/tauri2_guard.py",
      "role": "reference",
      "description": "Read-only scanner for Tauri 1 imports, config keys, Rust APIs and snake_case invoke arguments.",
      "skill": "tauri-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/tauri-2-guard/scripts/tauri2_guard.py",
        "codex": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
        "cursor": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
        "gemini-cli": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
        "antigravity-cli": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
        "copilot": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/scripts/tauri2_guard.py",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/skills/tauri-2-guard/scripts/tauri2_guard.py",
      "bytes": 8586,
      "lang": "markdown",
      "content": "#!/usr/bin/env python3\n\"\"\"Find Tauri 1 APIs, imports and config keys in a Tauri 2 app (front end, src-tauri Rust, tauri.conf.json, manifests).\n\nUsage: python3 tauri2_guard.py [PATH ...]        (default: the current folder)\n       python3 tauri2_guard.py --list            (print every rule)\n\nA \"guard: ok\" comment on a line silences its warnings (never its errors).\nPrints one line per finding:  path:line: level [rule] what is wrong -> what to use\nExit 0 when nothing at \"error\" level is found, 1 when something is, 2 on bad usage.\nStandard library only. Read-only: it never edits a file and makes no network calls.\n\"\"\"\nimport fnmatch\nimport os\nimport re\nimport sys\n\n# (rule id, level, regex, message, file patterns). Patterns run against each line with comments removed.\nRULES = [\n    ('api-tauri-module', 'error', '[\\\\\"\\']@tauri-apps/api/tauri[\\\\\"\\']',\n     '@tauri-apps/api/tauri was renamed -> @tauri-apps/api/core (invoke, convertFileSrc)', ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte']),\n    ('api-plugin-module', 'error', '[\\\\\"\\']@tauri-apps/api/(fs|dialog|shell|http|clipboard|notification|globalShortcut|os|process|updater|cli)[\\\\\"\\']',\n     'this module moved to a plugin in Tauri 2 -> @tauri-apps/plugin-<name> plus the Rust crate tauri-plugin-<name> and a capability permission', ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte']),\n    ('app-window', 'error', '\\\\bappWindow\\\\b',\n     'appWindow was removed -> getCurrentWebviewWindow() from @tauri-apps/api/webviewWindow (or getCurrentWindow() from /window)', ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte']),\n    ('webview-window-import', 'error', 'import\\\\s*\\\\{[^}]*\\\\bWebviewWindow\\\\b[^}]*\\\\}\\\\s*from\\\\s*[\\\\\"\\']@tauri-apps/api/window[\\\\\"\\']',\n     'WebviewWindow moved -> import it from @tauri-apps/api/webviewWindow', ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte']),\n    ('invoke-snake-args', 'warn', 'invoke\\\\(\\\\s*[\\\\\"\\'][^\\\\\"\\']+[\\\\\"\\']\\\\s*,\\\\s*\\\\{[^}]*\\\\b[a-z0-9]+_[a-z0-9_]+\\\\s*:',\n     'Tauri command arguments are camelCase on the JS side by default (Rust note_title -> JS noteTitle), unless the command uses rename_all = \"snake_case\"', ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte']),\n    ('global-tauri', 'warn', 'window\\\\.__TAURI__\\\\b',\n     'window.__TAURI__ only exists with app.withGlobalTauri: true -> import from @tauri-apps/api instead', ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte']),\n    ('shell-open-url', 'warn', 'import\\\\s*\\\\{[^}]*\\\\bopen\\\\b[^}]*\\\\}\\\\s*from\\\\s*[\\\\\"\\']@tauri-apps/plugin-shell[\\\\\"\\']',\n     'shell open() is deprecated for URLs and files -> openUrl / openPath from @tauri-apps/plugin-opener', ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte']),\n    ('conf-allowlist', 'error', '\\\\\"allowlist\\\\\"\\\\s*:',\n     'the allowlist was replaced by capabilities -> src-tauri/capabilities/*.json with plugin permissions', ['tauri.conf.json']),\n    ('conf-tauri-key', 'error', '^\\\\s{0,4}\\\\\"tauri\\\\\"\\\\s*:\\\\s*\\\\{',\n     'the top-level \"tauri\" object was renamed -> \"app\" (and bundle moves to the top level)', ['tauri.conf.json']),\n    ('conf-dist-dir', 'error', '\\\\\"distDir\\\\\"\\\\s*:',\n     'build.distDir was renamed -> build.frontendDist', ['tauri.conf.json']),\n    ('conf-dev-path', 'error', '\\\\\"devPath\\\\\"\\\\s*:',\n     'build.devPath was renamed -> build.devUrl', ['tauri.conf.json']),\n    ('conf-package', 'error', '^\\\\s{0,4}\\\\\"package\\\\\"\\\\s*:\\\\s*\\\\{',\n     'the \"package\" object was removed -> top-level productName and version', ['tauri.conf.json']),\n    ('conf-system-tray', 'error', '\\\\\"systemTray\\\\\"\\\\s*:',\n     'systemTray was renamed -> app.trayIcon (or build it in Rust with TrayIconBuilder)', ['tauri.conf.json']),\n    ('conf-updater', 'error', '\\\\\"updater\\\\\"\\\\s*:\\\\s*\\\\{\\\\s*\\\\\"active\\\\\"',\n     'the built-in updater moved to a plugin -> plugins.updater and tauri-plugin-updater', ['tauri.conf.json']),\n    ('rs-get-window', 'error', '\\\\.get_window\\\\(',\n     'get_window() only exists behind the unstable feature in Tauri 2 -> get_webview_window()', ['*.rs']),\n    ('rs-emit-all', 'error', '\\\\.emit_all\\\\(',\n     'emit_all() was removed -> emit() (to every target), or emit_to()', ['*.rs']),\n    ('rs-system-tray', 'error', '\\\\bSystemTray(Event|Menu|MenuItem)?\\\\b',\n     'SystemTray was replaced -> tauri::tray::TrayIconBuilder (feature tray-icon)', ['*.rs']),\n    ('rs-window-builder', 'error', '\\\\bWindowBuilder::new\\\\(',\n     'WindowBuilder::new was replaced -> WebviewWindowBuilder::new(app, label, WebviewUrl::App(...))', ['*.rs']),\n    ('rs-custom-menu', 'error', '\\\\bCustomMenuItem\\\\b|\\\\bMenu::new\\\\(\\\\s*\\\\)',\n     'the Tauri 1 menu API was replaced -> tauri::menu::{MenuBuilder, MenuItemBuilder}', ['*.rs']),\n    ('rs-api-module', 'error', '\\\\btauri::api::',\n     'tauri::api was removed -> the matching plugin crate (tauri-plugin-shell, -dialog, -fs, -http, -os, -process)', ['*.rs']),\n    ('rs-path-resolver', 'error', '\\\\.path_resolver\\\\(\\\\)',\n     'path_resolver() was removed -> app.path() (the PathResolver from the Manager trait)', ['*.rs']),\n    ('rs-window-param', 'warn', 'fn\\\\s+\\\\w+\\\\s*\\\\([^)]*:\\\\s*tauri::Window\\\\b',\n     'commands get a WebviewWindow in Tauri 2 -> window: tauri::WebviewWindow', ['*.rs']),\n    ('cargo-tauri-1', 'error', '^\\\\s*tauri(-build)?\\\\s*=\\\\s*(\\\\{[^}]*version\\\\s*=\\\\s*)?\\\\\"[~^=]?1\\\\.',\n     'Cargo.toml pins Tauri 1 -> tauri = \"2\" and tauri-build = \"2\"', ['Cargo.toml']),\n    ('npm-tauri-1', 'error', '\\\\\"@tauri-apps/(api|cli)\\\\\"\\\\s*:\\\\s*\\\\\"[~^]?1\\\\.',\n     'package.json pins Tauri 1 -> @tauri-apps/api and @tauri-apps/cli 2.x', ['package.json']),\n]\nFILES = ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', '*.vue', '*.svelte', '*.rs', 'tauri.conf.json', 'Cargo.toml', 'package.json']\nCOMMENT = '//'\nSKIP_DIRS = {\".git\", \".venv\", \"venv\", \"node_modules\", \"__pycache__\", \".agents\", \".claude\", \".cursor\", \"dist\", \"build\", \"target\", \".godot\"}\nCOMPILED = [(rid, lvl, re.compile(rx), msg, globs) for rid, lvl, rx, msg, globs in RULES]\n\n\ndef strip_comment(line):\n    \"\"\"Drop a trailing comment, leaving string literals alone.\"\"\"\n    q = None\n    i = 0\n    while i < len(line):\n        c = line[i]\n        if q:\n            if c == \"\\\\\":\n                i += 2\n                continue\n            if c == q:\n                q = None\n        elif c in \"\\\"'`\":\n            q = c\n        elif line.startswith(COMMENT, i):\n            return line[:i]\n        i += 1\n    return line\n\n\ndef wanted(name):\n    return any(fnmatch.fnmatch(name, g) for g in FILES)\n\n\ndef walk(paths):\n    for p in paths:\n        if os.path.isfile(p):\n            yield p\n            continue\n        for root, dirs, files in os.walk(p):\n            dirs[:] = sorted(d for d in dirs if d not in SKIP_DIRS)\n            for f in sorted(files):\n                if wanted(f):\n                    yield os.path.join(root, f)\n\n\ndef scan(path):\n    out = []\n    name = os.path.basename(path)\n    try:\n        with open(path, encoding=\"utf-8\", errors=\"replace\") as fh:\n            lines = fh.read().splitlines()\n    except OSError as e:\n        return [(path, 0, \"error\", \"unreadable\", str(e))]\n    for n, raw in enumerate(lines, 1):\n        code = strip_comment(raw)\n        if not code.strip():\n            continue\n        accepted = \"guard: ok\" in raw  # a person accepted the warnings on this line\n        for rid, lvl, rx, msg, globs in COMPILED:\n            if accepted and lvl == \"warn\":\n                continue\n            if globs and not any(fnmatch.fnmatch(name, g) for g in globs):\n                continue\n            if rx.search(code):\n                out.append((path, n, lvl, rid, msg))\n    return out\n\n\ndef main(argv):\n    if \"--list\" in argv:\n        for rid, lvl, _, msg, globs in RULES:\n            print(f\"{lvl:5} [{rid}] {msg}\" + (f\"  (only {', '.join(globs)})\" if globs else \"\"))\n        return 0\n    if any(a.startswith(\"-\") for a in argv):\n        print(__doc__)\n        return 2\n    paths = argv or [\".\"]\n    for p in paths:\n        if not os.path.exists(p):\n            print(f\"no such path: {p}\", file=sys.stderr)\n            return 2\n    files = list(walk(paths))\n    findings = []\n    for f in files:\n        findings.extend(scan(f))\n    for path, n, lvl, rid, msg in findings:\n        print(f\"{os.path.relpath(path)}:{n}: {lvl} [{rid}] {msg}\")\n    errors = sum(1 for x in findings if x[2] == \"error\")\n    warns = sum(1 for x in findings if x[2] == \"warn\")\n    print(f\"tauri2_guard: {len(files)} file(s), {errors} error(s), {warns} warning(s)\")\n    return 1 if errors else 0\n\n\nif __name__ == \"__main__\":\n    sys.exit(main(sys.argv[1:]))\n"
    },
    {
      "path": "skills/tauri-2-guard/references/v1-to-v2.md",
      "role": "reference",
      "description": "Tauri 1 to Tauri 2 tables for the front end, the config and Rust.",
      "skill": "tauri-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/tauri-2-guard/references/v1-to-v2.md",
        "codex": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
        "cursor": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
        "gemini-cli": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
        "antigravity-cli": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
        "copilot": ".agents/skills/tauri-2-guard/references/v1-to-v2.md"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/v1-to-v2.md",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/skills/tauri-2-guard/references/v1-to-v2.md",
      "bytes": 3132,
      "lang": "markdown",
      "content": "# Tauri 1 to Tauri 2, the code agents get wrong\n\nFrom the official guide (https://v2.tauri.app/start/migrate/from-tauri-1/). Checked against `@tauri-apps/api` 2.12.4,\n`@tauri-apps/cli` 2.12.4 (config schema 2.12.5) and the `tauri` 2.12.5 crate source.\n\n## Front end\n| Tauri 1 | Tauri 2 |\n|---|---|\n| `import { invoke, convertFileSrc } from \"@tauri-apps/api/tauri\"` | `from \"@tauri-apps/api/core\"` |\n| `import { appWindow } from \"@tauri-apps/api/window\"` | `getCurrentWebviewWindow()` from `@tauri-apps/api/webviewWindow` (or `getCurrentWindow()` from `/window`) |\n| `WebviewWindow` from `@tauri-apps/api/window` | from `@tauri-apps/api/webviewWindow` |\n| `@tauri-apps/api/fs` (`readTextFile(p, { dir })`) | `@tauri-apps/plugin-fs` (`readTextFile(p, { baseDir })`) |\n| `@tauri-apps/api/dialog` | `@tauri-apps/plugin-dialog` |\n| `@tauri-apps/api/shell` `open(url)` | `openUrl(url)` from `@tauri-apps/plugin-opener`; `Command` from `@tauri-apps/plugin-shell` |\n| `@tauri-apps/api/http` | `@tauri-apps/plugin-http` (`fetch`) |\n| `clipboard`, `notification`, `globalShortcut`, `os`, `process`, `updater`, `cli` | `@tauri-apps/plugin-clipboard-manager`, `-notification`, `-global-shortcut`, `-os`, `-process`, `-updater`, `-cli` |\n| `invoke(\"cmd\", { note_title })` | `invoke(\"cmd\", { noteTitle })`: arguments are camelCase by default |\n| `window.__TAURI__.*` | imports from `@tauri-apps/api` (the global needs `app.withGlobalTauri: true`) |\n\n## tauri.conf.json\n| Tauri 1 | Tauri 2 |\n|---|---|\n| `package.productName`, `package.version` | top-level `productName`, `version` |\n| `tauri.bundle.identifier` | top-level `identifier` |\n| `tauri` | `app` (windows, security, trayIcon); `bundle` moves to the top level |\n| `tauri.allowlist` | `src-tauri/capabilities/*.json` with plugin permissions |\n| `build.devPath` / `build.distDir` | `build.devUrl` / `build.frontendDist` |\n| `build.withGlobalTauri` | `app.withGlobalTauri` |\n| `tauri.systemTray` | `app.trayIcon` |\n| `tauri.updater` | `plugins.updater` and `tauri-plugin-updater` |\n\n## Rust\n| Tauri 1 | Tauri 2 |\n|---|---|\n| `app.get_window(\"main\")` | `app.get_webview_window(\"main\")` (`get_window` needs the `unstable` feature) |\n| `window.emit_all(event, payload)` | `window.emit(event, payload)` with `use tauri::Emitter` |\n| `window: tauri::Window` in a command | `window: tauri::WebviewWindow` |\n| `app.path_resolver().app_data_dir()` (Option) | `app.path().app_data_dir()` (Result) |\n| `SystemTray::new().with_menu(...)` | `tauri::tray::TrayIconBuilder::new().menu(&menu).build(app)?` (feature `tray-icon`) |\n| `Menu::new().add_item(CustomMenuItem::new(id, text))` | `MenuBuilder::new(app).item(&MenuItemBuilder::with_id(id, text).build(app)?).build()?` |\n| `WindowBuilder::new(app, label, WindowUrl::App(..))` | `WebviewWindowBuilder::new(app, label, WebviewUrl::App(..))` |\n| `tauri::api::shell::open`, `tauri::api::dialog` | the plugin crates |\n| builder in `main.rs` | `pub fn run()` in `lib.rs` with `#[cfg_attr(mobile, tauri::mobile_entry_point)]` |\n| `tauri = { version = \"1\", features = [\"shell-open\", ...] }` | `tauri = \"2\"` plus plugin crates; allowlist features are gone |\n"
    },
    {
      "path": "skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
      "role": "reference",
      "description": "Tauri 1 front end for checking the guard.",
      "skill": "tauri-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
        "codex": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
        "cursor": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
        "gemini-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
        "antigravity-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
        "copilot": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
      "bytes": 915,
      "lang": "markdown",
      "content": "// Tauri 1 front end, used to check the guard. Every marked import is gone in Tauri 2.\nimport { invoke } from \"@tauri-apps/api/tauri\";\nimport { appWindow, WebviewWindow } from \"@tauri-apps/api/window\";\nimport { readTextFile, BaseDirectory } from \"@tauri-apps/api/fs\";\nimport { open } from \"@tauri-apps/api/dialog\";\nimport { open as openLink } from \"@tauri-apps/api/shell\";\n\nexport async function saveNote(title: string, body: string) {\n  await invoke(\"save_note\", { note_title: title, body });\n  await appWindow.setTitle(`Notes: ${title}`);\n}\n\nexport async function loadNote() {\n  const path = await open({ filters: [{ name: \"Notes\", extensions: [\"md\"] }] });\n  return readTextFile(path as string, { dir: BaseDirectory.AppData });\n}\n\nexport function openHelp() {\n  new WebviewWindow(\"help\", { url: \"help.html\" });\n  return openLink(\"https://tauri.app\");\n}\n\nexport const version = window.__TAURI__.app.getVersion();\n"
    },
    {
      "path": "skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
      "role": "reference",
      "description": "Tauri 1 main.rs for checking the guard.",
      "skill": "tauri-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
        "codex": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
        "cursor": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
        "gemini-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
        "antigravity-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
        "copilot": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
      "bytes": 1207,
      "lang": "markdown",
      "content": "// Tauri 1 src-tauri/src/main.rs, used to check the guard.\nuse tauri::{CustomMenuItem, Manager, Menu, SystemTray, SystemTrayMenu, WindowBuilder, WindowUrl};\n\n#[tauri::command]\nfn save_note(window: tauri::Window, note_title: String, body: String) -> Result<(), String> {\n    let dir = window.app_handle().path_resolver().app_data_dir().ok_or(\"no app data dir\")?;\n    std::fs::write(dir.join(format!(\"{note_title}.md\")), body).map_err(|e| e.to_string())?;\n    window.emit_all(\"note-saved\", note_title).map_err(|e| e.to_string())\n}\n\nfn main() {\n    let tray = SystemTray::new().with_menu(SystemTrayMenu::new());\n    let menu = Menu::new().add_item(CustomMenuItem::new(\"quit\", \"Quit\"));\n    tauri::Builder::default()\n        .menu(menu)\n        .system_tray(tray)\n        .setup(|app| {\n            let main = app.get_window(\"main\").unwrap();\n            WindowBuilder::new(app, \"help\", WindowUrl::App(\"help.html\".into())).build()?;\n            tauri::api::shell::open(&main.shell_scope(), \"https://tauri.app\", None)?;\n            Ok(())\n        })\n        .invoke_handler(tauri::generate_handler![save_note])\n        .run(tauri::generate_context!())\n        .expect(\"error while running tauri application\");\n}\n"
    },
    {
      "path": "skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
      "role": "reference",
      "description": "Tauri 1 tauri.conf.json for checking the guard.",
      "skill": "tauri-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
        "codex": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
        "cursor": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
        "gemini-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
        "antigravity-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
        "copilot": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
      "bytes": 699,
      "lang": "markdown",
      "content": "{\n  \"build\": {\n    \"beforeDevCommand\": \"npm run dev\",\n    \"beforeBuildCommand\": \"npm run build\",\n    \"devPath\": \"http://localhost:1420\",\n    \"distDir\": \"../dist\",\n    \"withGlobalTauri\": true\n  },\n  \"package\": {\n    \"productName\": \"notes\",\n    \"version\": \"0.1.0\"\n  },\n  \"tauri\": {\n    \"allowlist\": {\n      \"all\": false,\n      \"fs\": { \"readFile\": true, \"scope\": [\"$APPDATA/*\"] },\n      \"dialog\": { \"open\": true },\n      \"shell\": { \"open\": true }\n    },\n    \"bundle\": { \"active\": true, \"identifier\": \"com.example.notes\", \"targets\": \"all\" },\n    \"systemTray\": { \"iconPath\": \"icons/icon.png\" },\n    \"updater\": { \"active\": false },\n    \"windows\": [{ \"title\": \"Notes\", \"width\": 800, \"height\": 600 }]\n  }\n}\n"
    },
    {
      "path": "skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
      "role": "reference",
      "description": "Tauri 1 Cargo.toml for checking the guard.",
      "skill": "tauri-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
        "codex": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
        "cursor": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
        "gemini-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
        "antigravity-cli": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
        "copilot": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt"
      },
      "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
      "raw_latest_url": "https://setupbay.com/raw/tauri-2-api-guard/latest/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
      "bytes": 354,
      "lang": "markdown",
      "content": "# Tauri 1 src-tauri/Cargo.toml, used to check the guard.\n[package]\nname = \"notes\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[build-dependencies]\ntauri-build = { version = \"1.5\", features = [] }\n\n[dependencies]\ntauri = { version = \"1.8\", features = [\"shell-open\", \"dialog-open\", \"fs-read-file\", \"system-tray\"] }\nserde = { version = \"1\", features = [\"derive\"] }\n"
    }
  ],
  "requires": {
    "tools": [
      "node",
      "python3"
    ],
    "env": [],
    "mcp": []
  },
  "tested": {
    "status": "untested",
    "last_run": null,
    "fixture": null,
    "per_agent": {
      "claude-code": "untested",
      "codex": "untested",
      "cursor": "untested",
      "gemini-cli": "untested",
      "antigravity-cli": "untested",
      "copilot": "untested"
    }
  },
  "security": {
    "scanned": true,
    "scanner": "intake-precheck/2",
    "verdict": "clean",
    "network": true,
    "scripts": [
      "tauri2_guard.py"
    ],
    "notes": "The scanner only reads source, config and manifest files and prints findings; it never edits files and makes no network calls. Installing the project's pinned packages with npm, or running cargo, downloads them."
  },
  "featured": false,
  "deprecated": false,
  "last_checked": "2026-10-29",
  "published": "2026-10-29",
  "updated": "2026-10-29",
  "compatibility": {
    "claude-code": "native",
    "codex": "native",
    "cursor": "native",
    "gemini-cli": "native",
    "antigravity-cli": "native",
    "copilot": "native"
  },
  "counts": {
    "rules": 2,
    "skills": 1,
    "mcp": 0
  },
  "url": "https://setupbay.com/loadouts/tauri-2-api-guard/",
  "api_url": "https://setupbay.com/api/loadouts/tauri-2-api-guard.json",
  "verification": {
    "level": "verified-install",
    "status": "verified",
    "label": "Verified install",
    "verified": true,
    "checked_at": "2026-10-29T12:33:24Z",
    "commit": "ba77c20fd68735fc14d7f033de79a1f14a5ff87f",
    "content_current": true,
    "agent_tests": "not-run",
    "counts": {
      "pass": 9,
      "fail": 0,
      "skip": 0,
      "not_applicable": 1
    },
    "meaning": "Level 1: automated checks on the files (parse, install paths, MCP config, safety scan, references, size, licence, starter build). No AI agent was run.",
    "checks": [
      {
        "id": "listing",
        "name": "Listing",
        "status": "pass",
        "summary": "Schema valid; 11 files declared, none missing or extra",
        "details": [
          "tested.status: untested (agent tests are separate from Level 1)"
        ]
      },
      {
        "id": "parse",
        "name": "Files parse",
        "status": "pass",
        "summary": "All 11 files parse; front matter valid",
        "details": []
      },
      {
        "id": "adapters",
        "name": "Adapters",
        "status": "pass",
        "summary": "CLAUDE.md and GEMINI.md import AGENTS.md and are up to date",
        "details": [
          "CLAUDE.md: matches the generator",
          "GEMINI.md: matches the generator"
        ]
      },
      {
        "id": "install-paths",
        "name": "Install paths",
        "status": "pass",
        "summary": "Correct paths for all 6 agents; layouts re-discovered",
        "details": [
          "Claude Code: 9 files, 1 skill in .claude/skills/",
          "Codex CLI: 8 files, 1 skill in .agents/skills/",
          "Cursor: 9 files, 1 skill in .agents/skills/, 1 rule",
          "Gemini CLI: 9 files, 1 skill in .agents/skills/",
          "Antigravity CLI: 8 files, 1 skill in .agents/skills/",
          "GitHub Copilot: 8 files, 1 skill in .agents/skills/"
        ]
      },
      {
        "id": "mcp",
        "name": "MCP config",
        "status": "n/a",
        "summary": "No MCP servers in this loadout",
        "details": []
      },
      {
        "id": "safety",
        "name": "Safety scan",
        "status": "pass",
        "summary": "Clean: no credentials, risky shell, hidden text or covert instructions",
        "details": [
          "Scanner intake-precheck/2: verdict clean; network no (listing says yes)"
        ]
      },
      {
        "id": "references",
        "name": "References",
        "status": "pass",
        "summary": "3 references between files resolve for every agent",
        "details": []
      },
      {
        "id": "size",
        "name": "Size limits",
        "status": "pass",
        "summary": "11 files, 22.6 KB total; largest skills/tauri-2-guard/scripts/tauri2_guard.py 8.4 KB",
        "details": [
          "Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule"
        ]
      },
      {
        "id": "licence",
        "name": "Licence",
        "status": "pass",
        "summary": "MIT, by SetupBay; text in the repository LICENSE",
        "details": []
      },
      {
        "id": "starter-build",
        "name": "Starter build",
        "status": "pass",
        "summary": "tauri2_guard.py passes a Tauri 2 notes app (front end, lib.rs, main.rs, tauri.conf.json, Cargo.toml) and flags every Tauri 1 line in the skill's four sample files: 25 errors and 3 warnings, including the snake_case invoke argument. With the pinned @tauri-apps packages, tsc passes the front end, a no",
        "details": [
          "Applied 18 loadout files at every agent's paths",
          "✓ scanner: the Tauri 2 app is clean: bash -c python3 .agents/skills/tauri-2-guard/scripts/tauri2_guard.py src src-tauri package.json; echo \"exit=$?\"",
          "✓ scanner: the Tauri 1 sample is flagged line by line: bash -c R=.claude/skills/tauri-2-guard/references/tauri1-sample; mkdir -p tauri1/src tauri1/src-tauri/src && cp $R/main.ts.txt tauri1/src/main.ts && cp $R/main.rs.txt tauri1/src-tauri/src/main.rs && cp $R/tauri.conf.json.txt tauri1/src-tauri/tauri.conf.json && cp $R/Cargo.toml.txt tauri1/src-tauri/Cargo.toml && python3 .claude/skills/tauri-2-guard/scripts/tauri2_guard.py tauri1; echo \"exit=$?\"",
          "✓ install @tauri-apps/api 2.12.4, the plugins, the CLI, Ajv and TypeScript (exact pins): npm ci --no-audit --no-fund",
          "✓ tsc type-checks the front end against the Tauri 2 packages: bash -c node_modules/.bin/tsc -p tsconfig.json; echo \"tsc=$?\"",
          "✓ node test with mockIPC: camelCase arguments reach the command: node --test test/notes.test.js",
          "✓ the CLI's config schema accepts the Tauri 2 config and rejects the Tauri 1 keys: bash -c node validate_conf.mjs src-tauri/tauri.conf.json; echo \"v2=$?\"; node validate_conf.mjs tauri1/src-tauri/tauri.conf.json; echo \"v1=$?\"",
          "✓ the published tauri 2.12.5 crate: the Tauri 1 Rust APIs are gone: bash -c curl -fsSL https://static.crates.io/crates/tauri/tauri-2.12.5.crate -o tauri.crate && python3 crate_probe.py tauri.crate",
          "Covers: The scanner's front-end, config, Rust and manifest rules against a real Tauri 1 app, and a clean Tauri 2 app",
          "Covers: The front end type-checks against @tauri-apps/api 2.12.4 and the plugin packages, and a mocked-IPC test pins the camelCase argument names",
          "Covers: tauri.conf.json against the schema shipped in @tauri-apps/cli 2.12.4",
          "Covers: Not covered: compiling the Rust side (that needs the platform WebView libraries); the crate source check confirms the Rust names instead"
        ]
      }
    ]
  },
  "install": {
    "claude-code": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "CLAUDE.md",
          "target": "CLAUDE.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/CLAUDE.md",
          "role": "adapter"
        },
        {
          "path": "skills/tauri-2-guard/SKILL.md",
          "target": ".claude/skills/tauri-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/tauri-2-guard/scripts/tauri2_guard.py",
          "target": ".claude/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/v1-to-v2.md",
          "target": ".claude/skills/tauri-2-guard/references/v1-to-v2.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/v1-to-v2.md",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "target": ".claude/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "target": ".claude/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "target": ".claude/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "target": ".claude/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/tauri-2-api-guard/claude-code.zip"
    },
    "codex": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/tauri-2-guard/SKILL.md",
          "target": ".agents/skills/tauri-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/tauri-2-guard/scripts/tauri2_guard.py",
          "target": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/v1-to-v2.md",
          "target": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/v1-to-v2.md",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/tauri-2-api-guard/codex.zip"
    },
    "cursor": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": ".cursor/rules/tauri-2-only.mdc",
          "target": ".cursor/rules/tauri-2-only.mdc",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/.cursor/rules/tauri-2-only.mdc",
          "role": "rules"
        },
        {
          "path": "skills/tauri-2-guard/SKILL.md",
          "target": ".agents/skills/tauri-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/tauri-2-guard/scripts/tauri2_guard.py",
          "target": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/v1-to-v2.md",
          "target": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/v1-to-v2.md",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/tauri-2-api-guard/cursor.zip"
    },
    "gemini-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "GEMINI.md",
          "target": "GEMINI.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/GEMINI.md",
          "role": "adapter"
        },
        {
          "path": "skills/tauri-2-guard/SKILL.md",
          "target": ".agents/skills/tauri-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/tauri-2-guard/scripts/tauri2_guard.py",
          "target": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/v1-to-v2.md",
          "target": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/v1-to-v2.md",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/tauri-2-api-guard/gemini-cli.zip"
    },
    "antigravity-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/tauri-2-guard/SKILL.md",
          "target": ".agents/skills/tauri-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/tauri-2-guard/scripts/tauri2_guard.py",
          "target": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/v1-to-v2.md",
          "target": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/v1-to-v2.md",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/tauri-2-api-guard/antigravity-cli.zip"
    },
    "copilot": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/tauri-2-guard/SKILL.md",
          "target": ".agents/skills/tauri-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/tauri-2-guard/scripts/tauri2_guard.py",
          "target": ".agents/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/scripts/tauri2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/v1-to-v2.md",
          "target": ".agents/skills/tauri-2-guard/references/v1-to-v2.md",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/v1-to-v2.md",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.ts.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/main.rs.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/tauri.conf.json.txt",
          "role": "reference"
        },
        {
          "path": "skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "target": ".agents/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "raw_url": "https://setupbay.com/raw/tauri-2-api-guard/1.0.0/skills/tauri-2-guard/references/tauri1-sample/Cargo.toml.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/tauri-2-api-guard/copilot.zip"
    }
  },
  "source_zip_url": "https://setupbay.com/download/tauri-2-api-guard/source.zip",
  "claude_code_plugin": {
    "name": "tauri-2-api-guard",
    "marketplace_url": "https://setupbay.com/marketplace.json",
    "install": [
      "/plugin marketplace add https://setupbay.com/marketplace.json",
      "/plugin install tauri-2-api-guard@setupbay"
    ],
    "zip_url": "https://setupbay.com/plugins/tauri-2-api-guard.zip",
    "sha256": "959909d642d16b2fbabfef1bb84365521812b1348e1c3ce40566dbd32c8a379b",
    "carries": [
      "skills"
    ],
    "note": "Plugins do not carry project rules (AGENTS.md, CLAUDE.md); install those from install.claude-code."
  }
}