Research: how should DropTerm package, distribute, and release for COSMIC in late 2026?

Date: 2026-10-10 Question: How do users actually install third-party COSMIC apps, what does each distribution channel (Flathub / the COSMIC Flatpak repo / deb / AUR / nix) demand from a Rust workspace with a git-pinned libcosmic, can the out-of-process panel applet ship in a Flatpak, and what does a healthy v1.0 release process look like for a single maintainer?

TL;DR

The COSMIC “app market” is Flathub plus the deb world, with one big carve-out that decides everything: apps belong on Flathub, panel applets belong in System76’s pop-os/cosmic-flatpak repository, and DropTerm’s own drop-down surface makes Flathub impossible for the main binary anyway. The official routing is written in libcosmic’s own README — “Applications may be submitted to Flathub. Desktop-specific components—such as COSMIC applets—are not permitted on Flathub so make sure to submit them to the COSMIC Flatpak repository instead” (libcosmic README) — and that repository (pop-os/cosmic-flatpak, 56 applets as of 2026-10-10) is offered inside the COSMIC Store as the recommended “COSMIC Flatpak” source. Out-of-process applets (like DropTerm’s cosmic-ext-dropterm-applet) work as Flatpaks by design: cosmic-panel discovers applet desktop files through XDG data dirs, detects that a desktop file came from a Flatpak export, and spawns it via Flatpak with the panel’s Wayland socket inherited. But DropTerm’s terminal window is a zwlr_layer_shell_v1 surface, and cosmic-comp binds layer-shell only for clients without a Wayland security context — so a sandboxed main binary gets no layer shell and cannot show the drop-down at all. That is not speculation; it is exactly why the cosmic-ext-applet-app-switcher applet was measured, found broken, and removed from the store (cosmic-flatpak #259). The recommended path for v1.0 is therefore: native-first — GitHub tag + release tarball (the System76 just vendor → vendor.tar convention), a cargo-deb deb for Pop!_OS users, an AUR package (which already has a direct precedent in cosmic-ext-quake-terminal), and the applet submitted to pop-os/cosmic-flatpak so store-first users can install it; Flathub for the main app only if a non-layer-shell fallback mode ever exists, and nixpkgs as a cheap follow-on (it already packages 11+ cosmic-ext-* apps via a documented hook).

Findings

1. The COSMIC “app market”: cosmic-store browses Flathub AND installs debs

The store on Pop!_OS 24.04 is pop-os/cosmic-store (cloned 2026-10-10, README.md: “WIP COSMIC Store”). Its backend layer is explicitly multi-kind — src/backend/mod.rs defines BackendName::{FlatpakUser, FlatpakSystem, Packagekit, Pkgar, RpmOstree} — so the same UI installs Flatpaks and distro packages (PackageKit covers apt/deb; pkgar and rpm-ostree cover System76’s immutable plans). Two details verified in source:

System76’s support docs confirm the user-facing behavior: on current Pop!_OS, “Flathub plus the Ubuntu repositories are the default software sources listed in the COSMIC Store”, both Flatpak and .deb versions of an app can be offered, and “apps not listed can be installed by downloading a 64-bit .deb file and double-clicking it, which opens the Store with an install option”; the Repoman tool manages additional Flatpak repos (system76.com/support/managing-apps). (UNVERIFIED: whether Pop!_OS 24.04 COSMIC is branded alpha/beta/stable at this exact date — the release-notes page moved and returned 404; nothing in this research depends on it.)

So “the app market” for DropTerm is: Flathub (apps) + COSMIC Flatpak repo (applets) + apt/deb + whatever the user adds by hand — and cosmic-store handles all of the first three natively.

2. The Flathub route: process, manifests, and the applet question

2.1 Submission process (active model, verified October 2026)

The documented, live process for new apps is still the GitHub model: follow the requirements, build locally with org.flatpak.Builder, lint with flatpak-builder-lint, then open a PR titled “Add " **against the `new-pr` branch of `flathub/flathub`**; after review a new per-app repo is created under the flathub org and updates from then on are plain commits to it that trigger server-side builds ([docs.flathub.org — submission](https://docs.flathub.org/docs/for-app-authors/submission)). Direct evidence the model is alive today: new per-app repos were still being created in the flathub org on 2026-10-07/08 (e.g. `io.github.word_sys.word-sys-pdf-editor`, `net.blip.Blip`), and their histories show bot PRs merging (`gh api orgs/flathub/repos?sort=created`, checked 2026-10-10). A **direct-upload** model also exists (upload prebuilt repos via the Flathub web portal); it is not in the docs' submission flow, but the MetaInfo guidelines acknowledge it: "Direct uploads (no Flathub GitHub repo) must add `flathub::manifest` location in a `` tag" ([metainfo-guidelines](https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines)). For DropTerm the GitHub model is the right default: it keeps the manifest in a reviewable repo and matches every COSMIC app already there.

Requirements that bite DropTerm specifically (docs.flathub.org — requirements):

2.2 A real COSMIC app manifest on Flathub

com.system76.CosmicTerm does not exist on Flathub (404 at https://flathub.org/apps/com.system76.CosmicTerm; System76 ships COSMIC apps as Pop debs only — finding 3.2). The COSMIC apps that ARE on Flathub (from Flathub’s own AppStream index, dl.flathub.org/repo/appstream/x86_64/appstream.xml.gz, fetched 2026-10-10) include dev.edfloreshz.CosmicTweaks, dev.edfloreshz.Tasks, io.github.cosmic_utils.Examine, com.vkhitrin.cosmicding, io.github.cosmic_utils.camera, io.github.pixeldoted.cosmic-ext-color-picker. The best-studied example, com.vkhitrin.cosmicding (Rust + libcosmic with git deps), manifest at flathub/com.vkhitrin.cosmicding:

runtime: org.freedesktop.Platform
runtime-version: "24.08"
base: com.system76.Cosmic.BaseApp        # System76's shared COSMIC base (branch: stable)
base-version: stable
sdk: org.freedesktop.Sdk
sdk-extensions: [org.freedesktop.Sdk.Extension.rust-stable]
finish-args:
  - --share=ipc
  - --share=network
  - --socket=fallback-x11
  - --socket=wayland
  - --device=dri
  - --talk-name=com.system76.CosmicSettingsDaemon   # COSMIC theming daemon
  - --filesystem=xdg-config/cosmic:rw               # libcosmic config (watch_config)
sources:
  - cargo-sources.json                  # flatpak-cargo output: every crate + git dep
  - type: git {url: https://github.com/vkhitrin/cosmicding.git, tag: v2025.11.1}

The finish-args pattern is stable across COSMIC Flatpaks — Examine (flathub/io.github.cosmic_utils.Examine, runtime 25.08) uses --socket=wayland --socket=fallback-x11 --device=all --talk-name=com.system76.CosmicSettingsDaemon --filesystem=xdg-config/cosmic:ro. So a Wayland COSMIC app needs: wayland socket (+fallback-x11 for X11 users), dri device (GPU rendering; --device=all is the blunter variant), settings-daemon talk-name (theme hot-reload), and xdg-config/cosmic access. A terminal additionally needs the host-shell story from §8.1 and — if SSH from inside the sandbox should work — --socket=ssh-agent (a standard Flatpak socket; flatpak sandbox permissions documents the socket set). Desktop file, icon, and metainfo are installed to /app/share/{applications,icons/hicolor,metainfo}/ — visible to the host because Flatpak exports them ($FLATPAK_ID.desktop etc., rewritten Exec per flatpak conventions).

2.3 Building a git-pinned libcosmic workspace with flatpak-builder

There is no network in the Flatpak build sandbox, so Cargo.lock’s crates.io AND git dependencies must be pre-materialized as manifest sources. The standard tool is flatpak-builder-tools/cargo (flatpak-cargo-generator): python3 flatpak-cargo-generator.py Cargo.lock -o cargo-sources.json produces a sources file that vendoring builds consume via CARGO_HOME=/run/build/<module>/cargo + cargo --offline build (flatpak-builder-tools/cargo README). Git deps come out as pinned {"type":"git", "url": …, "commit": <rev>, "dest": "flatpak-cargo/git/<name>-<shortsha>"} entries — verified in the wild in dev.cappsy.CosmicExtAppletDict’s cargo-sources.json, which materializes pop-os/libcosmic, pop-os/cosmic-protocols, pop-os/cosmic-panel-config, … exactly the way DropTerm’s pinned 08a09e3 rev would (cosmic-flatpak/app/dev.cappsy.CosmicExtAppletDict). DropTerm’s two-crate workspace needs both crates’ graphs in one cargo-sources.json (the generator walks the whole lockfile, so one file covers the applet member too).

2.4 CRITICAL: can an out-of-process COSMIC panel applet ship in a Flatpak? YES — the platform supports it explicitly; cosmic-comp is the part that doesn’t

The applet is an ordinary executable discovered by desktop-file stem and spawned by the panel as a separate process (established in docs/research/v3-panel-applet.md, findings 1-2). Every step of that works for Flatpaks:

The counter-case is cosmic-comp, and it hits the MAIN app, not the applet. cosmic-comp binds sensitive protocols only for non-sandboxed clients: WlrLayerShellState::new_with_filter::<State, _>(dh, client_not_sandboxed) at cosmic-comp/src/state.rs:738 (master 4d14528, 2026-10-08), where not_sandboxed() treats any client carrying a Wayland security context as sandboxed, with one carve-out — engine com.system76.CosmicPanel is trusted (state.rs:165-174), which is precisely how panel-attached Flatpak applets stay first-class. A Flatpak’s own security context does not get that treatment. DropTerm’s drop-down is built on libcosmic’s layer-surface API (src/surface.rs:11-16 imports layer_surface::{Anchor, KeyboardInteractivity, Layer as WlrLayer}; wlr_layer() maps Overlay/Top) — so a Flatpaked main binary would simply never receive zwlr_layer_shell_v1 in its wl_registry and could not create the drop-down. This is the exact, measured failure documented when the app-switcher applet was withdrawn: flatpak ≥1.15 “always attaches” a security context, zcosmic_toplevel_info_v1/zwlr_layer_shell_v1 disappear from the sandbox’s registry (58 → 36 globals on cosmic-comp 7ee78d9, Flatpak 1.16.6), and --filesystem=/usr/share/applications:ro-style entries are silently ignored (“/usr is reserved by Flatpak”) (cosmic-flatpak #259). The author’s only workaround was opting out of the Wayland sandbox entirely (--nosocket=wayland + host socket), “which defeats the point of shipping it as a Flatpak”.

Conclusion: applet → Flatpak OK (via cosmic-flatpak repo); main terminal → Flatpak NOT viable on COSMIC today. (UNVERIFIED: whether cosmic-comp will grow an intended path for sandboxed layer-shell clients — the #259 author reports asking; nothing has landed in master as of 4d14528.)

2026-11-08, first-party confirmation: the terminal experiment (packaging/flatpak/EXPERIMENT-layer-shell.md, walked on the validation VM against the pinned v0.3.1 archive) reproduced the #259 failure on DropTerm’s own binary — sandboxed client sees 33 of the native session’s 56 globals, xdg_wm_base present, zwlr_layer_shell_v1 absent, the app silently never surfaces while reporting --is-visible true. The silent hang is an app-side robustness gap (no error without RUST_LOG=debug; any compositor without wlr-layer-shell hits it) — logged as its own follow-up, independent of packaging.

2.5 The cosmic-flatpak submission flow (the applet’s home)

pop-os/cosmic-flatpak README: “This repository hosts applets and other flatpaks for COSMIC that are not suitable for upload to Flathub. For COSMIC apps, please first try to submit to Flathub.” Users add it with flatpak remote-add --if-not-exists --user cosmic https://apt.pop-os.org/cosmic/cosmic.flatpakrepo — or via the Store’s recommended-sources page (finding 1). Submission mechanics, verified from the repo (cloned 2026-10-10):

3. Native packaging and the System76 release convention

3.1 cargo-deb

cargo-deb produces a binary .deb from Cargo metadata: cargo deb → target/debian/<name>_<version>-1_<arch>.deb. Zero config gets a working package from name/version/license/description/repository in Cargo.toml; [package.metadata.deb] adds maintainer, depends, revision, section, and — the important one — assets = [[source, dest, mode]…] with globs, plus [package.metadata.deb.variants.<name>] for multiple debs from one crate and automatic $auto deps. Binaries are stripped by default; systemd units are first-class ([package.metadata.deb.systemd-units]) (cargo-deb README). For DropTerm the deb shape is simple precisely because the applet is a binary, not a .so — out-of-process applets need nothing in a special lib path. One deb with:

usr/bin/cosmic-ext-dropterm            ← cargo-deb auto-detects workspace bins, or list as assets
usr/bin/cosmic-ext-dropterm-applet
usr/share/applications/io.github.l1br3_io.CosmicExtDropterm.desktop
usr/share/applications/io.github.l1br3_io.CosmicExtDropterm.Applet.desktop
usr/share/metainfo/io.github.l1br3_io.CosmicExtDropterm.metainfo.xml
usr/share/icons/hicolor/…              ← res/icons content

That matches exactly where cosmic-panel/cosmic-settings look (XDG data dirs + PATH — finding 2.4) and what the justfile install convention does upstream. Note cargo-deb packages ONE package per invocation — for a workspace, either run it on the root package with explicit assets for the applet bin (simplest, one deb), or build two debs via variants/metadata in each member. (The coordinator’s correction is baked in here: there is no .so/libloading model anywhere in current cosmic-panel — applets are processes since the spawn_clients redesign.)

3.2 What a “COSMIC release” looks like at pop-os (read from cosmic-term)

Read from pop-os/cosmic-term @ master (cloned 2026-10-10), cross-checked with cosmic-settings and cosmic-applets:

For a third-party single maintainer, the transferable parts are: the vendor/build-vendored/install justfile trio, epoch-style lockstep version bumps (or plain semver), annotated tags, and desktop-file validation in CI (desktop-file-validate on every .desktop — validate-desktop-files.yml).

3.3 The third-party ecosystem and how community apps actually distribute

4. AUR: conventions, git-dep handling, and the dropterm-shaped gap

Searches via the AUR RPC API (2026-10-10):

The two archetypes a DropTerm package should copy:

cosmic-ext-quake-terminal (release, upstream tarball):

source=("${pkgname}-${pkgver}.tar.gz::${url}/archive/${pkgver}.tar.gz")
sha256sums=('…')
prepare() { cd "${pkgname}-${pkgver}"; cargo fetch --locked; }
build()    { just build-release --frozen; }          # with lld link args
package()  { just rootdir="${pkgdir}" install; }

(AUR cosmic-ext-quake-terminal)

cosmic-ext-applet-logomenu (release, applet):

depends=('cosmic-applets'); makedepends=('cargo' 'just' 'git')
prepare() { cargo fetch --target "$(rustc -vV | sed -n 's/host: //p')"; }
build()   { just build-release --frozen; }
package() { just rootdir="$pkgdir" install; }

(AUR cosmic-ext-applet-logomenu)

The checksum policy: only the top-level release tarball is hashed (sha256 of the GitHub archive); the libcosmic git dependency is pinned by Cargo.lock (committed upstream — AUR’s cargo guidelines require a locked, committed Cargo.lock) and fetched at build time via cargo fetch --locked in prepare(); the build then runs --frozen. This works because makepkg builds are not network-isolated by default. -git packages instead use git+<url>#branch=… sources and pkgver() from git describe. Naming: package name = upstream repo name (cosmic-ext-dropterm), optional -git twin. DropTerm’s justfile already speaks rootdir= so a PKGBUILD is nearly the logomenu one verbatim — plus the applet workspace member must be built too (cargo build -p cosmic-ext-dropterm -p cosmic-ext-dropterm-applet --frozen or a just build-release --workspace).

5. Nix: flake now, nixpkgs later — git libcosmic deps are a solved problem both ways

nixpkgs has first-class COSMIC packaging: a dedicated manual chapter documents libcosmicAppHook, which “wraps every executable, sets the search paths libcosmic reads at runtime, and links the libraries that libcosmic and Iced load with dlopen”, injects cosmic-settings theme fallbacks and cosmic-icons into XDG_DATA_DIRS, and handles Vergen env quirks (nixpkgs cosmic.section.md).

So: a DropTerm flake is buildRustPackage + cargoLock.lockFile + outputHashes.libcosmic (or allowBuiltinFetchGit) + libcosmicAppHook-equivalent wrapping (the hook itself is available on NixOS from nixpkgs even in a flake via pkgs.libcosmicAppHook). Getting **into nixpkgs** later means switching to fetchFromGitHub + cargoHash against a tag, exactly like sysinfo — a small, well-trodden PR. Worth noting: pop-os repos publish rolling flakes to FlakeHub (flakehub-publish-rolling.yml` in cosmic-term) as their nix story; that is a third option with zero review overhead.

6. Release automation: cargo-dist is healthy, but wrong-shaped for COSMIC; pop-os uses none

7. Go-to-market hygiene for v1.0 (checklist, all from primary specs)

8. Terminal-specific gotchas

8.1 PTY/shell spawn inside the Flatpak sandbox

Yes — left alone, the shell users get is the runtime’s shell: a Flatpak app spawning $SHELL/bash executes the Freedesktop runtime’s /usr/bin/bash against the sandbox filesystem, where the host’s home is invisible (except granted --filesystem= subsets) and host binaries dotfiles and tools don’t exist. The platform-blessed fix, used by the reference terminal Flatpak (app.devsuite.Ptyxis): grant --talk-name=org.freedesktop.Flatpak and run host processes via flatpak-spawn --host; Ptyxis goes further with a dedicated ptyxis-agent “typically running on the host system (even when the Ptyxis UI is a Flatpak)”, falling back to an in-sandbox agent when the host spawn fails — “When Ptyxis UI is a Flatpak, it uses permissions like org.freedesktop.Flatpak (for flatpak-spawn --host) to access the host for its agent” (Ptyxis README); its manifest adds --filesystem=host + --talk-name=org.freedesktop.Flatpak on top of the usual wayland/dri/ipc sockets (flathub/app.devsuite.Ptyxis manifest). For DropTerm this is the killer detail on top of §2.4: even if layer-shell were solved, every PTY DropTerm spawns would be runtime-context shells unless it grew a Ptyxis-style host-agent — a large behavioral difference from the native build. (All moot for the main app as long as cosmic-comp gates layer-shell.)

8.2 D-Bus across the sandbox boundary (host applet ↔ flatpaked app, and the reverse)

Flatpak filters the session bus: by default an app may own exactly $FLATPAK_ID, its subnames, and org.mpris.MediaPlayer2.$FLATPAK_ID, and may talk to those plus org.freedesktop.DBus and org.freedesktop.portal.*; anything more needs --own-name/--talk-name, and --socket=session-bus (unfiltered) “is a security risk” (flatpak sandbox permissions). Consequences for DropTerm’s two D-Bus relationships:

8.3 Notifications inside Flatpak

DropTerm’s bell uses notify-rust → org.freedesktop.Notifications directly (COSMIC has no portal consumer path wired in DropTerm today). In a Flatpak that name is not talkable by default; two options: --talk-name=org.freedesktop.Notifications (the permissive-looking but common choice) or switch to the portal interface org.freedesktop.portal.Notification (AddNotification), which is in the default-allowed portal namespace — its D-Bus definition ships in flatpak/xdg-desktop-portal data/org.freedesktop.portal.Notification.xml. The portal is fire-and-forget (no actions/timeout control like the desktop notification spec), which matters for a “bell attention” UX. For the applet in cosmic-flatpak, whichever path is chosen just needs the matching finish-arg.

Ranking for THIS project — a layer-shell drop-down terminal + out-of-process panel applet, single maintainer, appstore-style reach desired — by (reach × fit) / effort:

  1. Native release spine (do first, everything hangs off it). Adopt the System76 convention: extend the justfile with vendor/build-vendored + rootdir= install covering BOTH bins, desktop files, metainfo, icons; CI runs desktop-file-validate + tests; release = semver bump + annotated v<version> tag + GitHub Release with source archive, vendor.tar, per-arch binary tarballs and a sha256sums file (plain GHA matrix; cargo-dist optional but its deb gap and COSMIC-specific needs make it skippable). Effort S; enables items 2-4.
  2. Applet → pop-os/cosmic-flatpak (the single highest-leverage submission). Store-visible to every COSMIC user via the built-in “COSMIC Flatpak” source; the platform’s flatpak applet path is built for exactly this shape; manifest is ~40 lines on the dict-applet template with --talk-name=io.github.l1br3_io.CosmicExtDropterm added for the host-app control channel; PR checklist is satisfiable by a human author (no LLM-generated manifest content). Effort S-M. Caveat to test in CI/locally: applet-in-sandbox toggling the NATIVE app across the bus boundary (§8.2).
  3. AUR cosmic-ext-dropterm (+ optional -git). The niche is empty (no dropterm package exists; the quake-terminal PKGBUILD is a copy-adapt); Arch/COSMIC-derivative users are the natural early adopters. Effort S.
  4. cargo-deb deb from the GitHub release. Pop!_OS users who never leave apt: double-click install via cosmic-store; also the artifact to hand to anyone wanting a PPA. Effort S. (No apt repo of your own — not worth it.)
  5. Nix flake in-repo, nixpkgs PR when stable. Flake with cargoLock + outputHashes (or allowBuiltinFetchGit) + wrapping à la libcosmicAppHook; nixpkgs PR later copies the sysinfo shape (fetchFromGitHub
    • cargoHash) once there is a tagged release history. Effort M, mostly waiting on review.
  6. Flathub for the main app — blocked, revisit only on a trigger. The layer-shell sandbox gate (§2.4) makes the flagship feature impossible inside a standard Flatpak on cosmic-comp today; revisit only if (a) cosmic-comp grows an intended sandboxed-layer-shell path, or (b) DropTerm grows a non-layer-shell windowed fallback mode worth shipping separately. Do NOT ship a Flatpak that silently can’t drop down — that app-switcher lesson is the loudest one in this research.
  7. Ecosystem hygiene (cheap, compounding): add the ™ (“for the COSMIC™ desktop”) per TRADEMARK.md §5.2, PR into cosmic-utils/cosmic-project-collection, Flathub-grade metainfo (releases, OARS, ≤1000×700 screenshots) even for the native/deb path so cosmic-store renders it well, and StartupWMClass=cosmic-ext-dropterm in the desktop file.

Sources