Skip to main content

max / alloy_tui

Browser: swap Floorp for upstream Firefox + optional ungoogled-chromium Floorp's rough edges and ESR-based cadence lag were paying more cost than the fork-specific configurability was worth. Upstream Firefox with an enterprise policies.json captures the actual value (visual + behavioral config) at less cost: - firefox RPM baked into the image via dnf (Fedora main). - etc/firefox/policies/policies.json force-installs uBlock Origin and locks telemetry / Pocket / Firefox Home / user messaging off at the policy layer. - usr/share/alloy/firefox/{user.js,userChrome.css} carry per-profile UX prefs and the Helium-style compact chrome (same tokens as before). - ungoogled-chromium is documented as opt-in Flathub Flatpak, not baked; covers the "I need Blink" case without making it the default. - alloy-flatpak-firstboot.service drops Floorp; only Rnote remains. STACK.md rewritten; IMAGE.md, todo.md, preset comment, and incidental Floorp mentions updated.
Co-Authored-By
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-18 14:34 UTC
Signed with PGP, not checked
Commit: 5f98e0e0bf4233761a84fc02288fd44ad78ec8c5
Parent: 39b99c7
8 files changed, +111 insertions, -73 deletions
M Containerfile +5 -3
@@ -75,7 +75,7 @@
75 75 # Package additions — full Alloy stack per docs/STACK.md
76 76 #
77 77 # Sources noted per group. Anything absent from both Fedora main and
78 - # Terra is either handled via Flatpak (Rnote, Floorp) or downloaded
78 + # Terra is either handled via Flatpak (Rnote) or downloaded
79 79 # directly (Nerd Fonts).
80 80 # =====================================================================
81 81 RUN dnf install -y \
@@ -119,7 +119,9 @@
119 119 adw-gtk3-theme \
120 120 # Screenshot capture + region-select (sway has no built-in grab)
121 121 grim slurp \
122 - # Flatpak client (Flathub + Floorp/Rnote install at first boot)
122 + # Browser (Gecko default; ungoogled-chromium is opt-in Flatpak per docs/STACK.md)
123 + firefox \
124 + # Flatpak client (Flathub + Rnote install at first boot)
123 125 flatpak \
124 126 # Font tools
125 127 unzip fontconfig \
@@ -167,7 +169,7 @@
167 169 || true
168 170
169 171 # =====================================================================
170 - # Flathub + Floorp + Rnote — deferred to first boot
172 + # Flathub + Rnote — deferred to first boot
171 173 # =====================================================================
172 174 # bootc prefers /var empty at build time; `flatpak remote-add` and
173 175 # `flatpak install --system` both write to /var/lib/flatpak, which
M docs/IMAGE.md +1 -1
@@ -73,7 +73,7 @@
73 73 7. **Branding:** os-release, plymouth splash.
74 74 8. **Validation:** `bootc container lint` runs at build.
75 75
76 - Fedora Flatpaks (Floorp specifically) are installed system-wide in the image via `flatpak install --system flathub`, with the Flathub remote added first. This trades image size for zero-friction first-boot — user reboots into Alloy, opens Floorp, done.
76 + The base browser (Firefox) ships as an RPM baked into the image — one code path, no first-boot delay, and enterprise policies (`/etc/firefox/policies/policies.json`) take effect immediately. Rnote and any other Flathub-only apps are installed system-wide on first boot via `alloy-flatpak-firstboot.service`, which adds the Flathub remote and pulls the apps — an image-size / first-boot-latency trade Alloy accepts for tools without clean RPM sources.
77 77
78 78 ## Update cadence
79 79
M docs/STACK.md +21 -16
@@ -120,26 +120,31 @@
120 120
121 121 ## Browser
122 122
123 - **Floorp.** Firefox fork by Ablaze, Gecko-based, ships as Flatpak on Flathub. Picked over baseline Firefox because Floorp exposes materially more visual configurability through its own settings (density, tab layout, workspaces) without needing extensions, and picked over any Chromium fork because Alloy should not reinforce the Chromium monoculture — browser-engine diversity is load-bearing for the web, and Alloy shipping Gecko is a small vote in the right direction.
123 + **Firefox (upstream) baked in as the default; ungoogled-chromium available as an opt-in Flatpak.** Alloy's identity work happens at the engine level, not the fork level, so upstream Firefox is the right base — no ESR lag, no fork-specific patch drift, the most-tested Gecko build shipping. Alloy owns the visual and behavioral layer via three files:
124 124
125 - Alloy preconfigures Floorp with:
126 - - Helium-style ultra-compact horizontal chrome (thin tab strip, compact address bar, no title bar, no menu bar, no bookmarks bar).
127 - - Alloy light-mode tokens applied via `userChrome.css` — Flatwhite-adjacent warm cream from the same H=80, C=0.012 ramp used everywhere else (see [TOKENS.md](TOKENS.md)).
128 - - Telemetry, Pocket, studies, sponsored tiles, and new-tab feed content off.
129 - - Blank new tab, DuckDuckGo search suggestions off, formfill off (browser is not a password manager).
130 - - No vertical tabs — horizontal only, per firm preference.
125 + - `/etc/firefox/policies/policies.json` — enterprise policy. Pins **uBlock Origin** as a force-installed, update-locked extension. Disables telemetry, Pocket, studies, sponsored tiles, new-tab feed, formfill, and password saving at the policy layer (higher-precedence than user prefs).
126 + - `usr/share/alloy/firefox/user.js` — user-profile prefs. Backs up the policy kills for the settings not exposed to enterprise policy, and configures compact UI density, blank new tab, DuckDuckGo suggestions off, quiet scroll.
127 + - `usr/share/alloy/firefox/userChrome.css` — Helium-style ultra-compact horizontal chrome (thin tab strip, compact address bar, no title bar, no menu bar, no bookmarks bar), using Alloy's light-mode tokens (H=80, C=0.012 ramp from [TOKENS.md](TOKENS.md)).
131 128
132 - Config lives at [`usr/share/alloy/floorp/`](../usr/share/alloy/floorp/) — `user.js` for prefs, `chrome/userChrome.css` for chrome overrides, and a README explaining install and verification.
129 + Runs all modern sites (uBlock Origin blocks ads, never JS). Horizontal tabs only, per firm preference. Config lives at [`usr/share/alloy/firefox/`](../usr/share/alloy/firefox/) and [`etc/firefox/policies/`](../etc/firefox/policies/) with a README explaining install and verification.
130 +
131 + **Ungoogled-chromium** is offered as the second-engine escape valve for the rare site that only renders correctly under Blink, and for users who prefer Chromium ergonomics without Google telemetry. Not baked into the ISO. Install path:
132 +
133 + ```
134 + flatpak install flathub io.github.ungoogled_software.ungoogled_chromium
135 + ```
136 +
137 + No Alloy config is shipped for it. The point is a working Chromium engine on demand, not a second identity surface.
133 138
134 139 Accepted costs:
135 - - **userChrome.css drifts** across Firefox major versions. Alloy owns the theme; re-verify after each Floorp major release. Bounded work (a few selectors per bump).
136 - - **Floorp release cadence** lags upstream Firefox slightly (ESR-based). Security patches arrive a beat later. Trade accepted for the configurability.
137 - - **Fallback:** if Floorp stalls or drifts weirdly, Alloy falls back to plain Firefox + the same `userChrome.css`. The user-visible difference is smaller than it looks because Alloy owns the visual layer.
140 + - **userChrome.css drifts** across Firefox major versions. Alloy owns the theme; re-verify after each Firefox major release. Bounded work (a few selectors per bump).
141 + - **uBlock Origin pinning** is Alloy's enterprise policy, so Firefox will refuse to let the user disable or uninstall it via the extensions UI. Users who need to disable it can edit `/etc/firefox/policies/policies.json` themselves; Alloy documents the location.
138 142
139 143 Rejected:
140 - - **Chromium and any Chromium fork** (Brave, Vivaldi, Helium, Arc, Zen-if-it-were-Chromium). Alloy doesn't reinforce browser-engine monoculture.
141 - - **LibreWolf.** Stronger privacy defaults but less visual configurability than Floorp; the visual work would still need to happen and LibreWolf isn't friendlier to it.
142 - - **Zen Browser.** Gecko-based and design-forward, but the identity centers vertical tabs and sidebar-forward layout, which conflicts with the horizontal-tabs preference. Revisit only if Zen ships a first-class horizontal mode.
144 + - **Floorp.** Was the previous pick. Rough edges in daily use, ESR-based cadence lags Firefox security patches, fork-specific patches add drift Alloy doesn't own. Upstream Firefox with policies + userChrome.css captures the actual value (visual and behavioral configurability) at less cost.
145 + - **LibreWolf.** Ships uBlock Origin preinstalled — real win — but its hardening (`resistFingerprinting`, letterboxing, cookie clears on close, WebGL off) breaks modern sites. Un-hardening it to pass Alloy's "runs all modern sites" bar erases the reason to choose it over Firefox.
146 + - **Zen Browser.** Gecko-based and design-forward, but its identity centers vertical tabs and sidebar-forward layout. Revisit only if Zen ships a first-class horizontal mode as a supported configuration.
147 + - **Chromium as default, Brave, Vivaldi, Arc, Helium.** Alloy doesn't reinforce browser-engine monoculture. Ungoogled-chromium covers the "I need Blink" case without making it the default.
143 148
144 149 ## Shell
145 150
@@ -250,7 +255,7 @@
250 255
251 256 ### Media keys: **playerctl**
252 257
253 - C, MPRIS client. CLI. No config — sway binds media keys directly to `exec playerctl play-pause` and similar. Handles Spotify, mpv, Firefox/Floorp, and any MPRIS-compliant source.
258 + C, MPRIS client. CLI. No config — sway binds media keys directly to `exec playerctl play-pause` and similar. Handles Spotify, mpv, Firefox, and any MPRIS-compliant source.
254 259
255 260 Rejected: playerctld (still a playerctl variant), no serious alternative.
256 261
@@ -280,7 +285,7 @@
280 285
281 286 Config at [`etc/skel/.config/gtk-3.0/`](../etc/skel/.config/gtk-3.0/) and [`etc/skel/.config/gtk-4.0/`](../etc/skel/.config/gtk-4.0/) with matching `gtk.css` and `settings.ini` per version.
282 287
283 - **What this covers:** any GTK 3 or GTK 4 app that consumes libadwaita's named tokens — swayosd (GTK-rendered overlays), Floorp's system dialogs, cosmic-files if GTK-based, etc.
288 + **What this covers:** any GTK 3 or GTK 4 app that consumes libadwaita's named tokens — swayosd (GTK-rendered overlays), Firefox's system dialogs, cosmic-files if GTK-based, etc.
284 289
285 290 **What this doesn't cover:**
286 291 - Legacy GTK 3 apps with their own token sets (rare — most have migrated).
@@ -7,10 +7,13 @@
7 7 # - tailscaled: opt-in only. Enrollment happens via `alloy tail`
8 8 # (see docs/CONTINUITY.md — Alloy does not phone home
9 9 # before the user says yes).
10 - # - alloy-flatpak-firstboot: adds flathub and installs Floorp + Rnote
11 - # the first time the machine reaches multi-user with
12 - # network. Kept out of the build so /var stays empty
13 - # at image-build time (bootc lint requirement).
10 + # - alloy-flatpak-firstboot: adds flathub and installs Rnote the first
11 + # time the machine reaches multi-user with network. Kept
12 + # out of the build so /var stays empty at image-build
13 + # time (bootc lint requirement). Firefox is the default
14 + # browser and ships in the base image via dnf, so no
15 + # Flatpak involvement there; ungoogled-chromium is
16 + # user-installed on demand (see docs/STACK.md).
14 17 #
15 18 # Format: `enable|disable <unit>`. First match wins; entries without
16 19 # a match fall through to /usr/lib/systemd/system-preset/ defaults.
@@ -1,5 +1,5 @@
1 1 [Unit]
2 - Description=Alloy first-boot Flatpak provisioning (Floorp, Rnote)
2 + Description=Alloy first-boot Flatpak provisioning (Rnote)
3 3 Documentation=file:///usr/share/alloy/README
4 4 After=network-online.target
5 5 Wants=network-online.target
@@ -9,7 +9,7 @@
9 9 Type=oneshot
10 10 RemainAfterExit=yes
11 11 ExecStart=/usr/bin/flatpak remote-add --system --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
12 - ExecStart=/usr/bin/flatpak install --system --noninteractive --or-update flathub one.ablaze.floorp com.github.flxzt.rnote
12 + ExecStart=/usr/bin/flatpak install --system --noninteractive --or-update flathub com.github.flxzt.rnote
13 13 ExecStart=/usr/bin/mkdir -p /var/lib/alloy
14 14 ExecStart=/usr/bin/touch /var/lib/alloy/flatpak-firstboot.done
15 15
@@ -1,7 +1,11 @@
1 - // Alloy Floorp preferences
1 + // Alloy Firefox preferences
2 2 //
3 - // Loaded on every Floorp startup; overrides values in prefs.js.
4 - // See docs/STACK.md ("Terminal / Browser" section) for context.
3 + // Loaded on every Firefox startup; overrides values in prefs.js.
4 + // See docs/STACK.md ("Browser" section) for context.
5 + //
6 + // Higher-precedence policy kills (telemetry, Pocket, extension pinning,
7 + // password saving, etc.) live in /etc/firefox/policies/policies.json.
8 + // This file covers per-profile UX prefs the policy layer doesn't expose.
5 9
6 10 // -------------------------------------------------------------------
7 11 // Enable userChrome.css / userContent.css loading
@@ -27,8 +31,8 @@
27 31 user_pref("browser.tabs.firefox-view-next", false);
28 32
29 33 // Explicitly no vertical tabs.
30 - user_pref("floorp.browser.tabs.verticaltab", false);
31 34 user_pref("sidebar.verticalTabs", false);
35 + user_pref("sidebar.revamp", false);
32 36
33 37 // -------------------------------------------------------------------
34 38 // New tab / home page — blank
@@ -43,45 +47,7 @@
43 47 user_pref("browser.newtabpage.activity-stream.feeds.snippets", false);
44 48
45 49 // -------------------------------------------------------------------
46 - // Telemetry off
47 - // -------------------------------------------------------------------
48 - user_pref("toolkit.telemetry.enabled", false);
49 - user_pref("toolkit.telemetry.unified", false);
50 - user_pref("toolkit.telemetry.archive.enabled", false);
51 - user_pref("toolkit.telemetry.newProfilePing.enabled", false);
52 - user_pref("toolkit.telemetry.shutdownPingSender.enabled", false);
53 - user_pref("toolkit.telemetry.updatePing.enabled", false);
54 - user_pref("toolkit.telemetry.bhrPing.enabled", false);
55 - user_pref("toolkit.telemetry.firstShutdownPing.enabled", false);
56 - user_pref("datareporting.healthreport.uploadEnabled", false);
57 - user_pref("datareporting.policy.dataSubmissionEnabled", false);
58 - user_pref("browser.ping-centre.telemetry", false);
59 - user_pref("browser.newtabpage.activity-stream.telemetry", false);
60 - user_pref("browser.newtabpage.activity-stream.feeds.telemetry", false);
61 -
62 - // -------------------------------------------------------------------
63 - // Studies, experiments, Pocket
64 - // -------------------------------------------------------------------
65 - user_pref("app.shield.optoutstudies.enabled", false);
66 - user_pref("app.normandy.enabled", false);
67 - user_pref("app.normandy.api_url", "");
68 - user_pref("extensions.pocket.enabled", false);
69 - user_pref("extensions.pocket.api", "");
70 - user_pref("extensions.pocket.site", "");
71 -
72 - // -------------------------------------------------------------------
73 - // Privacy defaults
74 - // -------------------------------------------------------------------
75 - user_pref("browser.contentblocking.category", "strict");
76 - user_pref("privacy.donottrackheader.enabled", true);
77 - user_pref("privacy.globalprivacycontrol.enabled", true);
78 - user_pref("browser.formfill.enable", false);
79 - user_pref("signon.rememberSignons", false); // browser is not a password manager
80 - user_pref("browser.safebrowsing.malware.enabled", true); // keep this on
81 - user_pref("browser.safebrowsing.phishing.enabled", true);
82 -
83 - // -------------------------------------------------------------------
84 - // Search — DuckDuckGo default
50 + // Search — DuckDuckGo default; suggestions off
85 51 // -------------------------------------------------------------------
86 52 user_pref("browser.search.suggest.enabled", false);
87 53 user_pref("browser.urlbar.suggest.searches", false);
@@ -90,6 +56,14 @@
90 56 user_pref("browser.urlbar.trending.featureGate", false);
91 57 user_pref("browser.urlbar.weather.featureGate", false);
92 58
59 + // -------------------------------------------------------------------
60 + // Privacy defaults not covered by enterprise policy
61 + // -------------------------------------------------------------------
62 + user_pref("browser.contentblocking.category", "strict");
63 + user_pref("privacy.donottrackheader.enabled", true);
64 + user_pref("privacy.globalprivacycontrol.enabled", true);
65 + user_pref("browser.formfill.enable", false);
66 +
93 67 // -------------------------------------------------------------------
94 68 // Miscellany — reduce noise
95 69 // -------------------------------------------------------------------
@@ -1,7 +1,7 @@
1 1 /*
2 - * Alloy Floorp chrome — Helium-style ultra-compact horizontal, Flatwhite-adjacent
2 + * Alloy Firefox chrome — Helium-style ultra-compact horizontal, Flatwhite-adjacent
3 3 *
4 - * Applies Alloy's light-mode tokens (see docs/TOKENS.md) to Floorp's chrome
4 + * Applies Alloy's light-mode tokens (see docs/TOKENS.md) to Firefox's chrome
5 5 * and slims the tab strip, address bar, and toolbar to their smallest
6 6 * legible form. No vertical tabs. No bookmarks toolbar. No title/menu bar.
7 7 *
@@ -43,8 +43,8 @@
43 43 /* Bookmarks toolbar off — keyboard-driven, invoke via Ctrl-B if needed. */
44 44 #PersonalToolbar { display: none !important; }
45 45
46 - /* Floorp side-service bar off — no vertical UI on the side. */
47 - #sidebar-box[sidebarcommand="viewFloorpNotebookSidebar"] { display: none !important; }
46 + /* Sidebar off — no vertical UI on the side. */
47 + #sidebar-box { display: none !important; }
48 48 #sidebar-splitter[hidden="false"] { display: none !important; }
49 49
50 50 /* -------------------------------------------------------------------
@@ -1,0 +1,54 @@
1 + {
2 + "policies": {
3 + "ExtensionSettings": {
4 + "uBlock0@raymondhill.net": {
5 + "installation_mode": "force_installed",
6 + "install_url": "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi",
7 + "default_area": "menupanel",
8 + "updates_disabled": false
9 + }
10 + },
11 + "DisableTelemetry": true,
12 + "DisableFirefoxStudies": true,
13 + "DisablePocket": true,
14 + "DisableFormHistory": true,
15 + "DisableMasterPasswordCreation": true,
16 + "DisableFirefoxAccounts": false,
17 + "PasswordManagerEnabled": false,
18 + "OfferToSaveLogins": false,
19 + "DontCheckDefaultBrowser": true,
20 + "DisableProfileImport": true,
21 + "DisableSetDesktopBackground": true,
22 + "NetworkPrediction": false,
23 + "SearchSuggestEnabled": false,
24 + "PromptForDownloadLocation": false,
25 + "NewTabPage": false,
26 + "FirefoxHome": {
27 + "Search": true,
28 + "TopSites": false,
29 + "SponsoredTopSites": false,
30 + "Highlights": false,
31 + "Pocket": false,
32 + "SponsoredPocket": false,
33 + "Snippets": false,
34 + "Locked": true
35 + },
36 + "UserMessaging": {
37 + "WhatsNew": false,
38 + "ExtensionRecommendations": false,
39 + "FeatureRecommendations": false,
40 + "UrlbarInterventions": false,
41 + "SkipOnboarding": true,
42 + "MoreFromMozilla": false,
43 + "Locked": true
44 + },
45 + "OverrideFirstRunPage": "",
46 + "OverridePostUpdatePage": "",
47 + "EnableTrackingProtection": {
48 + "Value": true,
49 + "Locked": false,
50 + "Cryptomining": true,
51 + "Fingerprinting": true
52 + }
53 + }
54 + }