Skip to content

Installation & build

Spool can install the plugin for you — Settings → Decky Backup Plugin in the desktop app. This is implemented in tauri/src-tauri/src/decky_install.rs, Linux-only.

The plugin payload is embedded into the Spool binary at compile time via include_str!decky/dist/index.js, main.py, plugin.json, and package.json. (The whole embedded module is #[cfg(target_os = "linux")], and the dist/index.js it references requires the plugin to have been built with pnpm build before Spool is compiled — CI’s Linux build does this.) Embedding means the install works offline and is version-locked to the running Spool build.

install() stages the payload into a private dir (<app-data>/decky-staging/spool-backup), then runs a single privileged step via pkexec because Decky’s plugin dir and plugin_loader service are root-owned:

Terminal window
mkdir -p "$PLUGINS"
rm -rf "$PLUGINS/spool-backup"
cp -r "$SRC" "$PLUGINS/spool-backup"
chown -R root:root "$PLUGINS/spool-backup"
systemctl restart plugin_loader

If pkexec isn’t present it returns a clear error pointing at polkit or a manual Desktop-Mode copy. A dismissed auth dialog (exit 126) and a missing polkit agent in Game Mode (exit 127) get specific hints — the latter suggests running the install from Desktop Mode.

The decky_plugin_status command backs the Settings UI, reporting a DeckyPluginInfo:

FieldMeaning
supportedThis platform can install the plugin (Linux only)
installedA copy exists at ~/homebrew/plugins/spool-backup
installed_versionversion from the installed package.json, if readable
bundled_versionversion from the embedded package.json
decky_presentDecky Loader itself appears installed (~/homebrew exists)

The Quick Access panel (src/components/content.tsx) has a Settings section, persisted to the plugin’s settings.json via the get_settings / set_settings callables:

  • Notify on backup — show a toast when a backup finishes (default on).
  • Spool command — override the auto-detected spool / spool-launcher.sh path used to start the headless server (see Headless server).

decky/plugin.json declares the plugin to Decky Loader:

  • name: "Spool", author, api_version: 1.
  • flags: [] — no _root, so the backend runs as the deck user (see Overview).
  • a publish block (tags, description, image) for the Decky store.
Terminal window
cd decky
pnpm install
pnpm build # rollup -c → dist/index.js

package.json also has convenience deploy scripts (deploy, deploy:local) that rsync the built plugin to a Deck and restart plugin_loader. A distributed plugin is laid out as Decky Loader expects:

spool-backup/
dist/index.js [required]
main.py
plugin.json [required]
package.json [required]

.github/workflows/decky.yml builds and packages the plugin on pushes and PRs that touch decky/** or the Rust files the plugin depends on (plugin_server.rs, cli.rs, lib.rs, paths.rs, Cargo.toml). It runs under Node 22 with pnpm 11.5.0, installs with --frozen-lockfile, runs pnpm build, verifies dist/index.js exists, then zips the spool-backup/ layout above and uploads it as the spool-backup-plugin artifact.