Context
Most of the distribution plumbing already exists. State checked on 2026-08-10:
| Channel |
Workflow |
Status |
| winget |
publish-winget.yml |
Configured. WINGET_IDENTIFIER=OpenScreen.OpenScreen is set; microsoft/winget-pkgs still only carries manifests/s/SiddharthVaddem/OpenScreen, so the new identifier lands on the next release. |
| AUR |
aur-publish.yml |
Configured (AUR_PACKAGE_NAME, AUR_SSH_PRIVATE_KEY). |
| Nix |
bump-nix-package.yml |
Configured. |
| Microsoft Store |
— |
MSSTORE_PRODUCT_ID set. |
| Homebrew cask |
update-homebrew-cask.yml |
Dormant — see below. (Update 2026-08-11: fixed and publishing; the tap carries 1.9.2.) |
| Flathub |
— |
Absent. (Update 2026-08-11: bigger than it looks — see the status note at the bottom.) |
Two gaps remain.
1. The Homebrew cask job is skipped on every release
update-homebrew-cask.yml is gated on:
if: ... && vars.HOMEBREW_TAP_OWNER != '' && vars.HOMEBREW_TAP_REPO != ''
Neither variable exists on the repo, so the job is skipped every time — and a skipped job is green. This is the exact failure mode that publish-winget.yml documents in the comment above its own if:, after eight releases "succeeded" without publishing anything (#148). The same guard shape is still in place here.
If the tap isn't wanted, delete the workflow instead — dormant-and-green is the worst of the three options.
2. No Flathub package
A Flathub search for "openscreen" returns zero results. It is the main Linux discovery surface (GNOME Software and KDE Discover both pull from it) and the only channel here with no automation at all. The AppImage/deb/rpm/pacman targets don't help — Flathub needs its own manifest submitted to flathub/flathub.
Deliberately not proposed
Chocolatey and Scoop. Windows is already covered by winget plus the Store; add them only if someone asks.
Why this is worth finishing
Beyond installation convenience, these are the highest-authority pages that link the project by name, and they intercept "install openscreen" before it reaches the stale third-party download mirrors currently outranking getopenscreen.com.
Status, 2026-08-11
Homebrew publishes. The chain is closed: the tap repository exists, HOMEBREW_TAP_OWNER and HOMEBREW_TAP_REPO are set, #340 moved the configuration test into a reporting step, and HOMEBREW_TAP_TOKEN was created as a fine-grained PAT with contents write on the tap alone. GITHUB_TOKEN could never have stood in for it — it is scoped to this repository and cannot push to a second one.
Proven rather than assumed: update-homebrew-cask.yml was dispatched at v1.9.2 (run 31535851764), every step green through Commit and push to tap, and Casks/openscreen.rb now carries version 1.9.2 with both architecture digests. For contrast, the previous run of the same workflow — the release event earlier the same day, before #340 merged — concluded skipped, which is the failure this issue was opened about, on the record one last time.
What is still unverified is the consumer end: brew install --cask getopenscreen/openscreen/openscreen needs a Mac, and neither the tap contents nor CI can answer for it. The DMGs it points at are notarized, since the Apple credentials are present, so it should not need the quarantine dance.
Flathub is a port, not a manifest. Flathub's requirements forbid the shortcut every other channel here uses:
All source available submissions must be built entirely from source code. This requirement applies to the main application component defined in the manifest, as well as any runtime dependencies included in the manifest.
Prepackaged binaries — .deb, AppImage or similar — are prohibited, and extra-data is not an escape hatch: it exists for non-redistributable sources, and upstream authorship implies redistribution rights, so a submission from this repository has no grounds to use it. OpenScreen is MIT, therefore source-available, therefore it must build inside the sandbox with no network. Concretely that means offline npm sources generated from the lockfile, vendored crates for the Rust compositor and the pipewire-capture helper, Electron from org.electronjs.Electron2.BaseApp — and ffmpeg built from source, which is the expensive part.
ffmpeg deserves its own paragraph, because it is what makes this a port rather than a manifest. scripts/fetch-ffmpeg.mjs pins a BtbN prebuilt shared tree, which the rule above rejects. Substituting the org.freedesktop.Platform.ffmpeg-full extension does not work either, and the reason is specific: scripts/build-linux-compositor-addon.mjs renames every ffmpeg dynamic symbol in the libraries the addon ships, because Electron links Chromium's own stripped libffmpeg.so into the same address space and the addon would otherwise bind to that. Doing so needs headers and libraries the build owns; the extension ships libraries without dev headers. So ffmpeg has to be compiled inside the manifest, and whether that reproduces the tree the addon was actually tested against is the open question. None of it can be built or verified on a Windows machine — flatpak-builder is Linux-only — which is what #347 exists to settle in CI.
One defect found in the metadata that just landed. build/com.getopenscreen.OpenScreen.metainfo.xml declares <launchable type="desktop-id">openscreen.desktop</launchable>, but Flatpak only exports desktop files prefixed with the app ID, so the Flatpak will ship com.getopenscreen.OpenScreen.desktop and this launchable will not resolve. The CI gate added in #340 cannot catch it: appstreamcli validate checks AppStream correctness, not Flathub's naming rules, which live in flatpak-builder-lint.
To be explicit about a non-problem, since it looks like one: electron-builder.json5 sets appId: com.etiennelescot.openscreen while the AppStream ID is com.getopenscreen.OpenScreen. These live in different namespaces and Flathub constrains only its own — the metainfo <id> must equal the Flatpak ID, which is the manifest filename, and those two already agree. The Electron appId does not need to change, and should not: macOS keys TCC grants to it, the cask's zap trash paths are built from it, and the Store identity is separate again.
Verdict du spike, 2026-08-12
Deux runs de flatpak-spike.yml (31537831529, 31575509206) : c'est faisable, et la partie chère est prouvée.
| Question |
Réponse |
| runtime 24.08, BaseApp Electron2 24.08, node22, rust-stable existent ? |
oui, tout s'installe |
flatpak-node-generator digère package-lock.json ? |
oui — 770 paquets → 1572 sources, 903 Ko |
Les deux Cargo.lock vendorisent ? |
oui |
| Tarball ffmpeg upstream ? |
oui, 8.1.2 (464beb5e…) ; le pin BtbN est ce release + 34 commits |
| ffmpeg compile depuis les sources dans le sandbox ? |
oui — ~7 min, libav* construits, le build atteint le module app |
Le paragraphe ci-dessus sur ffmpeg comme obstacle principal reste vrai sur le pourquoi (Flathub refuse le binaire BtbN, et l'extension ffmpeg-full n'a pas les headers dont le renommage de symboles a besoin), mais l'obstacle est franchi : compiler ffmpeg dans le manifeste marche.
Ce qui reste est du câblage ordinaire, plus la revue humaine de Flathub :
- Chemin du cache npm.
npm ci --offline meurt en ENOTCACHED sur zustand-5.0.14.tgz : les sources générées atterrissent dans flatpak-node/npm-cache, alors que le manifeste pointe npm_config_cache ailleurs. Détail de configuration.
- Sources cargo dans le manifeste — un
cargo-sources.json par lockfile.
- Empaqueter Electron :
command: openscreen ne résout rien, et le <launchable> du metainfo doit devenir com.getopenscreen.OpenScreen.desktop.
Note sur l'outillage : le Stage E du run 2 a signalé « does not exist » sur un curl: (35) Connection reset by peer — un faux négatif, exactement la confusion « requête cassée » / « absent » que la revue de #347 avait corrigée sur le Stage A. Le digest étant désormais épinglé dans le manifeste, le Stage E n'a plus d'objet et devrait disparaître.
Progression du portage, 2026-08-12
Cinq runs. Chaque mur tombe et découvre le suivant, plus petit — sauf le dernier, qui est une décision produit.
| Mur |
Cause |
État |
| ffmpeg prébuilt refusé |
Règle Flathub « tout depuis les sources » |
✅ module ffmpeg 8.1.2 compilé (~7 min) |
npm ci → ENOTCACHED |
Chemins de cache inventés. Ils sont positionnels : flatpak-node/ sous le répertoire du module, et XDG_CACHE_HOME est là où le binaire Electron est mis en cache |
✅ passe |
| Crates hors-ligne |
CARGO_HOME doit être le chemin que flatpak-cargo-generator code en dur |
✅ les deux lockfiles fusionnent dans un seul vendor/ sans collision |
bindgen : Unable to find libclang |
Le SDK ne fournit pas libclang |
✅ extension llvm18 + LIBCLANG_PATH |
patchelf not found |
C'est lui qui réécrit les symboles ffmpeg pour ne pas se lier au libffmpeg.so de Chromium |
✅ module 0.18.0, cleanup: ['*'] |
Garde before-pack : payload Linux incomplet |
Il manque le helper whisper.cpp et ses .so ggml |
❌ décision à prendre |
Vérifié au passage : le helper pipewire compile et s'exécute — son « no ScreenCast portal » est sa propre sonde constatant qu'un runner CI n'a pas de session graphique, pas un échec de build. Et FFMPEG_DIR=/app résout : avcodec, avformat, avutil, swscale, swresample sont liés depuis le module compilé juste avant.
Le blocage restant n'est pas technique. electron/native/whisper-stt/CMakeLists.txt récupère whisper.cpp, cpp-httplib et nlohmann/json par FetchContent, donc par le réseau, qu'un sandbox Flatpak n'a pas. Deux issues, et elles ne donnent pas le même produit :
- Parité complète — déclarer les trois dépôts comme sources git épinglées et rediriger
FetchContent avec -DFETCHCONTENT_SOURCE_DIR_<NAME>. Faisable : scripts/build-whisper-stt.sh transmet déjà ses arguments à cmake (extra_cmake_flags=("$@")). Coût : trois pins de plus à maintenir, et probablement un ou deux murs supplémentaires puisque whisper.cpp tire ggml.
- Flatpak sans STT — désactiver la transcription dans cette variante. Le garde
before-pack existe précisément pour empêcher ça : sans le helper, « transcription and captions fail with a developer error shown to end users ». Il faudrait donc un chemin de désactivation propre, pas seulement contourner le garde.
Tant que ce n'est pas tranché, le manifeste ne peut pas produire d'app complète.
Le manifeste Flatpak construit et passe le linter, 2026-08-13
Quatorze runs de flatpak-spike.yml. Le manifeste vit dans build/flatpak/ et se construit hors réseau, entièrement depuis les sources : Success! en ~20 min, quatre modules (patchelf → spirv-headers → ffmpeg → openscreen), export nommé d'après l'app ID (fichier desktop, huit tailles d'icône, metainfo).
Verdict de flatpak-builder-lint, l'outil que Flathub applique à la soumission :
| Mode |
Erreurs |
manifest |
aucune (un avertissement : le runtime 25.08 existe) |
repo |
appstream-screenshots-not-mirrored-in-ostree, appstream-external-screenshot-url |
Les deux erreurs repo ne sont pas dans nos fichiers : le contrôle exige une ref OSTree screenshots/<arch> que seule l'étape de mise en miroir de Flathub crée, et il se désactive en présence d'une « test ref » — ce que fait leur CI. Un repo construit localement n'a ni l'une ni l'autre, donc c'est la seule classe de finding que ce spike ne peut pas trancher.
Les murs franchis, dans l'ordre, avec ce que chacun a coûté : ffmpeg depuis les sources (Flathub refuse le binaire BtbN) ; les chemins de cache npm, qui sont positionnels et où XDG_CACHE_HOME est ce qui met Electron en cache ; CARGO_HOME au chemin que le générateur code en dur ; llvm18 pour le libclang de bindgen ; patchelf, qui réécrit les symboles ffmpeg ; les trois dépôts FetchContent du helper STT, épinglés tag + commit, redirigés par une nouvelle couture WHISPER_EXTRA_CMAKE_FLAGS dans build-whisper-stt.sh ; SPIRV-Headers accordé au Vulkan du runtime ; le staging de ffmpeg là où le helper pipewire le cherche vraiment ; --config.electronDist pour supprimer tout téléchargement ; et directories.output, qui est release/${version} et pas dist/.
Deux gardes du repo ont fait exactement leur travail et méritent d'être cités : before-pack a refusé un payload sans le helper STT, puis sans les .so du helper — deux trous que le build avait franchis en silence.
Ce qui reste avant une soumission :
- Personne n'a lancé l'app. Un build vert n'est pas une app qui marche. Il faut un bureau Linux avec un portail — ni la CI ni le linter ne peuvent répondre.
- La source est un
type: dir le temps du spike. Flathub veut type: git tag + commit, impossible tant qu'aucune release ne contient le metainfo et le fichier desktop : v1.9.2 est antérieur aux deux.
mirror-urls sur le module ffmpeg : deux échecs réseau de ffmpeg.org sur quatorze runs.
- Écart de 34 commits entre ffmpeg 8.1.2 upstream et le snapshot BtbN épinglé — ça compile, ce n'est pas exercé à l'exécution.
- Éventuellement passer au runtime 25.08, ce qui rouvre les questions de versions des Stages A et B (node22, llvm18, BaseApp Electron).
Context
Most of the distribution plumbing already exists. State checked on 2026-08-10:
publish-winget.ymlWINGET_IDENTIFIER=OpenScreen.OpenScreenis set;microsoft/winget-pkgsstill only carriesmanifests/s/SiddharthVaddem/OpenScreen, so the new identifier lands on the next release.aur-publish.ymlAUR_PACKAGE_NAME,AUR_SSH_PRIVATE_KEY).bump-nix-package.ymlMSSTORE_PRODUCT_IDset.update-homebrew-cask.ymlTwo gaps remain.
1. The Homebrew cask job is skipped on every release
update-homebrew-cask.ymlis gated on:Neither variable exists on the repo, so the job is skipped every time — and a skipped job is green. This is the exact failure mode that
publish-winget.ymldocuments in the comment above its ownif:, after eight releases "succeeded" without publishing anything (#148). The same guard shape is still in place here.getopenscreen/homebrew-openscreen)HOMEBREW_TAP_OWNERandHOMEBREW_TAP_REPOif:into a step that reports its absence, mirroring whatpublish-winget.ymlnow doesHOMEBREW_TAP_TOKENsecretCasks/openscreen.rbat 1.9.2 landed in the tap on 2026-08-11brew install --cask getopenscreen/openscreen/openscreenon a MacIf the tap isn't wanted, delete the workflow instead — dormant-and-green is the worst of the three options.
2. No Flathub package
A Flathub search for "openscreen" returns zero results. It is the main Linux discovery surface (GNOME Software and KDE Discover both pull from it) and the only channel here with no automation at all. The
AppImage/deb/rpm/pacmantargets don't help — Flathub needs its own manifest submitted toflathub/flathub.flathub/flathubDeliberately not proposed
Chocolatey and Scoop. Windows is already covered by winget plus the Store; add them only if someone asks.
Why this is worth finishing
Beyond installation convenience, these are the highest-authority pages that link the project by name, and they intercept "install openscreen" before it reaches the stale third-party download mirrors currently outranking getopenscreen.com.
Status, 2026-08-11
Homebrew publishes. The chain is closed: the tap repository exists,
HOMEBREW_TAP_OWNERandHOMEBREW_TAP_REPOare set, #340 moved the configuration test into a reporting step, andHOMEBREW_TAP_TOKENwas created as a fine-grained PAT with contents write on the tap alone.GITHUB_TOKENcould never have stood in for it — it is scoped to this repository and cannot push to a second one.Proven rather than assumed:
update-homebrew-cask.ymlwas dispatched atv1.9.2(run31535851764), every step green through Commit and push to tap, andCasks/openscreen.rbnow carries version 1.9.2 with both architecture digests. For contrast, the previous run of the same workflow — thereleaseevent earlier the same day, before #340 merged — concludedskipped, which is the failure this issue was opened about, on the record one last time.What is still unverified is the consumer end:
brew install --cask getopenscreen/openscreen/openscreenneeds a Mac, and neither the tap contents nor CI can answer for it. The DMGs it points at are notarized, since the Apple credentials are present, so it should not need the quarantine dance.Flathub is a port, not a manifest. Flathub's requirements forbid the shortcut every other channel here uses:
Prepackaged binaries —
.deb, AppImage or similar — are prohibited, andextra-datais not an escape hatch: it exists for non-redistributable sources, and upstream authorship implies redistribution rights, so a submission from this repository has no grounds to use it. OpenScreen is MIT, therefore source-available, therefore it must build inside the sandbox with no network. Concretely that means offline npm sources generated from the lockfile, vendored crates for the Rust compositor and thepipewire-capturehelper, Electron fromorg.electronjs.Electron2.BaseApp— and ffmpeg built from source, which is the expensive part.ffmpeg deserves its own paragraph, because it is what makes this a port rather than a manifest.
scripts/fetch-ffmpeg.mjspins a BtbN prebuilt shared tree, which the rule above rejects. Substituting theorg.freedesktop.Platform.ffmpeg-fullextension does not work either, and the reason is specific:scripts/build-linux-compositor-addon.mjsrenames every ffmpeg dynamic symbol in the libraries the addon ships, because Electron links Chromium's own strippedlibffmpeg.sointo the same address space and the addon would otherwise bind to that. Doing so needs headers and libraries the build owns; the extension ships libraries without dev headers. So ffmpeg has to be compiled inside the manifest, and whether that reproduces the tree the addon was actually tested against is the open question. None of it can be built or verified on a Windows machine —flatpak-builderis Linux-only — which is what #347 exists to settle in CI.One defect found in the metadata that just landed.
build/com.getopenscreen.OpenScreen.metainfo.xmldeclares<launchable type="desktop-id">openscreen.desktop</launchable>, but Flatpak only exports desktop files prefixed with the app ID, so the Flatpak will shipcom.getopenscreen.OpenScreen.desktopand this launchable will not resolve. The CI gate added in #340 cannot catch it:appstreamcli validatechecks AppStream correctness, not Flathub's naming rules, which live inflatpak-builder-lint.To be explicit about a non-problem, since it looks like one:
electron-builder.json5setsappId: com.etiennelescot.openscreenwhile the AppStream ID iscom.getopenscreen.OpenScreen. These live in different namespaces and Flathub constrains only its own — the metainfo<id>must equal the Flatpak ID, which is the manifest filename, and those two already agree. The Electron appId does not need to change, and should not: macOS keys TCC grants to it, the cask'szap trashpaths are built from it, and the Store identity is separate again.Verdict du spike, 2026-08-12
Deux runs de
flatpak-spike.yml(31537831529,31575509206) : c'est faisable, et la partie chère est prouvée.flatpak-node-generatordigèrepackage-lock.json?Cargo.lockvendorisent ?464beb5e…) ; le pin BtbN est ce release + 34 commitslibav*construits, le build atteint le module appLe paragraphe ci-dessus sur ffmpeg comme obstacle principal reste vrai sur le pourquoi (Flathub refuse le binaire BtbN, et l'extension
ffmpeg-fulln'a pas les headers dont le renommage de symboles a besoin), mais l'obstacle est franchi : compiler ffmpeg dans le manifeste marche.Ce qui reste est du câblage ordinaire, plus la revue humaine de Flathub :
npm ci --offlinemeurt enENOTCACHEDsurzustand-5.0.14.tgz: les sources générées atterrissent dansflatpak-node/npm-cache, alors que le manifeste pointenpm_config_cacheailleurs. Détail de configuration.cargo-sources.jsonpar lockfile.command: openscreenne résout rien, et le<launchable>du metainfo doit devenircom.getopenscreen.OpenScreen.desktop.Note sur l'outillage : le Stage E du run 2 a signalé « does not exist » sur un
curl: (35) Connection reset by peer— un faux négatif, exactement la confusion « requête cassée » / « absent » que la revue de #347 avait corrigée sur le Stage A. Le digest étant désormais épinglé dans le manifeste, le Stage E n'a plus d'objet et devrait disparaître.Progression du portage, 2026-08-12
Cinq runs. Chaque mur tombe et découvre le suivant, plus petit — sauf le dernier, qui est une décision produit.
npm ci→ENOTCACHEDflatpak-node/sous le répertoire du module, etXDG_CACHE_HOMEest là où le binaire Electron est mis en cacheCARGO_HOMEdoit être le chemin queflatpak-cargo-generatorcode en durvendor/sans collisionUnable to find libclangllvm18+LIBCLANG_PATHpatchelf not foundlibffmpeg.sode Chromiumcleanup: ['*']before-pack: payload Linux incomplet.soggmlVérifié au passage : le helper pipewire compile et s'exécute — son « no ScreenCast portal » est sa propre sonde constatant qu'un runner CI n'a pas de session graphique, pas un échec de build. Et
FFMPEG_DIR=/apprésout : avcodec, avformat, avutil, swscale, swresample sont liés depuis le module compilé juste avant.Le blocage restant n'est pas technique.
electron/native/whisper-stt/CMakeLists.txtrécupère whisper.cpp, cpp-httplib et nlohmann/json parFetchContent, donc par le réseau, qu'un sandbox Flatpak n'a pas. Deux issues, et elles ne donnent pas le même produit :FetchContentavec-DFETCHCONTENT_SOURCE_DIR_<NAME>. Faisable :scripts/build-whisper-stt.shtransmet déjà ses arguments à cmake (extra_cmake_flags=("$@")). Coût : trois pins de plus à maintenir, et probablement un ou deux murs supplémentaires puisque whisper.cpp tire ggml.before-packexiste précisément pour empêcher ça : sans le helper, « transcription and captions fail with a developer error shown to end users ». Il faudrait donc un chemin de désactivation propre, pas seulement contourner le garde.Tant que ce n'est pas tranché, le manifeste ne peut pas produire d'app complète.
Le manifeste Flatpak construit et passe le linter, 2026-08-13
Quatorze runs de
flatpak-spike.yml. Le manifeste vit dansbuild/flatpak/et se construit hors réseau, entièrement depuis les sources :Success!en ~20 min, quatre modules (patchelf→spirv-headers→ffmpeg→openscreen), export nommé d'après l'app ID (fichier desktop, huit tailles d'icône, metainfo).Verdict de
flatpak-builder-lint, l'outil que Flathub applique à la soumission :manifestrepoappstream-screenshots-not-mirrored-in-ostree,appstream-external-screenshot-urlLes deux erreurs
repone sont pas dans nos fichiers : le contrôle exige une ref OSTreescreenshots/<arch>que seule l'étape de mise en miroir de Flathub crée, et il se désactive en présence d'une « test ref » — ce que fait leur CI. Un repo construit localement n'a ni l'une ni l'autre, donc c'est la seule classe de finding que ce spike ne peut pas trancher.Les murs franchis, dans l'ordre, avec ce que chacun a coûté : ffmpeg depuis les sources (Flathub refuse le binaire BtbN) ; les chemins de cache npm, qui sont positionnels et où
XDG_CACHE_HOMEest ce qui met Electron en cache ;CARGO_HOMEau chemin que le générateur code en dur ;llvm18pour le libclang de bindgen ;patchelf, qui réécrit les symboles ffmpeg ; les trois dépôtsFetchContentdu helper STT, épinglés tag + commit, redirigés par une nouvelle coutureWHISPER_EXTRA_CMAKE_FLAGSdansbuild-whisper-stt.sh;SPIRV-Headersaccordé au Vulkan du runtime ; le staging de ffmpeg là où le helper pipewire le cherche vraiment ;--config.electronDistpour supprimer tout téléchargement ; etdirectories.output, qui estrelease/${version}et pasdist/.Deux gardes du repo ont fait exactement leur travail et méritent d'être cités :
before-packa refusé un payload sans le helper STT, puis sans les.sodu helper — deux trous que le build avait franchis en silence.Ce qui reste avant une soumission :
type: dirle temps du spike. Flathub veuttype: gittag + commit, impossible tant qu'aucune release ne contient le metainfo et le fichier desktop :v1.9.2est antérieur aux deux.mirror-urlssur le module ffmpeg : deux échecs réseau de ffmpeg.org sur quatorze runs.