By stack
Apps built the same way break the same way. Find the app’s stack (the .deb’s
dependencies, readelf -d on the binary and strings usually tell), then go
through its list: what to put in the manifest and wrapper, and what to test
before the PR. Each item links to the page that explains it.
For agents
Electron
- Runtime
org.freedesktop.Platform,base: org.electronjs.Electron2.BaseAppat the same version; start withzypak-wrapper <binary> --ozone-platform-hint=auto "$@"(Folo). unset ELECTRON_RUN_AS_NODEin the wrapper. A few apps exit on anyELECTRON_*variable (VS Code’s terminal exportsELECTRON_NO_ATTACH_CONSOLE); clear them all for those. Test withenv -u ELECTRON_RUN_AS_NODE -u ELECTRON_NO_ATTACH_CONSOLE flatpak run …from an IDE terminal, or the test fails for a reason users never hit.StartupWMClass: measured; it is the product name (desktop integration).- Media:
--own-name=org.mpris.MediaPlayer2.chromium.*andTMPDIRfor cover art, if the app plays media (media controls). - Saved passwords on Hyprland and Sway:
--password-store=gnome-libsecret(keyrings). - Data in a
~/.dotdir(os.homedir()): grant it with:createor--persist(permissions). - A setuid
chrome-sandboxin a.deb: clear the bit (chmod -R a-s).
Chromium-based browsers
- Same base and zypak as Electron, plus
CHROME_WRAPPER,ZYPAK_SPAWN_LATEST_ON_REEXEC=1andZYPAK_EXPOSE_WIDEVINE_PATH(zypak). - Check the profile directory name the browser really uses before pointing anything at it; branded builds differ from the main product.
StartupWMClassmeasured;CHROME_DESKTOPis ignored by branded builds.- User flags: read a
<name>-flags.conffrom the app’s config directory in the wrapper, the way native packages do.
Tauri (WebKitGTK)
- Runtime
org.gnome.Platform. Keep the.deb’susrtree whole when it hasusr/lib/<Name>/(Debian packages). - Rendering:
WEBKIT_DISABLE_DMABUF_RENDERER=1, unless the window istransparentor the app crashes on GNOME 51, then:-0(WebKitGTK). - Name the launcher symlink after the app id, and use it as
StartupWMClass(Flow). - Tray: the
ayatana-stackprebuilt andxdg-run/tray-icon:create, only if it really has a tray (tray). - Clipboard plugin:
--socket=x11(copy and paste). - Single instance: grant
<identifier>.SingleInstance(second instance). - Updater plugin: can’t be turned off from outside (updaters).
- Use the
identifierintauri.conf.jsonas the app id.
Wails v3
- Links WebKitGTK 6 and GTK 4, so
org.gnome.Platformeven if the.debsays webkit2gtk-4.1. - Aborts at start unless the app’s
Linux.ApplicationIDis the Flatpak id (WebKitGTK 6). - Tray uses the unique connection name; only the watcher grant.
GPUI (Zed-style) and other cosmic-text apps
- A shipped
fonts.conflisting every font directory, andFONTCONFIG_FILEpointing at it (fonts). --talk-name=org.a11y.Bus(accessibility).--device=drifor GPU rendering.
Slint
- Check the Slint version in the binary first: up to 1.16 needs both the
fonts.confandSLINT_DEFAULT_FONT=<directory>; 1.17 and later needs onlySLINT_FONT_PATH=<directory>(fonts). SLINT_BACKEND=winit-softwareas a documented override for GPUs where rendering fails (meatshell).
Flutter
- Usually a relocatable bundle in a tarball; the freedesktop runtime is enough.
Tarballs often record a real uid:
--no-same-owner(Vynody). - A compiled GApplication id different from the Flatpak id needs
--own-name=<compiled id>, or the app exits silently (second instance). - Tray:
--own-name=org.fluttertray.*; MPRIS uses an app-id prefix. - File associations: usually
%F; many Flutter apps don’t parsefile://URIs (opening files). - Fonts work through fontconfig; no
fonts.confneeded.
Qt
- Prefer an AppImage that carries its own Qt on the freedesktop runtime over a
.deblinked to the system Qt (choosing a format). - Bundled Qt with only the
xcbplugin:--socket=x11,--unset-env=QT_QPA_PLATFORM,QT_QPA_PLATFORM="${QT_QPA_PLATFORM:-xcb}"(Mark Shot). - A bundled Qt may lack the portal platform theme; its file dialogs then see only the granted folders.
.NET
- Self-contained .NET 5 and older look for OpenSSL 1.1 and abort on a runtime
with only OpenSSL 3 (“No usable version of libssl”): the
openssl-1.1-compatprebuilt, appended last toLD_LIBRARY_PATH. Checktfmin<App>.runtimeconfig.json; .NET 6 and later don’t need it. - Never delete a file listed in
<App>.deps.json, even an unused native library: the host checks every entry at start and aborts if one is missing. - Avalonia tray:
--own-name=org.kde.*(tray).
Java
- Use the JRE upstream bundles, if it does; otherwise pin a JRE (Zulu, Temurin) as a second extra-data download and point the launcher at it.
user.homeis the real$HOME, not redirected: settings in a~/.appor~/.config/<app>directory need--persistor a grant (permissions).- An embedded Chromium (JxBrowser, JCEF) brings the nested-sandbox problem (embedded Chromium).
- HiDPI:
-Dsun.java2d.uiScalein the app’s options file, or the app’s own setting.
Windows apps (Wine)
- Packaged on Cellar:
the vendor’s Windows installer is the managed extra-data download, and
cellar-clia second, fixed one outside the managed block. Cellar runs the installer, unmodified, into the user’s prefix on first launch. - Grant the folders the app works in (
xdg-musicfor a player), not home. - Redirect the prefix’s desktop folder into the sandbox, or installers drop shortcuts on the host’s desktop.