Files
Panama/README.md
T
Gabriel Brown 3c359f3f7e Notice the battery, and the machine it is or is not in
Panama had no idea whether it was running on a laptop. No upower, no
battery, no lid, no AC: hypridle.conf says "This is a desktop" in its
own header, and that was true of the code as well as the machine.

panama-hw answers hardware questions one at a time, exits 0 or 1, and
prints nothing, so scripts, services and contracts all ask the same
way. The definition the rest of the laptop work hangs on is one line:
clamshell is lid-closed AND an external monitor. A machine with no
mains supply at all reports as being on wall power, because a desktop
cannot run out of it.

The battery service follows Vitals: sysfs through FileView, an
availability flag, and no subprocess on the timer. Globbing is the one
thing QML cannot do -- a battery is BAT0 or BAT1 or CMB0, mains is AC
or ADP1 or ACAD -- so panama-battery resolves the names once and the
shell reads the files directly after. Nothing falls back to a
plausible zero: a desktop shows no indicator, no card, and no charge
limit control where the firmware has no ceiling.

Also repairs two contracts that were already failing and had not been
noticed, because only the full suite runs them. The dependency
scanner treated line-initial variable assignments, case labels,
comments and heredoc bodies as commands, and `count`, `host`, `cancel`
and `import` are all real binaries on Fedora, so `command -v` could
not filter them out. It now drops comments and heredoc bodies and
requires a command to be followed by whitespace. Verified it still
catches a genuinely undeclared dependency rather than passing quietly.
The launcher command contract had not been told about the fourteen
commands added earlier today.
2026-08-21 21:43:14 -04:00

194 lines
9.8 KiB
Markdown

# Panama
Formerly Sunhat. A personal config for Fedora, with the intention of helping a
user set up their Fedora system with one command.
```sh
bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot)
```
`boot` installs git if the machine lacks it, clones this repository to
`~/.local/share/Panama` (or `$PANAMA_PATH`), and hands off to `install`. It is
deliberately small enough to read first, and the same two steps by hand work
identically:
```sh
git clone https://git.gbrown.org/gib/Panama.git ~/.local/share/Panama
~/.local/share/Panama/install
```
Both are safe to run again: an existing clone is fast-forwarded rather than
replaced, and `install` is the upgrade path.
`install` asks its questions first and then runs the stages in `setup/scripts/`
in order, without stopping again:
| Script | Does |
|---|---|
| `interview` | Every prompt, before anything is installed. Answers last one run and are never written to a durable path |
| `install-packages` | Repos (RPM Fusion, Terra, Hyprland COPR), the package lists in `setup/packages/`, then whichever optional categories were chosen |
| `link-dotfiles` | Symlinks `config/dot/<name>``~/.config/<name>`, and seeds the wallpaper, cursor theme and Firefox chrome |
| `change-settings` | Copies `config/copy/` over `/`, applies gsettings, enables user services |
| `link-vicinae-scripts` | Publishes the Vicinae script commands |
| `setup-identity` | git config, `gh auth login`, an SSH key — whichever were asked for |
| `install-hardware` | NVIDIA, Secure Boot enrollment, Fedora's extras, firmware — each only if it was asked for. Last, because enrollment and firmware are consumed at the next boot |
The run ends with a health summary from `panama-doctor`, which reports what is
actually running rather than what was attempted. It never fails the install: on a
fresh machine it legitimately reports things as not yet configured.
### Optional applications
Every machine gets the lists in `setup/packages/`. The interview also offers the
categories in `setup/packages/extras/` as a checklist, so a work laptop need not
acquire emulators and a desktop need not skip Steam. Nothing is preselected.
A category is one file. A bare line is a dnf package and a `flatpak:` line is a
Flathub ID, because the applications in a category do not all come from one
place. Adding a category is adding a file — the menu is read from the directory,
not written down anywhere.
Existing configs are moved to `config/old/` rather than overwritten.
## The desktop
Hyprland, with a shell written from scratch. It began as a replacement for a
GNOME session — Forge for tiling, Dash-to-Dock, Openbar, Vitals — and was built
to reproduce it closely enough that muscle memory transferred: same keybinds,
same panel contents, same dock, same Tokyo Night Moon palette.
That is history now rather than a second option. Panama installs and configures
one desktop, and the GNOME session it grew out of is neither installed nor
configured here. What each piece replaced is recorded in
[`config/dot/hypr/DESKTOP-PARITY.md`](config/dot/hypr/DESKTOP-PARITY.md) and in
the comments of the components themselves, because knowing what a thing was
modelled on explains why it behaves the way it does.
GNOME is not gone from the machine: `gnome-control-center` is a declared
dependency, and Panama's own Settings hands off to it for the panels it
deliberately does not own — Online Accounts, Color, Sound, Network, Keyboard,
Privacy, Wellbeing, Accessibility, and System for users, date and time, region
and remote desktop. The allow-list in
[`services/SystemSettings.qml`](config/dot/quickshell/services/SystemSettings.qml)
is what decides; anything not on it is a panel Panama owns itself.
| 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/containers/` | Container definitions systemd runs as units — currently the speech-to-text server behind dictation |
| `config/dot/vicinae/` | Raycast-style launcher, themed. Its commands live in `config/local/share/vicinae/` — script commands (settings deep links, power menu, reminders, window switcher, kill process, SSH hosts, recent files, color picker), and one compiled extension that adds web search with live suggestions. File search, calculator, clipboard, and emoji are Vicinae's own |
| `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`](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; `panama` is the entry point
config/
bash/ .bashrc, aliases, env (env is gitignored)
copy/ Files copied verbatim over / (needs sudo)
dot/ Symlinked into ~/.config
firefox/ Vendored Firefox chrome, linked into the browser profile
containers/ Quadlets, linked into ~/.config/containers/systemd
local/ Icons, the cursor theme, and the launcher's commands and
extensions, linked into ~/.local/share
old/ Backups of whatever was replaced (gitignored)
wallpapers/ Copied into ~/Pictures/Wallpapers when absent
setup/
apps/ Applications built from source, one file each
lib/ Shared by more than one stage; the extras catalog reader
packages/ One package per line; extras/ holds the optional categories
scripts/ Run in order by ./install
tests/ Contracts. See below
docs/ Settings reference, and the design specs behind the work
```
## Tests
138 of them, under `tests/`. Run the lot, or a subset by pattern:
```sh
panama test # everything
panama test dock # just the ones matching "dock"
tests/setup/interview-contract # or one directly; they are plain executables
```
They are called contracts rather than unit tests because that is what they are:
each one pins a decision that was expensive to get right and is cheap to undo by
accident. Most read or measure the real thing — launching a shell to measure a
surface's geometry, standing stub commands on `PATH` to see what a stage would
have installed, running a script against a throwaway `HOME` — rather than
asserting things about source text, because the bugs worth catching here have all
been ones that source text looked fine for.
```
tests/setup/ The installer: the interview, package lists, hardware, extras
tests/quickshell/ The shell and its settings pages
tests/hypr/ The compositor config
```
## Projects
A project is the set of windows you open together — which applications, which
workspace each was on, and for a terminal, which directory it was sitting in.
Arrange the desktop, then run **Save Layout as Project** from the launcher and
name it; **Open Project** lays it out again.
Workspaces are recorded as positions rather than numbers, and opening a project
claims free ones, so it never lands on top of what you are already doing. An
application that refuses to open twice — Slack, Thunderbird, the browser — is
moved into place rather than launched again. Saved layouts are listed on the
Desktop settings page, which is also where they are removed.
## The `panama` command
```sh
panama update # review, commit and sync this repo
panama edit # open it in Neovim
panama doctor # what is actually running, not what was installed
panama test # every contract, or a subset by pattern
panama upgrade # re-run ./install from anywhere
panama apps # choose applications to install, by category
panama app # applications no repository carries; build one by name
```
`panama apps` is the optional-application catalog, opened after the fact. The
interview offers the same categories during `./install`, whole; this picks a
category and then the applications inside it, so a machine can acquire Slack in
March without having wanted Discord in January. Both read
`setup/lib/extras-catalog`, so the two cannot describe different catalogues.
A category is one file under `setup/packages/extras/`. A bare line is a dnf
package, a `flatpak:` line is a Flathub id, `| Name` gives the menu something
readable, and an indented line belongs to the entry above it — which is how OBS
carries its sixteen plugin extensions as one thing to tick.
`panama-sudo` is pkexec with a stated reason: `panama-sudo --reason "why" --
command` shows the reason on Panama's password prompt, clearly labeled as an
unverified claim beside polkitd's own action text — meant for agents and
scripts, so the person typing the password learns why before they do. Without
a reason, a running shell, or `qs` it behaves exactly like pkexec.
`panama app` is deliberately not part of `./install`. Everything else Panama
installs comes from dnf or Flathub; these are built from source because no
packaged form exists, and a source build is slow, wants the network throughout,
and depends on an upstream that moves. That is the failure the interview exists
to prevent, so asking for one is something you do on purpose — and it is also
how you rebuild when a new version ships. Nothing is pinned: each build takes
the current upstream and reports a failure rather than working around it.
Adding one is adding a file to `setup/apps/`, and the file has to say why the
exception exists.
None of the scripts in this repository carry a `.sh` extension. A shebang and
the executable bit already select the interpreter, and the extension only
becomes something to keep in sync — which it did not stay.