Ferry ships as one Arch package, ferry, built from this checkout with pkgbuild/PKGBUILD.
| File | What |
|---|---|
pkgbuild/PKGBUILD |
Builds ferryd and ferry from the checkout (no source tarball). |
pkgbuild/ferry.install |
The messages pacman prints after install, upgrade and removal. |
dist/systemd/ferryd.service |
The user unit, installed to /usr/lib/systemd/user/. |
dist/ufw/ferry |
The ufw application profile ferry (4243/udp), installed to /etc/ufw/applications.d/. |
dist/ferry.desktop |
The launcher entry "Ferry", installed to /usr/share/applications/; it runs ferry ui arrange. |
plugin/ |
The omarchy-shell plugin ferry.bar, installed to /usr/share/ferry/plugin/; ferry setup links it. |
bin/install |
makepkg -fsi in pkgbuild/. |
scripts/pkg/check.sh |
What can be proven about a built package without root. |
scripts/pkg/dry-package.sh |
package() without a build: the file list and the plugin checks in seconds. |
scripts/pkg/expected-files.sh |
The list of files the package holds, which both scripts above compare with. |
Exactly this (scripts/pkg/expected-files.sh is the list the checks use):
/usr/bin/ferry
/usr/bin/ferryd
/usr/lib/systemd/user/ferryd.service
/usr/share/ferry/plugin/ the omarchy-shell plugin: manifest.json and its QML
/usr/share/applications/ferry.desktop the launcher entry (opens the Arrange panel)
/etc/ufw/applications.d/ferry (a backup file: pacman keeps your edits)
/usr/share/licenses/ferry/LICENSE
/usr/share/licenses/ferry/NOTICE
The plugin folder is plugin/ of the checkout without its developer README, root-owned and with no
symlink inside it (omarchy plugin validate refuses one). A package cannot touch $HOME, so
ferry setup links the folder into ~/.config/omarchy/plugins/ferry.bar and puts the widget on the
bar (see "The plugin step" below). No udev rule and no module config ship (decision brief A4).
The workspace also holds the M0 spikes; they are not built into the package.
depends are glibc, gcc-libs, libxkbcommon (the binaries link it) and systemd: the binaries
are Qt-free Rust. The plugin needs the Omarchy shell it is made for, which
every Omarchy machine has; it is not a depends, like ufw and xdg-desktop-portal-hyprland,
which are optdepends because Omarchy already has both.
bin/install # makepkg -fsi in pkgbuild/; pacman asks for sudo
ferry setup # as your user, not root; asks before each stepbin/install builds in pkgbuild/src/ (git-ignored), so a second run is an incremental build.
makepkg without -s and -i builds the package and installs nothing:
cd pkgbuild && makepkg -f # writes pkgbuild/ferry-<ver>-<rel>-<arch>.pkg.tar.zst (.xz where PKGEXT says so)
BUILDDIR=/tmp/fb PKGDEST=/tmp/fp makepkg -f # same, with nothing landing in the checkout
scripts/pkg/check.sh [PKG] # file list, unit, linkage, version, baseline CPU, namcapcheck() runs cargo test --frozen --release --workspace so the tests must not need a
compositor, a network or a lab VM. To skip the tests on a rebuild, makepkg -f --nocheck.
scripts/pkg/dry-package.sh runs package() with two empty executables for the binaries and compares
what it installs with the expected list, in a few seconds and with no build: use it after any edit
of the PKGBUILD or of plugin/. It also validates ferry.desktop (desktop-file-validate) and the
plugin (omarchy plugin validate), and checks that the plugin's id is ferry.bar and its version is
the workspace version.
Plain x86-64. The build never sets a target CPU: no target-cpu=native, no .cargo/config.toml.
makepkg's own RUSTFLAGS (/etc/makepkg.conf.d/rust.conf) is only -C force-frame-pointers=yes.
The same binary must run on x86-64-v2 CPUs such as the Celeron N3060. scripts/pkg/check.sh
checks the configuration and starts both binaries under a Nehalem CPU (qemu-x86_64-static).
That proves startup only: ring picks its AVX code paths at run time from cpuid.
On aarch64 the package is built the same way (arch=('x86_64' 'aarch64')) and the Nehalem run is
skipped; a package runs only on the arch it was built on.
One version. [workspace.package] version in the top Cargo.toml is the only version
. Every crate takes it with version.workspace = true; pkgver is read from it; the
build fails if ferry --version or ferryd --version says anything else. To release, change
that one line (and pkgrel=1), and commit.
ferry setup has one step for the bar plugin, the first of six. It makes two changes and asks once:
- The link
~/.config/omarchy/plugins/ferry.bar->/usr/share/ferry/plugin, the wayjankeesvw.meeting-recorderis linked on an Omarchy machine. A link that points elsewhere (a checkout under development) or a real directory of that name is yours: setup says so, leaves it alone and still does the second change. Then it asks the shell to look at its plugin directory again (omarchy-shell -q shell rescanPlugins, best effort). - The entry
{ "id": "ferry.bar" }inbar.layout.rightof~/.config/omarchy/shell.json, right after the tray (or after the plugin that took the tray's place, such asmy.tray), as the shell's ownomarchy plugin enablewould put it. Only that element is inserted into the text: every other byte of the file stays, and a backupshell.json.ferry-bak.<time>is made first. A cloned bar (bar.idismy.bar) changes nothing: every bar readsbar.layout. A file that the shell would not read (not JSON, no"version": 1, nobar.layout) is not touched: setup printsomarchy plugin enable ferry.bar --section rightinstead. With noshell.jsonat all, setup starts one from the shell's default ($OMARCHY_PATH/config/omarchy/shell.json), because a valid user file replaces the default whole and a file with only Ferry in it would empty the bar.
A second run reports the step as skipped. ferry setup --undo takes the entry out (every section) and
removes the link if it is the one setup made. --dry-run shows both changes and writes nothing.
A unit in ~/.config/systemd/user/ wins over /usr/lib/systemd/user/. ferry setup therefore
treats the two cases apart:
- Package installed, no user copy: setup runs
systemctl --user enable --now ferrydand writes no unit. It says(using the packaged unit /usr/lib/systemd/user/ferryd.service). - Package installed, and a user copy that
ferry setupwrote earlier (it starts with the# Written byferry setup`` line, and itsExecStart=names the old build): the copy would keep starting the old `ferryd`. Setup shows the plan and asks once: `systemctl --user disable --now ferryd`, delete the copy, `daemon-reload`, `enable --now ferryd`. The next `ferry setup` run skips the step. - Package installed, and a unit you wrote yourself at that path: setup never touches it. It says
that your file shadows the packaged unit and that you can delete it.
ferry doctorshows the same as aunitwarning (... shadows the packaged /usr/lib/systemd/user/ferryd.service). - No package: as before, setup writes the user copy with
ExecStart=set to theferrydnext to theferrythat ran it.
git pull # or switch branch
bin/install # pkgrel stays 1; -f overwrites the package file
systemctl --user restart ferryd # the running ferryd is still the old binary
ferry doctorpacman prints the restart line from post_upgrade. A package cannot restart a user's daemon:
it runs as root and cannot reach the user manager. ferry doctor warns on the daemon row when
the running ferryd's version differs from ferry --version, with the restart line as the fix.
A rebuild of the same pkgver (a new pkgrel, or new code under the same version) looks
identical to doctor, so restart it by hand then. Upgrade both machines to the same build: mixed versions
are not tested yet.
ferry setup --undo # as your user: takes the widget off the bar, unlinks the plugin,
# stops and disables ferryd, prints the Hyprland and ufw lines to remove
sudo pacman -R ferryAdd --purge to ferry setup --undo to revoke trusted peers and delete keys, config and state.
Take the printed lines out of ~/.config/hypr/ yourself, and run sudo ufw delete allow ferry
if you opened the port. If you removed the package first, ferry is gone: pacman's post_remove
message lists the steps by hand (systemctl --user disable --now ferryd, daemon-reload, rm of the
plugin link, the ferry.bar entry in shell.json, the ferry.lua require line, the ufw rule). The
shell cannot disable a plugin it no longer knows, so that entry is taken out of shell.json by hand.
Removal does not touch your home directory, and pacman -R keeps a
changed /etc/ufw/applications.d/ferry as .pacsave.