chore: add AGENTS.md (#3680)

* chore: add AGENTS.md

* Apply batched suggestions from code review [skip ci]

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>

* simplify

---------

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
This commit is contained in:
Lucas Fernandes NogueiraandAmr Bashir authored and GitHub committed 2026-10-11 22:07:25 -03:00
1 parent dff0dd4b23
commit 8efe845612
2 files changed
+150 -1

No files matched your search

+150
View File
@@ -0,0 +1,150 @@
# AGENTS.md
Instructions for coding agents working in this repository. The contributor guide is [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md).
## Overview
This repo holds the official [Tauri](https://tauri.app) plugins. Each directory in `plugins/` is one plugin, published as:
- the Rust crate `tauri-plugin-<name>` on crates.io, and
- the npm package `@tauri-apps/plugin-<name>`, its JavaScript bindings for the webview, at the **same version** as the crate.
Some plugins are Rust-only and have no npm package.
Each Tauri major version has a branch here (`v1`, `v2`, …) with the plugins compatible with it. PRs go to the default branch. Don't port changes between them unless asked.
## Layout
```text
plugins/<name>/
build.rs lists the plugin's commands and generates its permissions
src/lib.rs init()/Builder, plus a `<Name>Ext` trait on AppHandle & co.
src/commands.rs #[tauri::command] handlers
src/desktop.rs, mobile.rs platform implementations; mobile.rs calls into Kotlin/Swift
src/error.rs thiserror Error, serialized to JS as its message string
src/models.rs serde types shared with JS and native code
permissions/*.toml hand-written permission sets, including default.toml
permissions/autogenerated/ generated
permissions/schemas/ generated
guest-js/index.ts JS API: thin wrappers around invoke('plugin:<name>|<command>')
api-iife.js generated: the window.__TAURI__.<name> global (withGlobalTauri)
android/, ios/ native plugin code (Kotlin library, Swift package)
examples/ small per-plugin example apps
examples/api/ Svelte app that registers every plugin; the manual test bed
packages/api-e2e/ WebdriverIO e2e suite driven against examples/api
shared/rollup.config.js the rollup config every plugin builds with (createConfig)
shared/template/ skeleton for a new plugin ({{ placeholders }}, not compiled)
.changes/ covector change files
.scripts/ci/ scripts CI runs; they work locally too
```
## Build, lint, test
Run everything from the repo root.
```sh
pnpm install
pnpm build # every plugin: dist-js/, api-iife.js, src/init-iife.js
pnpm --filter @tauri-apps/plugin-<name> build # one plugin
```
Run `pnpm build` before `pnpm lint`, `pnpm ts:check`, the example app or the e2e suite, because they read the plugins from `dist-js/`.
Rust checks run per crate. CI runs them for every plugin a change affects, on Windows, Linux and macOS, and builds for iOS and Android:
```sh
cargo clippy -p tauri-plugin-<name> --all-targets -- -D warnings
cargo clippy -p tauri-plugin-<name> --all-targets --all-features -- -D warnings
cargo test -p tauri-plugin-<name> --all-targets --all-features
cargo test -p tauri-plugin-<name> --doc
```
Some plugins have mutually exclusive features (check `[features]` in their `Cargo.toml`) and don't build with `--all-features`. Drop that flag for them.
Formatting and JS checks. CI fails if any of them would change a file or report an error:
```sh
cargo fmt --all
taplo fmt # TOML
pnpm format # prettier: TS, JS, JSON, Markdown, YAML
pnpm lint # eslint with type-aware rules
pnpm ts:check
```
To try a change by hand, run `pnpm example:api:dev`. It starts `examples/api` against the local plugins.
The e2e suite runs with `pnpm test:api-e2e` (`test:api-e2e:android` and `test:api-e2e:ios` for mobile). Its prerequisites, environment variables and how to add a spec are in [packages/api-e2e/README.md](packages/api-e2e/README.md).
## Generated files
Don't edit these by hand. Regenerate them and commit the result together with the change that caused it.
| Files | Regenerated by |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `plugins/*/api-iife.js`, `plugins/*/src/init-iife.js` | `pnpm build`. CI fails if the build leaves a diff. |
| `plugins/*/permissions/autogenerated/**`, `plugins/*/permissions/schemas/schema.json` | the plugin's `build.rs`, on any `cargo check` or build of it |
| `CHANGELOG.md` files, package versions, the `version` of path dependencies | covector, at release time. Don't bump versions in a PR. |
Also leave `dist-js/` alone, along with the git-ignored `.tauri/` directories under `plugins/*/` and `plugins/*/android/`. The build copies Tauri's mobile API into those.
## Adding or changing a command
These places must agree:
1. `src/commands.rs`: write the `#[tauri::command]`, returning `crate::Result<T>`.
2. `src/lib.rs`: register it in `tauri::generate_handler![…]` on every platform where the JS API exposes it. If it can't work on a platform, register it anyway and return an error there. An unregistered command reaches JS as an opaque "command not found".
3. `build.rs`: add it to `COMMANDS`, which generates its `allow-…` and `deny-…` permissions. Without them, apps can't grant it. When you remove a command, also delete its file from `permissions/autogenerated/commands/`, because the build doesn't remove stale ones.
4. `permissions/default.toml`: add it only if every app should get it without opting in. Defaults are deliberately narrow.
5. `guest-js/index.ts`: call `invoke('plugin:<name>|<command_name>', { … })`. JS passes the command's snake_case parameters as camelCase keys (`file_path` becomes `filePath`), and serde structs use `#[serde(rename_all = "camelCase")]`. Give exported functions TSDoc with an `@example`, and set `@since` to the version the change will ship in.
6. Mobile: `mobile.rs` forwards with `run_mobile_plugin("<methodName>", args)` to the Kotlin `@Command` or Swift `@objc` method of that name.
7. Example app: if it should use the command, grant it in `examples/api/src-tauri/capabilities/` and cover it in `packages/api-e2e`.
8. Run `cargo check -p tauri-plugin-<name>` and `pnpm build`, then commit the regenerated files.
## Change files
A change to a published crate or npm package needs a [covector](https://github.com/jbolda/covector) change file in `.changes/`. Changes that only touch CI, tests, examples or docs don't. Here is a real one, `.changes/fix-fs-read-lines-error.md`:
```md
---
fs: patch
fs-js: patch
---
Fixed `readTextFileLines` yielding empty lines forever when reading fails (e.g. on a directory). The read error is now reported: the iterator rejects and the file is closed.
```
- The keys are package names from `.changes/config.json`. `<plugin>` is the crate and `<plugin>-js` is the npm package.
- **List both with the same bump, even when only the Rust side or only the JS side changed.** Their versions are kept identical. Rust-only plugins have no `-js` entry.
- The bump is `patch`, `minor` or `major`. Plugins that depend on the changed one (`dialog` on `fs`, for example) are bumped automatically, so don't list them.
- The body becomes the changelog entry. Write it for the plugin's users: what changed, and what they must update.
- Check the file with `node .scripts/ci/check-change-files.js .changes/<file>.md`.
## Rules and gotchas
- **License header:** new `.rs`, `.ts`, `.js`, `.kt`, `.swift` and `.yml` files must start with these lines (with `#` comments in YAML). Keep the year range exactly as written:
```text
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
```
Check new files with `node .scripts/ci/check-license-header.js <files>`. Without arguments, it also reports the git-ignored `.tauri/` copies, which you can ignore.
- **MSRV:** the tests run on exactly on MSRV configured in Cargo.toml (clippy runs on stable). Don't use newer std APIs, and check with `cargo +<version> check -p tauri-plugin-<name>` where <version> is the current MSRV for the plugin.
- **tauri features:** the workspace depends on `tauri` with `default-features = false`. A plugin that needs a tauri feature, such as `wry` on iOS, enables it in its own `Cargo.toml`. Build plugins with `-p`: a workspace-wide build unifies features with `examples/api`, which hides a missing one.
- **Platform cfgs:** use the `desktop` and `mobile` cfgs that `tauri-plugin`'s build script sets, and `target_os` for single platforms. Desktop-only dependencies go in the long `cfg(any(target_os = "macos", windows, target_os = "linux", …))` target table that the existing manifests use.
- **docs.rs:** a plugin with mobile code must detect docs.rs in its `build.rs` with `std::env::var_os("DOCS_RS")`, as `plugins/dialog/build.rs` does. `cfg!(docsrs)` is never set for build scripts, and `shared/template/build.rs` still has that old form.
- **Dependencies:** shared ones come from `[workspace.dependencies]` (`serde = { workspace = true }`). A plugin that depends on another uses a path plus a version (`tauri-plugin-fs = { path = "../fs", version = "2.6.0" }`).
- **Updates:** Renovate handles routine dependency updates, so don't run a blanket `cargo update` or `pnpm update`. Unrelated lockfile changes make CI build and test every plugin.
- **New npm versions:** pnpm won't install versions published less than 3 days ago (`minimumReleaseAge`). Ask before adding an exception to `pnpm-workspace.yaml`.
- **Platform support:** when a plugin gains or loses a platform, update `[package.metadata.platforms.support]` in its `Cargo.toml`, the table in its README and the table in the root README.
- **Mirrors:** plugins listed in `plugins/mirrors.txt` are pushed to read-only `tauri-apps/tauri-plugin-<name>` repositories. Make changes here, not in the mirrors.
- **Security:** report vulnerabilities privately, as [SECURITY.md](SECURITY.md) describes. Never put them in a public issue or PR.
## Commits and pull requests
- Use conventional-commit titles scoped to the plugin: `fix(fs): …`, `feat(notification): …`, `chore(deps): …`, `ci: …`, `docs(log): …`. When the change fixes an issue, end the title with `(fix #1234)`.
- Commits must be signed, so don't bypass signing. PRs are squash-merged, so intermediate commits are fine.
- A new feature needs a convincing reason, ideally an issue the maintainers accepted. Link it in the PR.
- [AI tool policy](.github/CONTRIBUTING.md#ai-tool-policy): the person submitting is responsible for everything an agent wrote, and replies to review comments must not be AI-written (translations excepted). PRs that ignore this are closed as `ai-slop`. Before handing work over, run the checks above and say plainly what you tested and on which platforms. Don't draft or post replies to review comments.
-1
View File
@@ -3,7 +3,6 @@
// SPDX-License-Identifier: MIT
// @ts-nocheck
// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
/** user-defined commands **/