The workflow ignores README pushes, so the previous note was wrong. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018jkHZhr7ZzHGGuE2bJQmGa
heiniremote-flatpak
Flatpak packaging for the HeiniRemote
customer agent (de.pc_heini.HeiniRemoteAgent) — an additional distribution
channel next to the plain release binary, with all dependencies (GStreamer,
libnice, wl-clipboard, …) pinned inside the freedesktop 25.08 runtime (24.08 ships libpipewire 1.2,
whose buffer negotiation fails against KWin 6.7 / PipeWire 1.6 hosts).
Same setup as o3de-flatpak:
a Gitea Action builds the Flatpak without flatpak-builder (no bubblewrap
needed in CI), exports it into an OSTree repo and force-pushes that to the
pages branch. The difference: the agent is compiled from upstream source
(newest v* tag, falling back to main while no release exists) instead of
repackaging a prebuilt archive.
Install
Note: this repository must stay public. Flatpak fetches the OSTree repo from the raw
pagesbranch without any credentials — with the repo set to private,flatpak remote-add/flatpak installfail with a 404. (The agent's source lives in the private HeiniRemote repo; only the built binary is published here.)
From the Flatpak remote (gets updates via flatpak update):
flatpak remote-add --if-not-exists heiniremote \
https://git.pc-heini.de/pc-heini/HeiniRemote-AgentFlatpak/raw/branch/pages/heiniremote.flatpakrepo
flatpak install heiniremote de.pc_heini.HeiniRemoteAgent
Or as a single-file bundle (attached to each release of this repo, no remote needed, but no auto-updates either):
flatpak install ./heiniremote-agent-<version>.flatpak
Configure
The agent needs a server URL and device token. Inside the sandbox the config path is:
~/.var/app/de.pc_heini.HeiniRemoteAgent/config/heiniremote/agent.toml
If a native install already left a config at ~/.config/heiniremote/agent.toml,
the wrapper picks it up automatically (read-only). HEINIREMOTE_SERVER_URL /
HEINIREMOTE_TOKEN env overrides work as usual:
flatpak run --env=HEINIREMOTE_SERVER_URL=wss://… de.pc_heini.HeiniRemoteAgent
Autostart
The native install runs as a systemd user service; the Flatpak equivalent is a
user unit wrapping flatpak run:
# ~/.config/systemd/user/heiniremote-agent.service
[Unit]
Description=PC-Heini Fernwartung (HeiniRemote Agent, Flatpak)
After=graphical-session.target
[Service]
ExecStart=flatpak run de.pc_heini.HeiniRemoteAgent
Restart=on-failure
[Install]
WantedBy=graphical-session.target
How the sandbox is punched
Screen capture and input injection go through xdg-desktop-portal (ScreenCast + RemoteDesktop) — that is the normal, fully sandboxed path and needs no special permission. Two things do:
--talk-name=org.freedesktop.Flatpak— the PTY rescue console must show the host, not the sandbox. The wrapper setsSHELL=/app/bin/host-shell, which execs the user's real login shell viaflatpak-spawn --host. This is a deliberate sandbox escape; for a remote maintenance tool the sandbox is packaging, not a security boundary.--filesystem=xdg-config/heiniremote:ro— adopt a native install'sagent.toml(see above).
Everything else is standard: network (signaling + WebRTC/TURN), wayland
(bundled wl-copy/wl-paste), dri (dmabuf screencast buffers), and the
StatusNotifier names for the tray icon.
Repo layout
| File | Role |
|---|---|
.gitea/workflows/build-flatpak.yml |
CI: resolve upstream version → cargo build → assemble → publish pages + release bundle. Daily schedule picks up new upstream versions. |
scripts/get-latest-version.sh |
Newest upstream v* tag, else main HEAD (0.0.0-git.<date>.<sha>). |
scripts/make-flatpak.sh |
bwrap-free assembly: build-init → copy files → build-finish → build-export. |
heiniremote-wrapper.sh |
Entry point: host-shell $SHELL override + config adoption. |
host-shell.sh |
flatpak-spawn --host bridge for the PTY console. |
de.pc_heini.HeiniRemoteAgent.* |
Desktop file, AppStream metainfo (version stamped by CI), icon. |
Builds track the newest upstream main commit. To rebuild before the nightly check, push a change to a packaging file (README, docs, LICENSE and .gitignore are ignored by the workflow) or run the workflow manually via workflow_dispatch.