Three bugs, all silent, all in the same feature. The write always worked. What failed was the refresh after it. That refresh is called from the mutation's own onExited handler and was guarded on `busy`, a binding over both processes -- and a binding hands back its cached value until the change notification feeding it has been delivered, which inside that handler has not happened yet. So `busy` read true, refresh returned immediately, and the page kept showing the old application with no error anywhere. Guards now read the Process objects directly, where the value is current, and a refresh is no longer blocked by the mutation that asked for it. The service also kept its own list of which roles it would accept. It stayed at seven when the helper and the page grew documents, text and archives, so choosing a PDF viewer set an error and changed nothing. It is derived from the snapshot now. And category matching never worked. DesktopEntries returns a QML list, for which Array.isArray is false, so the code stringified it into "Network,WebBrowser" and split on ";" alone -- one token matching no category. Browsers still appeared because their generic name contains "web browser" and the terms fallback carried the role by itself. Archives matched nothing at all, so that row could only ever offer the application it already had. The harness that should have caught the first bug passed while it was live: it set each role to the value it already had and asserted no error appeared, and the bug produces no error. It now changes a role to a genuinely different application, requires the service to observe the new value, and changes it back -- with the contract restoring the original from the outside however the run ends. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
Panama
Formerly Sunhat. A personal config for Fedora, with the intention of helping a user set up their Fedora system with one command.
git clone https://git.gbrown.org/gib/Panama.git ~/.local/share/Panama
~/.local/share/Panama/install
install runs everything in setup/scripts/ in order:
| Script | Does |
|---|---|
install-packages |
Repos (RPM Fusion, Terra, Hyprland COPR), then the four package lists in setup/packages/ |
link-dotfiles |
Symlinks config/dot/<name> → ~/.config/<name> |
change-settings |
Copies config/copy/ over /, applies gsettings, enables user services |
Existing configs are moved to config/old/ rather than overwritten.
Desktops
Panama configures two desktops that coexist. Both sessions stay available in GDM, so you can switch back and forth while you settle in.
GNOME
The original setup: Forge for tiling, Dash-to-Dock, Openbar, Vitals,
AppIndicator support. Configured through config/dot/forge/ and gsettings.
Hyprland
A from-scratch replacement built to reproduce the GNOME setup closely enough that muscle memory transfers — same keybinds, same panel contents, same dock, same Tokyo Night Moon palette.
| Piece | What it is |
|---|---|
config/dot/hypr/ |
Compositor config. Lua, not hyprlang — see its README |
config/dot/quickshell/ |
The shell: bar, dock, Continuum overview, Settings, Screen Intelligence, focus sessions, quick settings, notifications, screenshot UI |
config/dot/vicinae/ |
Raycast-style launcher, themed |
config/dot/uwsm/ |
Session environment (see the uwsm caveat in the hypr README) |
config/dot/wofi/ |
Fallback launcher, in case the shell fails to start |
config/dot/xdg-desktop-portal/ |
Portal backend routing |
Start here: config/dot/hypr/README.md — it
covers the Lua migration, the uwsm environment gotcha, the HDR decision, the
full keymap, and troubleshooting.
Log in as "Hyprland (uwsm-managed)", not plain "Hyprland".
Layout
bin/ Small user-facing commands on PATH
config/
bash/ .bashrc, aliases, env (env is gitignored)
copy/ Files copied verbatim over / (needs sudo)
dot/ Symlinked into ~/.config
old/ Backups of whatever was replaced (gitignored)
setup/
packages/ One package per line
scripts/ Run in order by ./install