{
 "app_id": "io.github.stepan.WayVoice",
 "source_url": "https://raw.githubusercontent.com/stepan-pavlenko/wayvoice/main/io.github.stepan.WayVoice.json",
 "runtime": "org.gnome.Platform",
 "runtime_version": "50",
 "sdk": "org.gnome.Sdk",
 "finish_args": [
  "--share=ipc",
  "--share=network",
  "--socket=wayland",
  "--socket=fallback-x11",
  "--filesystem=xdg-run/pipewire-0",
  "--talk-name=org.freedesktop.Flatpak",
  "--talk-name=org.freedesktop.Notifications"
 ],
 "module_count": 2,
 "fetched_at": "2026-10-05T15:42:02.744067+00:00",
 "manifest": {
  "id": "io.github.stepan.WayVoice",
  "runtime": "org.gnome.Platform",
  "runtime-version": "50",
  "sdk": "org.gnome.Sdk",
  "command": "wayvoice-settings",
  "build-options": {
   "build-args": [
    "--share=network"
   ]
  },
  "finish-args": [
   "--share=ipc",
   "--share=network",
   "--socket=wayland",
   "--socket=fallback-x11",
   "--filesystem=xdg-run/pipewire-0",
   "--talk-name=org.freedesktop.Flatpak",
   "--talk-name=org.freedesktop.Notifications"
  ],
  "cleanup-commands": [
   "find /app -name '__pycache__' -type d -prune -exec rm -rf {} +",
   "find /app -name '*.pyc' -delete",
   "rm -rf /app/lib/wayvoice/runtime/lib/python3*/site-packages/pip /app/lib/wayvoice/runtime/lib/python3*/site-packages/pip-*.dist-info /app/lib/wayvoice/runtime/bin/pip*",
   "rm -rf /app/lib/wayvoice/runtime/share"
  ],
  "modules": [
   {
    "name": "wl-clipboard",
    "buildsystem": "meson",
    "config-opts": [
     "-Dwerror=false",
     "-Dfishcompletiondir=no",
     "-Dzshcompletiondir=no"
    ],
    "cleanup": [
     "/share/doc"
    ],
    "sources": [
     {
      "type": "git",
      "url": "https://github.com/bugaevc/wl-clipboard.git",
      "tag": "v2.3.0",
      "commit": "67a7b937895bceec1ae5ccebb10216f63f70ca1b"
     }
    ]
   },
   {
    "name": "wayvoice",
    "buildsystem": "simple",
    "sources": [
     {
      "type": "dir",
      "path": ".",
      "skip": [
       ".git",
       ".flatpak-builder",
       "build",
       "build-dir",
       "dist",
       "__pycache__",
       "*.pyc"
      ]
     }
    ],
    "build-commands": [
     "# wl-clipboard is built from source instead of being pulled in as a shared",
     "# module: the module registry cannot be resolved from every builder, and",
     "# without wl-copy the text never even reaches the clipboard. It is a tiny",
     "# meson project whose only build dependency (wayland-client) is part of the",
     "# GNOME SDK. The pinned tag v2.3.0 and its commit are both recorded, so the",
     "# build is reproducible and cannot silently follow a moving branch.",
     "# fish and zsh completions are disabled: upstream installs them under",
     "# /usr/share, which is read-only in a build sandbox, and only /app is",
     "# writable (bash completions install into /app and are kept).",
     "# Note the cleanup list: \"*\" would delete wl-copy/wl-paste themselves,",
     "# because it wipes everything the module installed, not just its sources.",
     "#",
     "# Runtime/SDK: GNOME 50 is the current GNOME release, so the Flatpak is",
     "# built against it and gets the newest GTK4/libadwaita; branch 49 is",
     "# still installed on this host and would work as a fallback, but it is",
     "# an already superseded GNOME. The runtime also ships everything the",
     "# engine needs at run time: python3 and the PipeWire tools.",
     "#",
     "# Two processes, two entry points (see app/src/wayvoice/cli.py):",
     "#   wayvoice-daemon   -> wayvoice.daemon, the background dictation service",
     "#   wayvoice-settings -> wayvoice.ui, the GTK4/libadwaita window",
     "# `command` starts the settings window, because that is the process a",
     "# launcher has to open: Flatpak appends the arguments of",
     "# `flatpak run <id> ...` AFTER the command, and it rewrites the exported",
     "# desktop entry into `flatpak run <id> wayvoice-settings`. With the",
     "# window as the command both entry points keep working, whereas a daemon",
     "# command would swallow that argument and only start a daemon.",
     "# The daemon is started explicitly, in its own sandbox instance:",
     "#   flatpak run --command=wayvoice-daemon io.github.stepan.WayVoice",
     "#",
     "# Layout: same shape as scripts/build-deb.sh, rooted at /app:",
     "#   /app/bin/*                       the POSIX-sh wrappers (they look the",
     "#                                    sources up relative to themselves)",
     "#   /app/lib/wayvoice/app            copy of app/ (pyproject.toml, src/)",
     "#   /app/lib/wayvoice/runtime        prebuilt Faster-Whisper venv (below)",
     "#   /app/share/systemd/user          the four user units",
     "#   /app/share/applications          the desktop entry",
     "#   /app/share/metainfo              the AppStream metainfo",
     "#   /app/share/icons/hicolor/...     scalable + symbolic app icons",
     "#   /app/share/polkit-1/actions      the manage-deps policy",
     "#   /app/share/doc/wayvoice          README, CHANGELOG, LICENSE",
     "# /app/bin + /app/lib/wayvoice/app/src is exactly the first candidate",
     "# the wrappers probe (<bindir>/../lib/wayvoice/app/src), and paths.py",
     "# derives the same root from parents[2] of the module, so nothing in the",
     "# project needs to know about /app.",
     "install -d /app/bin /app/lib/wayvoice",
     "cp -a app /app/lib/wayvoice/app",
     "find /app/lib/wayvoice/app -name '__pycache__' -type d -prune -exec rm -rf {} +",
     "find /app/lib/wayvoice/app -name '*.pyc' -delete",
     "install -m 0755 scripts/wayvoice scripts/wayvoice-daemon scripts/wayvoice-settings scripts/wayvoice-engine-setup scripts/setup-user /app/bin/",
     "install -d /app/share/systemd/user",
     "install -m 0644 systemd/wayvoice.service systemd/wayvoice-setup.service systemd/wayvoice-engine-setup.service systemd/wayvoice-ydotool.service /app/share/systemd/user/",
     "install -d /app/share/applications /app/share/metainfo",
     "install -m 0644 data/io.github.stepan.WayVoice.desktop /app/share/applications/io.github.stepan.WayVoice.desktop",
     "install -m 0644 data/io.github.stepan.WayVoice.metainfo.xml /app/share/metainfo/io.github.stepan.WayVoice.metainfo.xml",
     "install -d /app/share/icons/hicolor/scalable/apps /app/share/icons/hicolor/symbolic/apps",
     "install -m 0644 data/icons/hicolor/scalable/apps/io.github.stepan.WayVoice.svg /app/share/icons/hicolor/scalable/apps/io.github.stepan.WayVoice.svg",
     "install -m 0644 data/icons/hicolor/symbolic/apps/io.github.stepan.WayVoice-symbolic.svg /app/share/icons/hicolor/symbolic/apps/io.github.stepan.WayVoice-symbolic.svg",
     "# The udev rule (data/80-wayvoice-uinput.rules) is deliberately NOT",
     "# installed: it hands /dev/uinput to the logged-in user, which is a",
     "# host concern - a Flatpak cannot add rules to the host udev database.",
     "#",
     "# The polkit policy is installed for parity with the Debian package, but",
     "# it has no effect here: pkexec does not exist inside the sandbox and a",
     "# Flatpak cannot register a polkit action on the host. `wayvoice deps",
     "# --install` and the matching button in the settings window are",
     "# therefore unavailable in the Flatpak build, which the application",
     "# already handles - pkgsys hides the button when pkexec is missing.",
     "# Nothing is left to install in the sandbox anyway: wl-copy comes from",
     "# the wl-clipboard module, and notify-send plus the pw-* tools are part",
     "# of org.gnome.Platform itself.",
     "install -d /app/share/polkit-1/actions",
     "install -m 0644 packaging/io.github.stepan.WayVoice.manage-deps.policy /app/share/polkit-1/actions/io.github.stepan.WayVoice.manage-deps.policy",
     "install -d /app/share/doc/wayvoice",
     "install -m 0644 README.md CHANGELOG.md LICENSE /app/share/doc/wayvoice/",
     "# The user units are shipped so that the file set matches the Debian",
     "# package, but nothing can start them: org.gnome.Platform ships no",
     "# systemctl at all, and the host user manager cannot see /app. What",
     "# still works is service.py, which falls back to spawning the daemon",
     "# directly when no user manager answers - that is what lets the window",
     "# work in the sandbox. `wayvoice engine-setup` likewise prepares the",
     "# runtime in-process when systemctl is missing. setup-user still cannot",
     "# do its job: it applies the GSettings shortcut and enables the ydotoold",
     "# unit through systemctl, both of which fail here.",
     "#",
     "# ydotool is intentionally neither shipped nor emulated: the client",
     "# needs /dev/uinput and the ydotoold daemon, and Flatpak exposes",
     "# neither. Auto-paste degrades to \"the text ends up in the clipboard\"",
     "# in the Flatpak build. That is the expected sandbox behaviour, not a",
     "# packaging bug, and it cannot be worked around without asking the",
     "# user for a privileged host helper.",
     "#",
     "# Engine, baked into the image so that the first dictation needs neither",
     "# pip nor a network connection. The version bounds are copied verbatim",
     "# from app/src/wayvoice/engine_setup.py:",
     "#   av>=11,<19                faster-whisper <= 1.2.x still calls",
     "#                             av.open(..., metadata_errors=...); PyAV 19",
     "#                             removed that argument, hence the upper bound",
     "#   faster-whisper>=1.1.1,<2  first release of the supported 1.x line",
     "# ctranslate2, tokenizers, onnxruntime, numpy and huggingface-hub arrive",
     "# transitively. The venv uses the SDK interpreter, the same one that runs",
     "# the app, so engine and application share a single Python.",
     "# pyvenv.cfg therefore records /usr/bin as its home, which stays correct",
     "# at run time: the SDK is mounted at /usr during the build and the",
     "# merged-usr runtime is mounted at /usr inside the app sandbox as well",
     "# (with /bin symlinked to usr/bin), so bin/python3 keeps resolving.",
     "# Wheel downloads need network during the build only, which is why the",
     "# manifest asks for it explicitly through build-options.build-args",
     "# (--share=network).",
     "#",
     "# The venv is placed next to the app sources, i.e. /app/lib/wayvoice/runtime,",
     "# and engine.py looks there first (paths.app_dir().parent / \"runtime\",",
     "# only when it really holds bin/python), falling back to the per-user",
     "# $XDG_DATA_HOME/wayvoice/runtime it creates itself. Inside a Flatpak",
     "# sandbox XDG_DATA_HOME is ~/.var/app/<id>/data, a directory that only",
     "# exists at run time, so the per-user path could not be used for a",
     "# prebuilt engine: this is what makes the image work offline.",
     "# WAYVOICE_RUNTIME overrides both, for unusual layouts.",
     "python3 -m venv /app/lib/wayvoice/runtime",
     "/app/lib/wayvoice/runtime/bin/python -m pip install --disable-pip-version-check --no-input --upgrade 'av>=11,<19' 'faster-whisper>=1.1.1,<2'",
     "/app/lib/wayvoice/runtime/bin/python -c \"import av, faster_whisper; m = int(av.__version__.split('.')[0]); assert m < 19, av.__version__; print('PyAV', av.__version__, 'faster-whisper', faster_whisper.__version__)\"",
     "touch /app/lib/wayvoice/runtime/.engine-v1-ready",
     "# cleanup: the __pycache__/.pyc trees pip leaves behind plus pip itself are",
     "# build leftovers and nothing else is generated in the image. The",
     "# cleanup section uses cleanup-commands because cleanup takes paths,",
     "# not shell lines.",
     "#",
     "# finish-args, one by one:",
     "#   --share=ipc                              the settings window and the",
     "#                                              pasted text reach XWayland",
     "#                                              clients only with the X11",
     "#                                              IPC socket pair shared",
     "#   --share=network                         the only outbound connection",
     "#                                              WayVoice ever makes: fetching",
     "#                                              model weights from",
     "#                                              huggingface.co (model_fetch.",
     "#                                              py, the download the settings",
     "#                                              window and `wayvoice model",
     "#                                              --download` start). Needed at",
     "#                                              run time, not only at build",
     "#                                              time: verified that without",
     "#                                              it resolving huggingface.co",
     "#                                              fails inside the sandbox with",
     "#                                              gaierror, so the download",
     "#                                              button cannot work. The",
     "#                                              permission is broader than the",
     "#                                              purpose - recognition itself",
     "#                                              is entirely local and never",
     "#                                              touches the network.",
     "#   --socket=wayland                         native display for the GTK4",
     "#                                              window",
     "#   --socket=fallback-x11                    the window also opens on an",
     "#                                              X11-only session",
     "#   --filesystem=xdg-run/pipewire-0          the microphone. pw-record",
     "#                                              (audio.py) speaks the",
     "#                                              PipeWire protocol and needs",
     "#                                              $XDG_RUNTIME_DIR/pipewire-0",
     "#                                              from the host; Flatpak has",
     "#                                              no --socket=pipewire",
     "#                                              permission, so the socket is",
     "#                                              mapped in explicitly. If the",
     "#                                              session has no PipeWire the",
     "#                                              mapping is skipped with a",
     "#                                              warning instead of breaking",
     "#                                              the launch.",
     "#   --talk-name=org.freedesktop.Flatpak      the portal bus name Flatpak",
     "#                                              itself uses (flatpak-spawn",
     "#                                              --host, portal fallbacks).",
     "#                                              Nothing in the code calls it",
     "#                                              today; it is granted so that",
     "#                                              a host-side helper keeps",
     "#                                              working if one is ever needed",
     "#   --talk-name=org.freedesktop.Notifications  notify-send (notify.py)",
     "#                                              talks this name directly",
     "#                                              and Flatpak blocks it by",
     "#                                              default",
     "#   NOT requested, on purpose:",
     "#   --socket=pulseaudio                      nothing in WayVoice speaks",
     "#                                              PulseAudio; Flatpak would",
     "#                                              also hand over /dev/snd",
     "#                                              through it, which is not",
     "#                                              needed once pipewire-0 is",
     "#                                              mapped",
     "#   --device=all                             verified unnecessary: with",
     "#                                              --filesystem=xdg-run/",
     "#                                              pipewire-0 pw-record already",
     "#                                              records without /dev/snd, and",
     "#                                              it is the only conceivable",
     "#                                              route to /dev/uinput, which",
     "#                                              stays useless without",
     "#                                              ydotoold on the host",
     "#   --filesystem=xdg-data/wayvoice:create     XDG_DATA_HOME is",
     "#                                              ~/.var/app/<id>/data inside",
     "#                                              the sandbox; the host",
     "#                                              ~/.local/share/wayvoice is",
     "#                                              never read, so granting it",
     "#                                              would expose a directory the",
     "#                                              app does not use",
     "#   --talk-name=org.gnome.Shell               the private GNOME Shell bus",
     "#                                              name; WayVoice ships no Shell",
     "#                                              extension and never calls it,",
     "#                                              notifications arrive through",
     "#                                              org.freedesktop.Notifications",
     "true"
    ]
   }
  ]
 }
}