{"article":{"slug":"flatpak-from-the-cli-sucks","title":"Flatpak from the CLI sucks","subtitle":null,"summary":"kowalski7cc explains why Flatpak works for desktop GUI apps but is awkward for terminal tools: entrypoints, PATH, sandbox friction, and packaging tradeoffs that hurt CLI UX.","content_type":"opinion","language":"en","canonical_url":"https://kowalski7cc.xyz/blog/flatpak-from-the-cli-sucks/","author":{"name":"kowalski7cc","url":"https://kowalski7cc.xyz/","person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"kowalski7cc","url":"https://kowalski7cc.xyz/","listing_slug":null,"listing":null},"topics":[{"name":"Open Source","slug":"open-source","url":"https://listedarticles.com/topics/open-source"},{"name":"Developer Tools","slug":"developer-tools","url":"https://listedarticles.com/topics/developer-tools"},{"name":"Opinion","slug":"opinion","url":"https://listedarticles.com/topics/opinion"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1268,"reading_minutes":6,"published_at":"2026-10-03T00:00:00.000Z","added_at":"2026-10-04T17:12:37.440Z","updated_at":"2026-10-04T17:12:37.440Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":false},"profile_url":"https://listedarticles.com/articles/flatpak-from-the-cli-sucks","markdown_url":"https://listedarticles.com/articles/flatpak-from-the-cli-sucks.md","example":false,"citation":"kowalski7cc, kowalski7cc. \"Flatpak from the CLI sucks.\" 3 Oct 2026. https://kowalski7cc.xyz/blog/flatpak-from-the-cli-sucks/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://kowalski7cc.xyz/blog/flatpak-from-the-cli-sucks/"},"body_markdown":"## Package management, from the beginning\n\nOne of the features Linux had way before its competition was the ability to download applications from online repositories, which would later be called an \"app store\". Before this, you would have to download the application binaries and libraries, or build it yourself from the source code, making sure you already had all the required dependencies to compile the application. To solve this issue, package managers like \"APT\" and \"DNF\" were developed. On the surface, the task may seem simple: download, install, update, and remove applications. Under the hood, however, a package manager must handle complex operations: downloading the requested application along with all required libraries, checking dependency availability, resolving conflicts, extracting files to the disk, and running any optional post-installation scripts. Once a program was installed, it could be run by clicking on the new icon that appeared, or if the program was placed in `/bin/` or another path in the system `$PATH` variable, by typing the name of the executable.\n\nAs time moved on, new requirements emerged for package managers: distribution-agnostic support and enhanced security through application sandboxing. Because every distribution family had its own package manager, it quickly became obvious that maintaining packages for multiple distributions was time-consuming for developers, and impossible for distribution maintainers to package every available application. Additionally, as security threats increased, it became necessary to isolate untrusted applications from the system, including legitimate software that might be exploited by malware. Access to documents, peripherals, and other aspects of the system needed to be restricted, granting temporary usage only with explicit user permission.\n\nOne of these package managers with a new approach is Flatpak.\n\nFlatpak tries to solve both issues by radically changing the packaging and distribution model. It allows developers to ship applications in a layered format that includes all necessary dependencies, working across all distributions, and runs them inside a sandbox. Flatpak provides two kinds of permissions: static permissions declared in the manifest, and dynamic permissions requested at runtime through portals exposed over D-Bus.\n\nThis format quickly became the mainstream, default, or even the only way in some distributions to install graphical applications via the software store. However, command-line applications were left behind, and for good reason. Sure, a few CLI-only tools exist, such as flatpak-builder (the tool used to build new Flatpaks), but developers tend to avoid packaging them. Furthermore, as we'll see, their usage from the command line... is rather difficult!\nIf we had installed Flatpak Builder from our distribution's repository with a classic package, we would launch it with `flatpak-builder build-folder manifest.yaml`. However, when installed as a Flatpak itself, the command becomes `flatpak run org.flatpak.Builder build-folder manifest.yaml`.\nNot only does the command become longer and require the full \"app id\" (which consist of a \"unique three-part identifier\", pinpointing both the developer and the application), but also requires the filesystem sandbox to be disabled!\n\nIn the meantime, `flatpak run` got a new `--file-forwarding` option, which maps a specified file from the command line (expressed in the arguments between the `@@` delimiters) inside the sandbox to make it available to the application. However, this approach still has a catch.\n\nAdding the required option and enclosing the file path with `@@` doesn't help at all with the command length, but more importantly doesn't work with directories or non-existent files you may want to create (such as when converting a picture, where the second file path would be the output file)\n\n## Windows 10 and the Universal Windows Platform\n\nOther operating systems encountered the exact same issues regarding application distribution and sandboxing. Windows took a drastic approach: rather than improving the classic Win32 desktop stack, it created an entirely new platform. Even though the technology was initially quite immature, it laid the foundation to distribute \"APPX\" software through the Windows Store alongside sandboxing via AppContainer.\n\nSoon, developers would realize that migrating from Win32 created a massive workload in trying to port applications to the new platform-and it was not always possible due to the technical limitations of UWP. So in a later update to Windows, the Desktop Bridge was introduced.\n\nAmong the new features, many of which centered on packaging in the \"APPX\" format existing Win32 desktop applications, a series of improvements was added to run both UWP and Win32 apps more easily from the command line.\n\nOf course, not every app supported this feature, as it required developers to update the application manifest by adding the `uap3:AppExecutionAlias` extension and specifying the name of the exported executable outside the sandbox. This would create a special 0-byte execution alias inside `%LOCALAPPDATA%\\Microsoft\\WindowsApps`, which is included in the user's PATH variable. This file relies on an NTFS reparse point tagged with `IO_REPARSE_TAG_APPEXECLINK`. When executed, Windows reads this reparse data and launches the actual binary from the restricted `C:\\Program Files\\WindowsApps` directory within its designated application container. An application can export multiple aliases, and the alias name doesn't have to match the executable file inside the container.\n\nBecause these aliases sit in a directory that is included in the user's PATH variable, they can sometimes cause conflicts. A classic example is typing python into CMD and unexpectedly opening the Microsoft Store rather than launching the Python version you manually installed from the python website.\n\nTo solve this issue, the system provides a simple interface to view all aliases exported by installed applications, along with toggles to disable them. When an alias is turned off, Windows simply deletes that 0-byte reparse point from the `%LOCALAPPDATA%\\Microsoft\\WindowsApps` directory. With the file gone, the shell continues searching the rest of the user's PATH.\n\n## A solution for Flatpak\n\nFlatpak development could take inspiration from the Windows approach. A suggested solution would consist of multiple small changes. The first would be adding an `export-commands` key to the Flatpak manifest, mapping internal executable paths to exported command aliases. This approach allowes developers to create wrapper files with complex names inside the package and exporting them with simple names.\n\n```\napp-id: uk.org.greenend.chiark.sgtatham.putty\nruntime: org.freedesktop.Platform\nruntime-version: '26.08'\nsdk: org.freedesktop.Sdk\nrename-desktop-file: putty.desktop\nrename-icon: putty\ncommand: putty\nexport-commands:\n  putty: putty\n  puttygen: puttygen\n  psftp: psftp\n  pageant: pageant\n  pscp: pscp\n...\n```\nFlatpak builder can take the new section and build the following section in the app `metadata` file:\n\n```\n[Commands]\nputty=putty\nputtygen=puttygen\npsftp=psftp\npageant=pageant\npscp=pscp\n```\nUpon installation, other than showing supported aliases among the current requested permission screen, Flatpak could generate a set of wrapper scripts (analogous to the ones already present in `/var/lib/flatpak/exports/bin/`) with a few key changes: These wrappers would automatically append a `--command` flag for each exported internal binary, save the wrapper script using the designated alias name, and provide built-in support for `--file-forwarding` by detecting existing file arguments and wrapping them in `@@` delimiters.\n\n```\n#!/bin/sh\nfor arg do\n    shift\n    if [ -e \"$arg\" ]; then\n        set -- \"$@\" \"@@\" \"$(readlink -f \"$arg\")\" \"@@\"\n    else\n        set -- \"$@\" \"$arg\"\n    fi\ndone\nexec /usr/bin/flatpak run --branch=master --arch=x86_64 --command=\"putty\" --file-forwarding uk.org.greenend.chiark.sgtatham.putty \"$@\"\n```\nThe Flatpak command could then be extended to include subcommands for enabling or disabling specific aliases, or configuring whether new applications can automatically export aliases by default. Graphical management tools, such as system Settings or Flatseal, could integrate a dedicated control panel, similar to the one in Windows, to simplify alias management for users.\n\n## A Unified Path Forward for Desktop and CLI\n\nAs desktop Linux continues to gain mainstream attention, the differences between GUI applications and CLI utilities becomes increasingly important. While Flatpak laid the foundations to solve fragmentation and security challenges of graphical software, extending those same principles of sandboxing and distribution-agnostic delivery to command-line tools requires an implementation change.","body_html":"<h2 id=\"package-management-from-the-beginning\">Package management, from the beginning</h2>\n<p>One of the features Linux had way before its competition was the ability to download applications from online repositories, which would later be called an &quot;app store&quot;. Before this, you would have to download the application binaries and libraries, or build it yourself from the source code, making sure you already had all the required dependencies to compile the application. To solve this issue, package managers like &quot;APT&quot; and &quot;DNF&quot; were developed. On the surface, the task may seem simple: download, install, update, and remove applications. Under the hood, however, a package manager must handle complex operations: downloading the requested application along with all required libraries, checking dependency availability, resolving conflicts, extracting files to the disk, and running any optional post-installation scripts. Once a program was installed, it could be run by clicking on the new icon that appeared, or if the program was placed in <code>/bin/</code> or another path in the system <code>$PATH</code> variable, by typing the name of the executable.</p>\n<p>As time moved on, new requirements emerged for package managers: distribution-agnostic support and enhanced security through application sandboxing. Because every distribution family had its own package manager, it quickly became obvious that maintaining packages for multiple distributions was time-consuming for developers, and impossible for distribution maintainers to package every available application. Additionally, as security threats increased, it became necessary to isolate untrusted applications from the system, including legitimate software that might be exploited by malware. Access to documents, peripherals, and other aspects of the system needed to be restricted, granting temporary usage only with explicit user permission.</p>\n<p>One of these package managers with a new approach is Flatpak.</p>\n<p>Flatpak tries to solve both issues by radically changing the packaging and distribution model. It allows developers to ship applications in a layered format that includes all necessary dependencies, working across all distributions, and runs them inside a sandbox. Flatpak provides two kinds of permissions: static permissions declared in the manifest, and dynamic permissions requested at runtime through portals exposed over D-Bus.</p>\n<p>This format quickly became the mainstream, default, or even the only way in some distributions to install graphical applications via the software store. However, command-line applications were left behind, and for good reason. Sure, a few CLI-only tools exist, such as flatpak-builder (the tool used to build new Flatpaks), but developers tend to avoid packaging them. Furthermore, as we&#39;ll see, their usage from the command line... is rather difficult!\nIf we had installed Flatpak Builder from our distribution&#39;s repository with a classic package, we would launch it with <code>flatpak-builder build-folder manifest.yaml</code>. However, when installed as a Flatpak itself, the command becomes <code>flatpak run org.flatpak.Builder build-folder manifest.yaml</code>.\nNot only does the command become longer and require the full &quot;app id&quot; (which consist of a &quot;unique three-part identifier&quot;, pinpointing both the developer and the application), but also requires the filesystem sandbox to be disabled!</p>\n<p>In the meantime, <code>flatpak run</code> got a new <code>--file-forwarding</code> option, which maps a specified file from the command line (expressed in the arguments between the <code>@@</code> delimiters) inside the sandbox to make it available to the application. However, this approach still has a catch.</p>\n<p>Adding the required option and enclosing the file path with <code>@@</code> doesn&#39;t help at all with the command length, but more importantly doesn&#39;t work with directories or non-existent files you may want to create (such as when converting a picture, where the second file path would be the output file)</p>\n<h2 id=\"windows-10-and-the-universal-windows-platform\">Windows 10 and the Universal Windows Platform</h2>\n<p>Other operating systems encountered the exact same issues regarding application distribution and sandboxing. Windows took a drastic approach: rather than improving the classic Win32 desktop stack, it created an entirely new platform. Even though the technology was initially quite immature, it laid the foundation to distribute &quot;APPX&quot; software through the Windows Store alongside sandboxing via AppContainer.</p>\n<p>Soon, developers would realize that migrating from Win32 created a massive workload in trying to port applications to the new platform-and it was not always possible due to the technical limitations of UWP. So in a later update to Windows, the Desktop Bridge was introduced.</p>\n<p>Among the new features, many of which centered on packaging in the &quot;APPX&quot; format existing Win32 desktop applications, a series of improvements was added to run both UWP and Win32 apps more easily from the command line.</p>\n<p>Of course, not every app supported this feature, as it required developers to update the application manifest by adding the <code>uap3:AppExecutionAlias</code> extension and specifying the name of the exported executable outside the sandbox. This would create a special 0-byte execution alias inside <code>%LOCALAPPDATA%\\Microsoft\\WindowsApps</code>, which is included in the user&#39;s PATH variable. This file relies on an NTFS reparse point tagged with <code>IO_REPARSE_TAG_APPEXECLINK</code>. When executed, Windows reads this reparse data and launches the actual binary from the restricted <code>C:\\Program Files\\WindowsApps</code> directory within its designated application container. An application can export multiple aliases, and the alias name doesn&#39;t have to match the executable file inside the container.</p>\n<p>Because these aliases sit in a directory that is included in the user&#39;s PATH variable, they can sometimes cause conflicts. A classic example is typing python into CMD and unexpectedly opening the Microsoft Store rather than launching the Python version you manually installed from the python website.</p>\n<p>To solve this issue, the system provides a simple interface to view all aliases exported by installed applications, along with toggles to disable them. When an alias is turned off, Windows simply deletes that 0-byte reparse point from the <code>%LOCALAPPDATA%\\Microsoft\\WindowsApps</code> directory. With the file gone, the shell continues searching the rest of the user&#39;s PATH.</p>\n<h2 id=\"a-solution-for-flatpak\">A solution for Flatpak</h2>\n<p>Flatpak development could take inspiration from the Windows approach. A suggested solution would consist of multiple small changes. The first would be adding an <code>export-commands</code> key to the Flatpak manifest, mapping internal executable paths to exported command aliases. This approach allowes developers to create wrapper files with complex names inside the package and exporting them with simple names.</p>\n<pre><code>app-id: uk.org.greenend.chiark.sgtatham.putty\nruntime: org.freedesktop.Platform\nruntime-version: &#39;26.08&#39;\nsdk: org.freedesktop.Sdk\nrename-desktop-file: putty.desktop\nrename-icon: putty\ncommand: putty\nexport-commands:\n  putty: putty\n  puttygen: puttygen\n  psftp: psftp\n  pageant: pageant\n  pscp: pscp\n...</code></pre>\n<p>Flatpak builder can take the new section and build the following section in the app <code>metadata</code> file:</p>\n<pre><code>[Commands]\nputty=putty\nputtygen=puttygen\npsftp=psftp\npageant=pageant\npscp=pscp</code></pre>\n<p>Upon installation, other than showing supported aliases among the current requested permission screen, Flatpak could generate a set of wrapper scripts (analogous to the ones already present in <code>/var/lib/flatpak/exports/bin/</code>) with a few key changes: These wrappers would automatically append a <code>--command</code> flag for each exported internal binary, save the wrapper script using the designated alias name, and provide built-in support for <code>--file-forwarding</code> by detecting existing file arguments and wrapping them in <code>@@</code> delimiters.</p>\n<pre><code>#!/bin/sh\nfor arg do\n    shift\n    if [ -e &quot;$arg&quot; ]; then\n        set -- &quot;$@&quot; &quot;@@&quot; &quot;$(readlink -f &quot;$arg&quot;)&quot; &quot;@@&quot;\n    else\n        set -- &quot;$@&quot; &quot;$arg&quot;\n    fi\ndone\nexec /usr/bin/flatpak run --branch=master --arch=x86_64 --command=&quot;putty&quot; --file-forwarding uk.org.greenend.chiark.sgtatham.putty &quot;$@&quot;</code></pre>\n<p>The Flatpak command could then be extended to include subcommands for enabling or disabling specific aliases, or configuring whether new applications can automatically export aliases by default. Graphical management tools, such as system Settings or Flatseal, could integrate a dedicated control panel, similar to the one in Windows, to simplify alias management for users.</p>\n<h2 id=\"a-unified-path-forward-for-desktop-and-cli\">A Unified Path Forward for Desktop and CLI</h2>\n<p>As desktop Linux continues to gain mainstream attention, the differences between GUI applications and CLI utilities becomes increasingly important. While Flatpak laid the foundations to solve fragmentation and security challenges of graphical software, extending those same principles of sandboxing and distribution-agnostic delivery to command-line tools requires an implementation change.</p>","headings":[{"level":2,"text":"Package management, from the beginning","id":"package-management-from-the-beginning"},{"level":2,"text":"Windows 10 and the Universal Windows Platform","id":"windows-10-and-the-universal-windows-platform"},{"level":2,"text":"A solution for Flatpak","id":"a-solution-for-flatpak"},{"level":2,"text":"A Unified Path Forward for Desktop and CLI","id":"a-unified-path-forward-for-desktop-and-cli"}]}}