Tauri Plugins¶
PyWry's native window mode runs on Tauri via the PyTauri Python bindings. Tauri ships a rich ecosystem of plugins — clipboard access, notifications, HTTP requests, filesystem operations, global shortcuts, and more. PyWry exposes a configuration-driven system for enabling any of the 19 bundled plugins.
How It Works¶
sequenceDiagram
participant App as PyWry (Python)
participant RT as runtime.py
participant Sub as __main__.py (subprocess)
participant Tauri as Tauri Engine
App->>RT: set_tauri_plugins(["dialog", "fs", "notification"])
RT->>Sub: env PYWRY_TAURI_PLUGINS="dialog,fs,notification"
Sub->>Sub: _load_plugins() — check flags, import modules
Sub->>Tauri: builder.build(plugins=[dialog.init(), fs.init(), notification.init()])
Tauri->>Tauri: Register plugins + grant capabilities
- You list the plugins you want in config (Python, TOML, or env var).
PyWry.__init__()forwards them to the runtime module.- The runtime passes
PYWRY_TAURI_PLUGINSas an environment variable to the subprocess. - The subprocess dynamically imports and initialises only the requested plugins.
- Tauri's capability system (via
capabilities/default.toml) pre-grants:defaultpermissions for all bundled plugins, so capabilities don't need separate configuration.
Quick Start¶
Python¶
from pywry import PyWry, PyWrySettings
settings = PyWrySettings(
tauri_plugins=["dialog", "fs", "notification", "clipboard_manager"],
)
app = PyWry(settings=settings)
app.show("<h1>Hello with plugins!</h1>")
pywry.toml¶
pyproject.toml¶
Environment Variable¶
# Comma-separated plugin names
export PYWRY_TAURI_PLUGINS="dialog,fs,notification,clipboard_manager"
Defaults
If you don't configure anything, dialog and fs are enabled — matching PyWry's original behaviour.
Available Plugins¶
All 19 plugins bundled in the pytauri_wheel binary are listed below. Each plugin exposes a JavaScript (window.__TAURI__.*) and/or Python API once enabled.
| Plugin name | JS API | Description |
|---|---|---|
autostart |
— | Launch at OS login |
clipboard_manager |
clipboardManager |
Read/write system clipboard |
deep_link |
deepLink |
Handle custom URL schemes |
dialog |
dialog |
Native open/save/message dialogs |
fs |
fs |
Filesystem read/write/watch |
global_shortcut |
globalShortcut |
System-wide keyboard shortcuts |
http |
http |
HTTP client (fetch replacement) |
notification |
notification |
OS notification centre |
opener |
opener |
Open URLs / files with default app |
os |
os |
Platform, arch, locale info |
persisted_scope |
— | Persist runtime FS scopes across restarts |
positioner |
— | Position windows (centre, tray, etc.) |
process |
process |
Restart / exit app |
shell |
shell |
Execute system commands |
single_instance |
— | Prevent duplicate app instances |
updater |
updater |
Auto-update from remote server |
upload |
upload |
Upload files with progress |
websocket |
websocket |
WebSocket client |
window_state |
— | Save/restore window size & position |
Feature flags
Each plugin has a compile-time feature flag (e.g. PLUGIN_NOTIFICATION). If the bundled pytauri_wheel was not compiled with a particular feature, enabling that plugin at runtime will raise a RuntimeError with a clear message. The default PyWry wheel includes all 19.
Using Plugin APIs in JavaScript¶
Once a plugin is enabled, its JavaScript API is available through the Tauri bridge. Use the JavaScript Bridge to interact:
from pywry import PyWry, PyWrySettings
app = PyWry(settings=PyWrySettings(
tauri_plugins=["dialog", "clipboard_manager"],
# clipboard has NO default permissions — must grant explicitly
extra_capabilities=[
"clipboard-manager:allow-write-text",
"clipboard-manager:allow-read-text",
],
))
html = """
<h2>Tauri Plugin Demo</h2>
<button onclick="askQuestion()">Ask a question (dialog)</button>
<button onclick="copyToClipboard()">Copy text to clipboard</button>
<button onclick="pickFile()">Pick a file</button>
<p id="result"></p>
<script>
const result = document.getElementById("result");
async function askQuestion() {
const { ask } = window.__TAURI__.dialog;
const yes = await ask("Do you want to continue?", {
title: "PyWry",
kind: "warning",
});
result.textContent = yes ? "User chose Yes" : "User chose No";
}
async function copyToClipboard() {
const { writeText, readText } = window.__TAURI__.clipboardManager;
await writeText("Hello from PyWry!");
const contents = await readText();
result.textContent = "Clipboard now contains: " + contents;
}
async function pickFile() {
const { open } = window.__TAURI__.dialog;
const path = await open({ multiple: false, directory: false });
if (path) {
result.textContent = "Selected: " + path;
} else {
result.textContent = "No file selected.";
}
}
</script>
"""
app.show(html)
Each button triggers a real OS interaction — a native dialog or a clipboard write — with the result displayed in the page.
Plugin documentation
For the full JavaScript API of each plugin, see the Tauri Plugins documentation.
Notification plugin on Windows
The notification plugin only shows OS notifications for installed apps. In development mode on Windows it will silently return null. Use dialog for visible feedback during development.
Extra Capabilities¶
Tauri's capability system controls which APIs a window is allowed to call. By default, PyWry grants :default permissions for every bundled plugin. This is sufficient for most use cases.
If you need fine-grained permissions beyond the defaults (e.g. shell:allow-execute, fs:allow-read-file), use the extra_capabilities setting:
settings = PyWrySettings(
tauri_plugins=["shell", "fs"],
extra_capabilities=["shell:allow-execute", "fs:allow-read-file"],
)
Or via TOML:
Or the environment variable:
Capability names use hyphens
Tauri permission strings use hyphens, not underscores: clipboard-manager:default, not clipboard_manager:default. Plugin config names use underscores (Python identifiers), but capability permission strings use the Tauri convention.
Capabilities That Don't Exist¶
Two plugins — persisted_scope and single_instance — do not register Tauri capability manifests. They are Rust-only plugins without permission-gated functionality. Including persisted-scope:default or single-instance:default in a capabilities file will cause a Tauri panic at startup. PyWry's capabilities/default.toml intentionally omits them.
You can still enable these plugins (they'll be initialised at the Rust level), but do not add capability strings for them.
Architecture Details¶
Plugin loading flow¶
config.py—PyWrySettings.tauri_pluginsvalidates names againstAVAILABLE_TAURI_PLUGINS.app.py—PyWry.__init__()callsruntime.set_tauri_plugins(settings.tauri_plugins)andruntime.set_extra_capabilities(settings.extra_capabilities).runtime.py— Stores both lists and passes them asPYWRY_TAURI_PLUGINSandPYWRY_EXTRA_CAPABILITIESenvironment variables when starting the subprocess.__main__.py— The subprocess:- Reads
PYWRY_TAURI_PLUGINS, calls_load_plugins()which validates names, checksPLUGIN_*feature flags, dynamically imports modules, and calls.init(). - Reads
PYWRY_EXTRA_CAPABILITIES. If non-empty, copies the package directory to a temp staging dir and writes anextra.tomlcapability file with the requested permissions. This is necessary becausecontext_factory()reads capabilities from static TOML files, and installed packages may be read-only.
- Reads
- Tauri build —
context_factory(ctx_dir)reads all.tomlfiles undercapabilities/(including the stagedextra.tomlif present), thenbuilder_factory().build(plugins=plugins)registers all initialised plugins with the Tauri engine.
Capability files¶
Base permissions live in pywry/capabilities/default.toml. It pre-grants :default for all 17 plugins that have valid Tauri capability manifests. Permissions for plugins that aren't initialised are simply unused — they don't cause errors or security issues.
When extra_capabilities is configured, an additional extra.toml is generated at runtime in a temporary directory with just the extra permissions. The temp directory is cleaned up when the subprocess exits.
Troubleshooting¶
"Unknown Tauri plugin 'xyz'"¶
The plugin name isn't in the registry. Check spelling — use underscores (e.g. clipboard_manager, not clipboard-manager).
"PLUGIN_XYZ feature was not compiled"¶
The pytauri_wheel binary was compiled without that plugin's feature flag. This shouldn't happen with the default PyWry distribution, but custom builds may exclude plugins.
App crashes on startup after adding capabilities¶
If you get a PanicException mentioning UnknownManifest, you've added a capability string for a plugin that doesn't register one (persisted_scope or single_instance). Remove the offending string from extra_capabilities.
Next Steps¶
- Configuration Guide — Full settings reference
- JavaScript Bridge — Calling Tauri APIs from JS
- Events — Python↔JS event system
- PyTauri Plugin Docs — Upstream plugin tutorial