The client side of the Omarchy integration (#428 was the host side). Three user-visible things, all verified on the testbox:
Super+Space → type a host's name → enter → stream. One managed block in omarchy-menu.jsonc: a punktfunk submenu (merging with the host tool's block by reused ids, which the extension format documents), Open Punktfunk, the couch console, one connect row per saved host, and wake rows where a MAC is known. Opt-in via punktfunk-client --omarchy-menu on or the new preferences switch; off removes exactly our block.
Both client surfaces follow the theme, live. The GTK shell recolours libadwaita's named palette; the Skia console builds its field, ink and accent from the same four values. A 2 s poll each (the web console's interval, for the same reason: ~/.local/state/omarchy/current is a symlink that omarchy-theme-set re-points, which a file monitor on the resolved path cannot follow).
A client-only box needs zero setup. The shared reader (pf_client_core::omarchy) prefers our rendered punktfunk.json and falls back to the theme's native colors.toml, which every Omarchy box has. The template stays a host-side, web-console concern.
One switch rules both surfaces: follow_os_theme (default on), its row shown only where a theme is actually published — availability, not platform, so Android can feed one later without a row edit. The console hides its Background picker while the system theme rules it.
Rejected paths
Dynamic menu rows via the extension provider field. The header advertises it, but Menu.qml (4.0.1) resolves providers only against a map baked into the shell — fonts, power-profiles, apps. An extension naming anything else is silently ignored. Hence static rows kept true instead: trust::KnownHosts::save() calls the sync, and save is the one door every store mutation walks through — GTK pairing, the couch console, the CLI — followed by omarchy-menu refresh.
A picker row (gum/fzf into --connect). Per-host rows beat a two-step picker, and the search bar finds them by name, which was the point.
Registering the theme template for clients. Host-side consent machinery for values colors.toml already carries.
A QML rewrite of the shell was ruled out earlier in the program; the GTK shell keeps its shape and only wears the colours.
The bug this branch found in the field
Both jsonc validators — punktfunk-omarchy's menu_is_valid and my Rust port — stripped // to end-of-line with no idea of strings. The deployed host block carries || echo https://localhost:47992inside an action string, so the host tool refused the very file it had written, and the client inherited the bug until the on-glass run caught it. Both now use the same string-aware scan (comments and trailing-comma forgiveness only outside strings); the doc comments in each point at the other.
Verification
Gate (pf-gtkflow, Xvfb): clippy -D warnings clean on pf-client-core, pf-console-ui, punktfunk-client-linux, punktfunk-client-session (--features ui); 257 + 231 + 9 tests plus the GTK display test green.
On glass (home-omarchy-1, Omarchy 4.0.1, over a live 240 fps stream): both surfaces flipped ethereal → flexoki-light → back mid-run with no restart; --add-host updated the menu block with no menu command (the save-hook, live); --omarchy-menu off returned omarchy-menu.jsoncbyte-identical to its pre-test backup; omarchy-menu refresh/ping ok, no shell journal errors.
The non-vacuity habit: the settings row test drives the real row_applies gating, the hostile-host-name test reads the label back through the parser, and the_theme_reaches_a_widget_through_the_app_stylesheet fails against libadwaita's own #3584e4 when the provider is withheld.
Surfaced but out of scope (host-side, recorded in the tracker-notes sense)
The theme switch's hyprctl reload reset the streamed head to a giant mode mid-stream on the testbox — the #437 re-apply either isn't in the deployed canary or didn't catch this; a client-window resize heals it.
"Punktfunk pairing request — 'a device'" toasts piled up during client probing and shell restarts; looks like reachability probes or watcher reconnects surfacing as pairing-request hook events.
Known limits: omarchy-menu refresh needs OMARCHY_PATH outside a session shell (we seed the packaged default); an in-stream overlay keeps the brand ink — only the console shell and the GTK app follow the theme; the light-theme contrast ceiling recorded for the web console (a theme whose own fg is ~5:1 on its bg) applies here too, softened by the 3:1 accent lift.
The client side of the Omarchy integration (#428 was the host side). Three user-visible things, all verified on the testbox:
- **`Super`+`Space` → type a host's name → enter → stream.** One managed block in `omarchy-menu.jsonc`: a `punktfunk` submenu (merging with the host tool's block by reused ids, which the extension format documents), *Open Punktfunk*, the couch console, one connect row per saved host, and wake rows where a MAC is known. Opt-in via `punktfunk-client --omarchy-menu on` or the new preferences switch; `off` removes exactly our block.
- **Both client surfaces follow the theme, live.** The GTK shell recolours libadwaita's named palette; the Skia console builds its field, ink and accent from the same four values. A 2 s poll each (the web console's interval, for the same reason: `~/.local/state/omarchy/current` is a symlink that `omarchy-theme-set` re-points, which a file monitor on the resolved path cannot follow).
- **A client-only box needs zero setup.** The shared reader (`pf_client_core::omarchy`) prefers our rendered `punktfunk.json` and falls back to the theme's native `colors.toml`, which every Omarchy box has. The template stays a host-side, web-console concern.
One switch rules both surfaces: `follow_os_theme` (default on), its row shown only where a theme is actually **published** — availability, not platform, so Android can feed one later without a row edit. The console hides its Background picker while the system theme rules it.
## Rejected paths
- **Dynamic menu rows via the extension `provider` field.** The header advertises it, but `Menu.qml` (4.0.1) resolves providers only against a map baked into the shell — `fonts`, `power-profiles`, `apps`. An extension naming anything else is silently ignored. Hence static rows kept true instead: `trust::KnownHosts::save()` calls the sync, and save is the one door every store mutation walks through — GTK pairing, the couch console, the CLI — followed by `omarchy-menu refresh`.
- **A picker row** (gum/fzf into `--connect`). Per-host rows beat a two-step picker, and the search bar finds them by name, which was the point.
- **Registering the theme template for clients.** Host-side consent machinery for values `colors.toml` already carries.
- **A QML rewrite of the shell** was ruled out earlier in the program; the GTK shell keeps its shape and only wears the colours.
## The bug this branch found in the field
Both jsonc validators — `punktfunk-omarchy`'s `menu_is_valid` and my Rust port — stripped `//` to end-of-line with no idea of strings. The deployed host block carries `|| echo https://localhost:47992` **inside an action string**, so the host tool refused the very file it had written, and the client inherited the bug until the on-glass run caught it. Both now use the same string-aware scan (comments and trailing-comma forgiveness only outside strings); the doc comments in each point at the other.
## Verification
- Gate (`pf-gtkflow`, Xvfb): `clippy -D warnings` clean on pf-client-core, pf-console-ui, punktfunk-client-linux, punktfunk-client-session (`--features ui`); 257 + 231 + 9 tests plus the GTK display test green.
- On glass (`home-omarchy-1`, Omarchy 4.0.1, over a live 240 fps stream): both surfaces flipped ethereal → flexoki-light → back mid-run with no restart; `--add-host` updated the menu block with **no** menu command (the save-hook, live); `--omarchy-menu off` returned `omarchy-menu.jsonc` **byte-identical** to its pre-test backup; `omarchy-menu refresh`/`ping` ok, no shell journal errors.
- The non-vacuity habit: the settings row test drives the real `row_applies` gating, the hostile-host-name test reads the label back through the parser, and `the_theme_reaches_a_widget_through_the_app_stylesheet` fails against libadwaita's own `#3584e4` when the provider is withheld.
## Surfaced but out of scope (host-side, recorded in the tracker-notes sense)
1. The theme switch's `hyprctl reload` reset the streamed head to a giant mode mid-stream on the testbox — the #437 re-apply either isn't in the deployed canary or didn't catch this; a client-window resize heals it.
2. "Punktfunk pairing request — 'a device'" toasts piled up during client probing and shell restarts; looks like reachability probes or watcher reconnects surfacing as pairing-request hook events.
Known limits: `omarchy-menu refresh` needs `OMARCHY_PATH` outside a session shell (we seed the packaged default); an in-stream overlay keeps the brand ink — only the console shell and the GTK app follow the theme; the light-theme contrast ceiling recorded for the web console (a theme whose own fg is ~5:1 on its bg) applies here too, softened by the 3:1 accent lift.
Every colour in the shell's own stylesheet already resolved through
libadwaita's named palette, so wearing the desktop's theme is a matter
of redefining those names -- not of touching a widget. Omarchy has been
rendering the four values on every theme switch since the host
integration landed, and until now only the web console read them.
Hex only. The surfaces are mixed out of the background/foreground pair,
so the numbers are needed anyway; GTK's CSS parser knows nothing of
oklch; and an unrendered template still holds its literal `{{ accent }}`,
which the same check is what refuses.
The accent is split, because libadwaita spends one name on accented text
and another on a fill. The fill keeps the theme's exact colour, and only
the text form is lifted toward the foreground until it reads at 3:1 --
several Omarchy light themes pick an accent that is handsome as a fill
and illegible as a label.
success, warning and destructive keep libadwaita's values: a theme with
a red accent must not make "Unpair" and "Connect" the same colour.
Colours only. The widget vocabulary stays Adwaita.
`--ignored` alone starts all three display tests in one process, and GTK
initialises once per process from one thread -- libtest gives each test
its own thread, `--test-threads=1` included. So whichever starts first
wins and the rest panic with "Attempted to initialize GTK from two
different threads". Each passes alone; the note said otherwise.
menu_is_valid stripped `//` to end-of-line with no idea of strings, so
the console row's own action -- it carries a https://localhost:47992
fallback -- was cut mid-string and the whole file refused as
unparsable. Found on the testbox: the script could no longer edit the
very file it had written.
The replacement scans character-wise, stripping comments and forgiving
trailing commas only OUTSIDE strings. The client mirrors the algorithm
in Rust (omarchy_menu::jsonc_parse); change one, change both.
The GTK shell already recoloured; this moves the reader into
pf-client-core and spends it twice more, so the console wears the theme
too and a client-only box needs no setup at all:
- The reader falls back to the theme's own colors.toml when our
rendered template is absent. Only host boxes render the template, and
a box that is only a screen was themed nowhere.
- The console gets a follow-system palette: a quiet field mixed from
the theme's own ground, ink and accent derived with the same 3:1 lift
the shell uses. The session binary polls the file every 2 s and
publishes on change; the shell's existing palette-rebuild seam does
the rest, so an omarchy-theme-set lands mid-session with no restart.
- One switch rules both surfaces: follow_os_theme, default on, its row
shown only where a theme is actually published -- and the console
hides its Background picker while the system theme rules it.
One managed block in omarchy-menu.jsonc: the punktfunk submenu (merging
with the host tool's block by reused ids), Open Punktfunk, the couch
console, and a connect row per saved host -- typing a host's name into
Super+Space and pressing enter starts the stream. Wake rows where a
MAC is known.
The menu cannot generate rows at runtime -- its provider field resolves
only against a map baked into the shell (verified in Menu.qml, Omarchy
4.0.1) -- so the rows are static and kept true instead:
KnownHosts::save calls the sync, and save is the one door every store
mutation walks through, in the GTK app, the couch console and the CLI
alike. omarchy-menu refresh repaints an open shell.
Opt-in (a preferences switch, or --omarchy-menu on); off removes
exactly our block -- on the testbox the file came back byte-identical.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The client side of the Omarchy integration (#428 was the host side). Three user-visible things, all verified on the testbox:
Super+Space→ type a host's name → enter → stream. One managed block inomarchy-menu.jsonc: apunktfunksubmenu (merging with the host tool's block by reused ids, which the extension format documents), Open Punktfunk, the couch console, one connect row per saved host, and wake rows where a MAC is known. Opt-in viapunktfunk-client --omarchy-menu onor the new preferences switch;offremoves exactly our block.~/.local/state/omarchy/currentis a symlink thatomarchy-theme-setre-points, which a file monitor on the resolved path cannot follow).pf_client_core::omarchy) prefers our renderedpunktfunk.jsonand falls back to the theme's nativecolors.toml, which every Omarchy box has. The template stays a host-side, web-console concern.One switch rules both surfaces:
follow_os_theme(default on), its row shown only where a theme is actually published — availability, not platform, so Android can feed one later without a row edit. The console hides its Background picker while the system theme rules it.Rejected paths
providerfield. The header advertises it, butMenu.qml(4.0.1) resolves providers only against a map baked into the shell —fonts,power-profiles,apps. An extension naming anything else is silently ignored. Hence static rows kept true instead:trust::KnownHosts::save()calls the sync, and save is the one door every store mutation walks through — GTK pairing, the couch console, the CLI — followed byomarchy-menu refresh.--connect). Per-host rows beat a two-step picker, and the search bar finds them by name, which was the point.colors.tomlalready carries.The bug this branch found in the field
Both jsonc validators —
punktfunk-omarchy'smenu_is_validand my Rust port — stripped//to end-of-line with no idea of strings. The deployed host block carries|| echo https://localhost:47992inside an action string, so the host tool refused the very file it had written, and the client inherited the bug until the on-glass run caught it. Both now use the same string-aware scan (comments and trailing-comma forgiveness only outside strings); the doc comments in each point at the other.Verification
pf-gtkflow, Xvfb):clippy -D warningsclean on pf-client-core, pf-console-ui, punktfunk-client-linux, punktfunk-client-session (--features ui); 257 + 231 + 9 tests plus the GTK display test green.home-omarchy-1, Omarchy 4.0.1, over a live 240 fps stream): both surfaces flipped ethereal → flexoki-light → back mid-run with no restart;--add-hostupdated the menu block with no menu command (the save-hook, live);--omarchy-menu offreturnedomarchy-menu.jsoncbyte-identical to its pre-test backup;omarchy-menu refresh/pingok, no shell journal errors.row_appliesgating, the hostile-host-name test reads the label back through the parser, andthe_theme_reaches_a_widget_through_the_app_stylesheetfails against libadwaita's own#3584e4when the provider is withheld.Surfaced but out of scope (host-side, recorded in the tracker-notes sense)
hyprctl reloadreset the streamed head to a giant mode mid-stream on the testbox — the #437 re-apply either isn't in the deployed canary or didn't catch this; a client-window resize heals it.Known limits:
omarchy-menu refreshneedsOMARCHY_PATHoutside a session shell (we seed the packaged default); an in-stream overlay keeps the brand ink — only the console shell and the GTK app follow the theme; the light-theme contrast ceiling recorded for the web console (a theme whose own fg is ~5:1 on its bg) applies here too, softened by the 3:1 accent lift.Every colour in the shell's own stylesheet already resolved through libadwaita's named palette, so wearing the desktop's theme is a matter of redefining those names -- not of touching a widget. Omarchy has been rendering the four values on every theme switch since the host integration landed, and until now only the web console read them. Hex only. The surfaces are mixed out of the background/foreground pair, so the numbers are needed anyway; GTK's CSS parser knows nothing of oklch; and an unrendered template still holds its literal `{{ accent }}`, which the same check is what refuses. The accent is split, because libadwaita spends one name on accented text and another on a fill. The fill keeps the theme's exact colour, and only the text form is lifted toward the foreground until it reads at 3:1 -- several Omarchy light themes pick an accent that is handsome as a fill and illegible as a label. success, warning and destructive keep libadwaita's values: a theme with a red accent must not make "Unpair" and "Connect" the same colour. Colours only. The widget vocabulary stays Adwaita.