Commit Graph
100 Commits
Author SHA1 Message Date
David Heinemeier Hansson cc9a3aadb3 Report live battery power draw 2026-07-20 16:37:33 -07:00
David Heinemeier Hansson af513d3206 Preserve power panel keyboard selection 2026-07-20 16:37:33 -07:00
David Heinemeier HanssonandClaude Opus 4.8 228b5ac3ba Give every hero toggle a keyboard focus ring
Each panel's hero on/off toggle (Tailscale, Dropbox Wi-Fi, Bluetooth,
network, audio mute) now has a reachable "header" cursor section, a focus
ring around the hero icon, Enter/Space activation, a letter shortcut, and
hover parity. The hero is inset by heroRingPad so the ring stays inside
the Flickable/ScrollView clip box instead of being cut off.

Bluetooth and audio get a virtual "header" section above their device
sections, so the adapter/mute can be toggled by keyboard even when no
device rows exist. Network repurposes its previously dead header section.

For the PanelHero-based panels (Tailscale, Dropbox), route panel state
through the wrapper's `header` id: inside a PanelHero iconComponent `root`
resolves to PanelHero, not the Panel, so `root.headerHasCursor` and
`root.setHeaderCursor()` silently referenced the wrong object.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 15:50:05 -07:00
David Heinemeier HanssonandClaude Fable 5 835181f112 Keep nudging Bluetooth discovery on while the panel is open
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 14:32:23 -07:00
David Heinemeier HanssonandClaude Fable 5 000fa2a972 Let the Tailscale panel toggle on and off like Dropbox
The hero icon is now the optimistic on/off toggle with a tooltip,
replacing the connect block and the progress lines beneath the hero.
The disconnected cross is drawn grey rather than red, and action
errors expire after a couple of seconds instead of sticking forever.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 14:26:19 -07:00
David Heinemeier HanssonandClaude Opus 4.8 a7c0d0f6a1 Let the Dropbox panel pause and resume syncing
Click the Dropbox hero icon to pause or resume the daemon (dropbox-cli
stop/start), with a tooltip on hover. When paused, both the hero and the
bar icon grey out and the phrase reads "Syncing paused". The greying is
optimistic so it reacts the instant you click, then reconciles with the
real daemon state once it settles (reverting if the command failed).

Also fix status.py's running detection, which was stuck reporting true:
this dropbox-cli inverts the `running` exit code and reports "isn't
running" (not "not running") when stopped, so the paused state never
showed. Detection now keys off the status text alone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 14:00:50 -07:00
David Heinemeier HanssonandClaude Fable 5 ff1d1c325e Suppress Hyprland reload errors for the whole quattro upgrade
Suppression was enabled only after cleanup_legacy_user_paths had already
moved ~/.local/share/omarchy aside, so the live session could auto-reload
during the swap window and pop "source= globbing error: found no match"
for every legacy hyprland.conf source line. Enable suppression as the
first step of the upgrade sequence instead; the EXIT trap still restores
it if the upgrade dies early.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 11:45:23 -07:00
David Heinemeier HanssonandClaude Fable 5 f96827c909 Simplify the quattro upgrade script
- Extract run_as_user_omarchy and run_as_user_wayland_session helpers to
  replace ten hand-rolled run_as_user env blocks
- Declare the retired user-unit list once instead of three times
- Use git ls-files --others to find user-added theme backgrounds instead
  of diffing against the tracked list by hand
- Stop rewriting the SDDM 10-theme/10-wayland confs the omarchy package
  already installs, and drop the duplicate [Theme] section from
  99-omarchy-login.conf
- Drop the legacy-path rewrite in the theme hyprland.conf shim; the user
  transition already rewrote those references
- Remove dead code: the unreachable channel re-validation, the declare -F
  guard in cleanup_on_exit, and the unset block at the end of the
  user-transition script

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 11:44:50 -07:00
David Heinemeier HanssonandClaude Fable 5 88d60e1468 Point gum prompts at the terminal in the quattro upgrade
The user-transition script is fed to bash on stdin, so the browser-close
gum confirm read the script itself: it auto-declined and swallowed the
remaining script text, leaving bash to fail on a mid-construct syntax
error. The outer confirm and reboot prompts had the same exposure when
the script runs via curl | bash. Read all three from /dev/tty.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 11:39:50 -07:00
David Heinemeier HanssonandClaude Fable 5 4f1b1fceb8 Pass the --yes flag into the quattro user transition
The Copy URL shortcut repair checked the outer script's yes variable,
which never reached the user-transition heredoc's bash process, so the
upgrade died with "yes: unbound variable" under set -u whenever a
browser was running with the old extension id in its Preferences.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 11:26:33 -07:00
David Heinemeier Hansson 8719b0d031 Fix pending migration notifications 2026-07-20 11:07:44 -07:00
David Heinemeier HanssonandClaude Fable 5 5232505c12 Don't block the desktop on network-online at boot
graphical.target was gated on network-online.target: cups-browsed orders
itself After=network-online.target and sits in multi-user.target, so the
session waited for NetworkManager-wait-online (DHCP/Wi-Fi association)
before coming up. On the bench VM that was ~140ms, but it's the classic
multi-second boot stall on real Wi-Fi.

Mask NetworkManager-wait-online.service so network-online.target is
reached immediately and nothing in the boot waits for connectivity;
NetworkManager still comes up and cups-browsed browses once the link is
live. Mirrors the existing systemd-networkd-wait-online mask. Enabled at
install (enable-services.sh) and masked on existing installs via
migration.

Verified on a fresh boot: the graphical.target critical chain no longer
passes through network-online.target / NetworkManager-wait-online.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 10:34:26 -07:00
David Heinemeier HanssonandClaude Opus 4.8 86fd228cda Refresh gum theming when launching presentation terminals
gum_env.lua is fed into the compositor environment via hl.env at login,
but that environment is captured once and is not refreshed on a theme
switch. Terminals launched through uwsm-app inherit the caller's
environment (scopes don't read systemctl --user set-environment), so a
floating terminal would show the login-time theme's gum colors.

Extract the export logic into a sourced omarchy-restart-gum helper and
source it from the presentation terminal launcher so gum widgets match
the active theme.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 09:44:48 -07:00
David Heinemeier HanssonandClaude Fable 5 e85cde2c9c Don't autostart the print-queue applet
system-config-printer ships /etc/xdg/autostart/print-applet.desktop, so
installing it for the printer GUI also starts a ~24 MiB Python tray applet
in every session whose only job is print-job notifications. Override it
with a Hidden=true entry in config/autostart (same mechanism already used
for fcitx5 and limine-snapper-notify), so the applet no longer autostarts.
Printing and the system-config-printer GUI are unaffected.

Verified: with the override in place, systemd's xdg-autostart generator no
longer produces app-print\x2dapplet@autostart.service.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 09:19:35 -07:00
David Heinemeier HanssonandClaude Fable 5 9314c12718 Test that the clamshell poll is gated to docked laptops
Guards the dock-gating in omarchy-hyprland-monitor-watch: the poll runs
only when omarchy-hw-laptop and an external monitor are both present, via
sync_poll_state, with the event loop fed by process substitution so it
can start/stop the poll. Behaviourally simulated (stubbed hw checks +
synthetic monitor events): the poll runs only while docked and stops on
undock; a desktop or undocked laptop never polls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 09:03:26 -07:00
David Heinemeier HanssonandClaude Fable 5 f1237e1962 Drive media play-order off MPRIS signals instead of polling
The media service ran a 500ms repeat timer calling syncPlayingOrder() for
the whole session — two CPU wakeups a second even with nothing playing.
syncPlayingOrder only depends on the set of MPRIS players and each
player's isPlaying state, both of which the Mpris service already signals.

Replace the timer with onPlayersChanged (players appearing/disappearing)
plus an Instantiator that connects isPlayingChanged for each live player,
and a Component.onCompleted for the initial sync.

Verified with a test MPRIS player: play/pause and player add/remove all
update the active player with no periodic timer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 08:33:00 -07:00
David Heinemeier HanssonandClaude Fable 5 d548b730e0 Only run the clamshell poll while docked, not for every laptop
The reconciliation poll (added in "Fix clamshell display recovery") is a
backstop for lid transitions the Hyprland switch binds can miss across
suspend/resume. But the internal panel is only ever disabled while the
laptop is docked — lid shut with an external monitor active — so the poll
has nothing to reconcile when undocked. Running it 24/7 on every laptop
wakes the CPU every 2s for no reason, which is exactly the case where
battery matters most.

Start the poll when an external monitor is present and stop it when the
last one goes away (driven by the socat monitor-add/remove watch), gated
on omarchy-hw-laptop. Undocked laptops and desktops now never poll; a
docked laptop keeps the 2s recovery poll. Switch the event reader from a
pipe to process substitution so it runs in the main shell and can manage
the poll's lifetime.

Desktop verified: no poll runs even with external monitors attached. The
docked-laptop start/stop path needs a check on real laptop hardware.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 08:15:09 -07:00
David Heinemeier HanssonandClaude Fable 5 63f147ef85 Only run the clamshell poll on laptops
omarchy-hyprland-monitor-watch ran poll_clamshell_state() every 2s for
the whole session, and each pass forks omarchy-hyprland-monitor-clamshell
plus its hyprctl/jq/monitor-* children. Clamshell (lid) handling can only
ever apply to a machine with a lid, so on desktops and VMs this was pure
churn — the single largest remaining source of idle process wakeups
(~3 forks/sec on an otherwise idle desktop).

Gate the poll behind a new omarchy-hw-laptop helper (lid button, or a
laptop DMI chassis type as a fallback). The event-driven socat watch on
Hyprland monitor add/remove is unchanged, so monitor hotplug still
reconciles everywhere; only the periodic lid poll is now laptop-only.

Verified on a desktop: steady-state omarchy-hyprland-* forks drop from
~3/sec to zero, socat watch still present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 08:09:07 -07:00
David Heinemeier HanssonandClaude Fable 5 ad023413c6 Derive the network bar pill from the native Networking service
The pill was populated by polling omarchy-network-status (previously
every 3s, then 10s). Derive kind/signalStrength directly from the
Quickshell.Networking service instead: wired-connected → ethernet
(preferred, matching the default-route device), else a connected Wi-Fi
network → wifi with its signal, else disconnected. The service's
properties are change-notified, so the pill updates on connect/
disconnect and signal changes with no polling and no subprocess.

Removes the last periodic poll from the bar; the label/frequency pill
fields were write-only and are dropped.

Verified live: pill tracks ethernet → disconnected → ethernet in real
time as the wired device goes down and up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 07:56:43 -07:00
David Heinemeier HanssonandClaude Fable 5 a64d895a02 Spawn shell subprocesses with bash -c instead of bash -lc
Each `bash -lc` starts a login shell that re-sources the profile
(mise activation, /etc/profile.d) on every invocation — ~16 forks per
call versus ~2 for `bash -c` — which taxes every menu/panel/launcher
action the shell shells out for. The session already exports PATH and
env to the shell, so omarchy commands resolve fine under `bash -c`.

Switch the internal/omarchy-owned spawns (theme+background switches,
brightness, monitor scaling, DNS, lock/fingerprint, keyboard-layout
probe, voxtype status, and the `:`/printf state-file writes) to
`bash -c`. Leave `bash -lc` on the sites that run user-configurable
commands (custom bar-widget exec, menu provider/guard scripts,
launcher scan commands, configurable idle/screensaver command), where
a user's command may rely on their login environment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 22:46:27 -07:00
David Heinemeier HanssonandClaude Fable 5 4d630c9f30 Stop polling monitor/network state on an idle desktop
The monitor panel polled `omarchy-monitor-state` every 5s (26 forks per
call) and the network panel polled `omarchy-network-status` every 3s,
both with `running: true` rather than gating like the sibling panels.

Monitor: gate the poll on `opened` (brightness/scale are only shown in
the open panel, which already refreshes on open) and drive the bar glyph
from Quickshell.screens instead of the polled display list, so monitor
count stays correct without polling.

Network: the bar pill needs live-ish state, so keep polling but at 10s
instead of 3s. (Deriving the pill from the native Networking service
would remove the poll entirely; left as a follow-up since it needs Wi-Fi
state testing.)

Idle fork rate drops ~20/s to ~14/s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 22:46:27 -07:00
David Heinemeier HanssonandClaude Fable 5 f619c397f2 Make status indicators event-driven instead of polling
The indicators widget broadcast a refresh every 2s, fanning out to four
status subprocesses (nightlight, idle, reminder, screen-recording), and
NightLight/StayAwake each ran an additional 5s poll. On an idle desktop
this was the dominant source of process churn (~33 of ~53 forks/sec in a
VM). The state-changing commands already push `omarchy.indicators
refresh` over IPC, so the polling was redundant.

Drop the 2s broadcast and the two 5s timers; indicators now refresh at
startup and on the IPC push. Also fix three callers that pushed to the
wrong target `Indicators` instead of `omarchy.indicators` (screen
recording, notification silencing, and the omarchy-shell help example) —
those pushes silently failed and only appeared to work because the poll
masked them.

Idle fork rate drops ~53/s to ~20/s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 22:46:27 -07:00
David Heinemeier HanssonandClaude Fable 5 ca4b0b3b61 Stop polling the background symlink every 100ms
The background plugin ran a 100ms Timer that spawned a readlink
subprocess ~10x/sec for the life of the shell, purely to notice
wallpaper changes. Wallpaper updates already arrive over IPC
(omarchy-theme-bg-set calls `background set`, omarchy-theme-set calls
`background themeTransition`), and the initial wallpaper is read once
in Component.onCompleted, so the poll was redundant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 22:46:27 -07:00
David Heinemeier HanssonandClaude Fable 5 b87de89372 Stop the migration notifier from busy-looping the session
omarchy-update-user-notify.path used PathExistsGlob= on the packaged
migrations directory. That directive is level-triggered: systemd re-checks
it every time the triggered unit deactivates and fires again while the glob
still matches. Since applied migrations stay on disk forever (state lives in
~/.local/state/omarchy/migrations), the glob always matches, so the oneshot
notifier re-triggered itself in a tight loop (~26-66 starts/sec) — burning
about a core and flooding the journal for the whole session.

The loop existed since the unit was introduced, but the default start-rate
limit killed it after 5 iterations, taking the .path unit down with
'unit-start-limit-hit'. That symptom was reported as #6174 and fixed
yesterday by setting StartLimitIntervalSec=0 — which removed the only brake
and turned the capped hiccup into an unbounded busy-loop.

Fix the actual cause instead:

* Drop PathExistsGlob= from the .path unit, keeping the edge-triggered
  PathModified= watch for updates that land mid-session.
* Revert the StartLimitIntervalSec=0 override; with the level trigger gone
  there is no self-re-fire to trip the limit, and the default limit is a
  useful backstop again.
* Preserve the once-per-login pending check the glob used to provide by
  giving the service its own WantedBy=graphical-session.target, enabled at
  first-run alongside the other user units.
* Add a migration that daemon-reloads, revives a rate-limit-killed .path,
  restarts the watcher, and enables the login-time notifier on existing
  installs.

Verified with transient path/service units: the old config runs the service
200 times in 3 seconds; the new config runs it zero times while idle and
exactly once when a new migration file lands.

Thanks to @HANCORE-Linux for finding and diagnosing the problem.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:49:41 -07:00
David Heinemeier HanssonandClaude Fable 5 844859a000 Always overwrite unowned strays under /usr/share/omarchy on update
The tree is wholly package-owned, but files can land there unowned
(in-place extension work, script-written files), and pacman then aborts
the entire upgrade on the file conflict — as happened when copy-url's
service worker was renamed to background-2.js. The conflict check runs
before any hooks or scriptlets, so the package itself can't recover;
the update command has to allow the overwrite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:31:10 -07:00
David Heinemeier HanssonandClaude Fable 5 f3878b341c Share a single power profile parser between list and set
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:29:15 -07:00
David Heinemeier HanssonandClaude Fable 5 d211de2ffc Match Wi-Fi first-run notification format to the other invitations
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:17:04 -07:00
David Heinemeier HanssonandClaude Fable 5 e96163c075 Give glyph notifications with bodies the large icon slot
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:17:04 -07:00
David Heinemeier HanssonandClaude Fable 5 54d79d9d16 Fix screen flash when waking from sleep into the unlock screen
The lock service arms a 5s blank timer whenever the screen locks, and
input at the lock screen re-arms it. Closing the lid sprays pointer
noise over the lock surface, so the timer was routinely armed right
before suspend, froze mid-countdown, and fired moments after resume --
blanking the freshly woken unlock screen under the user.

Guard the timer with a wall-clock check: if far more time elapsed than
the interval, the countdown slept through a suspend, so take a fresh
run-up instead of blanking. This also blanks the lock screen 5s after
an untouched resume.

Two accomplices made the flash worse and hid the real bug:

- The clamshell watcher's 2s poll fired an unconditional global DPMS
  enable whenever no external monitor was active, relighting any blank
  within 2 seconds (lock-screen blanking never stuck on undocked
  laptops) and racing the resume modeset. Recovery now only wakes
  displays when it actually re-enables one.

- Every keystroke at the lock screen dispatched a redundant DPMS
  enable via omarchy-system-wake, forcing extra modesets in the
  fragile just-resumed DRM state. Brightness "on" now skips the
  dispatch when every active display is already lit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:42:18 -07:00
David Heinemeier Hansson 324fd387c0 Convert two more themes that are a good fit to be generic 2026-07-19 19:07:07 -07:00
David Heinemeier HanssonandClaude Fable 5 4cbe47c14d Generate ristretto neovim/vscode configs from the colorset too
The colorset is the Monokai Pro Ristretto palette, so the generated
themes keep all the accent colors. Brightened muted to Monokai Pro's
actual comment color, since comments sit on that key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:07:07 -07:00
David Heinemeier HanssonandClaude Fable 5 cc4b92f367 Match Brave Origin refresh on binary path to avoid installer self-match
The stable Brave Origin's process is named plain "brave" (the wrapper
execs /opt/brave-origin-bin/brave), so pgrep -x brave-origin never
matches, and pgrep -f brave-origin also matches the installer's own
floating terminal - which made omarchy-install-browser launch a
headless browser and hang on first install.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:05:42 -07:00
David Heinemeier HanssonandClaude Fable 5 81217e5749 Generate vantablack neovim/vscode/btop configs from the colorset too
Tuned muted, dark_foreground, and lighter_background to the tiers the
explicit themes used, which also fixes muted falling back to pure white
in the generated terminal configs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 18:43:04 -07:00
David Heinemeier Hansson 3f2f2dd245 Can now generate these configs just from the expanded colorset 2026-07-19 18:37:25 -07:00
c442ad7d93 Make YouTube and Zoom webapps opaque on any browser and profile
Ports #6092 from master: the video-app opacity opt-out only matched
Chrome/Chromium on the default profile, so Brave, Edge, and non-default
profiles kept the translucent default-opacity styling.

Co-Authored-By: Zeus-Deus <github.commits@widow.cc>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 18:28:07 -07:00
a1e0875eb4 Pin browser password store to gnome-libsecret (#6065)
Chromium-based browsers auto-detect their os_crypt backend at launch. On
Hyprland the xdg-desktop-portal Secret backend has no provider, so the
autodetect can fall back to the 'basic' (v10) store, making previously
v11-encrypted cookies and saved passwords undecryptable — the user is
silently logged out of everything. Pin gnome-libsecret (the stock
omarchy keyring) so the backend is deterministic, matching what we
already do for VSCode.

Migration covers chromium, brave, chrome, and edge flags confs for
existing installs.

Co-authored-by: Niklas Tscheppe <ntscheppe@drgt.net>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 18:07:02 -07:00
David Heinemeier HanssonandClaude Fable 5 ddab62ea0d Only brace the expansions zsh misparses
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 17:48:17 -07:00
David Heinemeier Hansson d4d1b518e0 Remove redundant Hyprland launch wrapper
With initial workspace tracking disabled, windows naturally open on the active workspace. Remove the explicit Hyprland workspace dispatch and let shell actions, shell restarts, and presentation terminals launch directly.
2026-07-19 17:36:34 -07:00
David Heinemeier Hansson 146f73bf85 Don't need to have this much explaining 2026-07-19 17:28:00 -07:00
David Heinemeier HanssonandClaude Fable 5 12dc7ae558 Shrink lock screen password dots to fit the field
Long passwords used to overflow the input field and clip with no
feedback that typing was still registering. Scale the dot size and
letter spacing down as the password grows, like macOS, so every
keystroke stays visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 11:03:00 -07:00
David Heinemeier HanssonandJon Kinney ec9f8241c1 Fix power action terminal scope race
Co-authored-by: Jon Kinney <jonkinney@gmail.com>
2026-07-19 10:31:27 -07:00
1feb0250b4 Update Omarchy skill for Quattro's Lua configuration
The skill still described pre-Quattro .conf files and workflows, sending
agents to inactive config files and stale commands. Now covers the Lua
config layout, o.bind/hl.unbind/hl.monitor forms, .d hook directories
with omarchy hook install, plugin cloning, and corrected command routes.

Distilled from #6310.

Co-Authored-By: ssupt <149246609+ssupt@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:20:52 -07:00
David Heinemeier HanssonandClaude Fable 5 17c8af3f14 Simplify shell restart around quickshell instance management
omarchy-restart-shell now kills by config dir via quickshell kill and
relaunches with --no-duplicate, polling kill until every instance is
gone since kill returns without waiting and -n silently exits if one
remains. The locked-session refusal reads Hyprland monitor state alone,
which covers a hung shell holding the lock; the redundant shell IPC
probe, availability guards, and omarchy-shell path indirection are gone.

Shell IPC calls now time out (2s default, OMARCHY_SHELL_IPC_TIMEOUT to
override) so probing an unresponsive shell fails fast instead of
hanging the caller.

omarchy-hyprland-launch checks dispatch output for "ok" rather than the
exit code, which is 0 even on Lua errors, so a failed dispatch falls
through to the bash -lc fallback instead of silently launching nothing.

The Quattro upgrade cutover delegates to omarchy-restart-shell instead
of carrying its own copy of the lock check, pkill, and readiness loop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:09:54 -07:00
David Heinemeier HanssonandClaude Fable 5 3edf254a12 Translate tmux key notation back into readable hotkeys
Restore the key translation the awk parser used to do (C-M-S-Left →
CTRL + ALT + SHIFT + LEFT, PPage → PAGE UP, etc) as a display pass over
the tmux list-keys output, along with the PREFIX header line and the
COPY MODE table label.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:00:46 -07:00
David Heinemeier Hansson 008f3a2212 Fix Kitty terminal cwd detection 2026-07-19 09:59:13 -07:00
David Heinemeier HanssonandClaude Fable 5 0f2f3f11cb Remember power profile choices per power source across reboots
Explicit profile selections from the power panel or menu are now saved
under an ac/battery key in ~/.local/state/omarchy/powerprofiles and
reapplied on boot and on plug/unplug. Only successful, user-made
selections are persisted, so the performance/balanced defaults still
apply when nothing has been chosen.

All entry points key off the same power signal, UPower's OnBattery:
the shell reads it natively and omarchy-powerprofiles-set autodetect
queries it via busctl. This replaces the sysfs online checks, which
disagreed with the shell on desktops without power_supply entries and
lagged behind plug events on some USB-C laptops.

Plug/unplug switching moves from the udev rule into the shell's battery
service, which already receives UPower's debounced state changes, so
the udev rule and its settle-sleep workaround are gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 09:33:23 -07:00
David Heinemeier Hansson 6ba0e9c234 Fix monitor scaling down getting stuck at 3x due to floating point drift
Hyprland can report a scale set to 3 as something like 3.0000000000000004.
The previous directional comparison treated that as above the 3 preset, so
Super+Alt+Slash (scale down) would stay at 3 instead of reaching 2.

Snap the reported scale to the nearest preset first, then step up/down.
Add a regression test for the floating-point case.
2026-07-19 09:10:14 -07:00
David Heinemeier HanssonandClaude Fable 5 c030337cb6 Only bundle vconsole.conf in the initramfs for Latin keyboard layouts
Bundling vconsole.conf makes Plymouth apply the user's layout at the LUKS
prompt, but for layouts whose letter keys aren't Latin (Hebrew, Greek,
Cyrillic, Arabic, ...) that makes the necessarily-Latin passphrase
untypeable and locks the user out of their machine.

mkinitcpio sources its conf.d drop-ins as shell, so omarchy_hooks.conf now
checks XKBLAYOUT at every rebuild and only bundles the file for Latin
layouts; non-Latin layouts keep the US fallback the passphrase was set
under. A migration strips the unconditional line and rebuilds the UKI on
affected installs.

Closes #6229.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 09:04:09 -07:00
David Heinemeier HanssonandGitHub 7bfb8cf954 Not where we keep doc links 2026-07-19 08:12:43 -07:00
David Heinemeier Hansson 73efa7d926 Remove stale nofile config during Quattro upgrade 2026-07-18 21:42:00 -07:00
David Heinemeier Hansson be4a9ed6dd Move Tmux keybindings to menu end 2026-07-18 21:33:10 -07:00
David Heinemeier Hansson 7b5c915c8c Clear bar move outline on release 2026-07-18 21:23:09 -07:00
David Heinemeier Hansson 6742adce3d Focus weather city input on return 2026-07-18 21:19:14 -07:00
David Heinemeier Hansson be1aab859d Prevent weather icon flicker 2026-07-18 21:19:10 -07:00
David Heinemeier Hansson c7952c980f Synchronize weather hero icon 2026-07-18 21:11:52 -07:00
David Heinemeier HanssonandClaude Fable 5 afa2839a5a Rename bg/fg palette keys to background/foreground
The canonical colors.toml keys are now background/foreground, including
all permutations (dark_background, darker_background, lighter_background,
dark_foreground, light_foreground, bright_foreground). The old short
names are gone entirely, not kept as aliases; legacy alacritty-generated
themes still resolve through the ANSI color0/color7 fallback.

Theme files are also regrouped: accent/selection/muted first, then the
backgrounds, then the foregrounds, then the named colors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 16:24:51 -07:00
David Heinemeier HanssonandClaude Fable 5 72d7646c64 Add SSHD setup and removal under Setup/Remove > Security
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 16:09:03 -07:00
David Heinemeier HanssonandClaude Fable 5 fa2b997513 Keep software-composited cursors out of screenshots
Hyprland falls back to compositing the cursor into the frame on GPUs
without working hardware cursors, so grim would capture it. Force
hardware cursors for the duration of the capture and restore after.

Closes #6142

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 15:42:01 -07:00
David Heinemeier HanssonandClaude Fable 5 96bb617a9c Match Mullvad hosts by suffix
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:56:46 -07:00
David Heinemeier Hansson 1620b3467b Refresh applications during Quattro upgrade 2026-07-18 12:56:46 -07:00
1024bf5e7a Backfill pre-quattro hardware support and tmux fixes for existing installs
Existing quattro installs get sof-firmware, the Mesa Vulkan drivers,
the tmux terminal-features and pane-binding fixes, and the XPS 13 text
scaling via migration, while Omarchy 4 upgraders get the same hardware
support and scaling through omarchy-upgrade-to-quattro.

The Vulkan driver backfill adapts da46ad85 from master.

Co-authored-by: Sai Sridhar <tarrasridhar1154@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:31:34 -07:00
David Heinemeier HanssonandClaude Fable 5 46df0cf495 Nudge XPS 13 text scaling down just ever so slightly
The 2560x1600 panel on the 2026 XPS 13 (DX13260) renders the default
scaling a touch large. Ports f1fa7f69 from master.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:31:25 -07:00
David Heinemeier HanssonandClaude Fable 5 804d138909 Widen sof-firmware install to all Intel SOF audio platforms
The sof-audio-pci-intel-* driver family needs sof-firmware to boot the
DSP, but mainline linux only optdeps it, so affected installs came up
with a Dummy Output sink only. Replace the Panther Lake check with
omarchy-hw-intel-sof, which detects any Intel PCI audio controller.

Ports ffa81021 from master, which adapts basecamp/omarchy#6200.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:31:25 -07:00
David Heinemeier HanssonandClaude Fable 5 2f081f57b2 Append the kitty extkeys terminal feature instead of overwriting slot 3
Ports efcd7805 from master.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:31:03 -07:00
David Heinemeier HanssonandClaude Fable 5 a4c13bdefb Make package removal match exact installed names only
pacman -Q resolves provider names, so dropping a virtual package could
remove whichever package provides it. Read pacman -Qq once and match
requested names exactly, ignoring providers and duplicate arguments.
Ports the provider-ignoring semantics of 9791b227 from master with a
single pacman query instead of one per package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:31:03 -07:00
David Heinemeier HanssonandClaude Fable 5 f7152cac17 Remove dropped bsnes2014 and mame2016 RetroArch cores
libretro-bsnes2014 and libretro-mame2016 no longer exist in the repos,
which made the whole retroarch install fail. Ports fe30a07d from master.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:30:54 -07:00
David Heinemeier HanssonandGitHub d39c791e68 Merge pull request #6236 from basecamp/fix-clamshell-dpms-wake
Fix internal laptop screen re-lighting itself 2sec after locking
2026-07-18 12:09:04 -07:00
David Heinemeier HanssonandClaude Fable 5 9aa1dcd664 Drag the bar to move it, drop the config panel
Position the bar by dragging (or click-and-holding) empty bar space
toward a screen edge, with a ghost slab previewing the target edge.
With drag for position and double-click for transparency, the bar
config panel, its inline gear button, and the omarchy-launch-bar-settings
CLI are no longer needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:44:35 -07:00
David Heinemeier Hansson 66cdec78c2 Align bar settings control spacing 2026-07-18 10:56:19 -07:00
David Heinemeier Hansson 52ecb4eaf7 Equalize bar status icon spacing 2026-07-18 10:51:14 -07:00
David Heinemeier Hansson b39313abcf Simpler finish 2026-07-18 10:45:47 -07:00
David Heinemeier Hansson d0cc4b9674 More explicit clear 2026-07-18 10:40:43 -07:00
David Heinemeier Hansson 79e408b323 Clear before the logo 2026-07-18 10:33:02 -07:00
David Heinemeier Hansson 4d3165d8c1 Keep new browser windows on current workspace 2026-07-18 10:29:38 -07:00
David Heinemeier Hansson 4db7a03235 Let's try a logo 2026-07-18 10:26:55 -07:00
David Heinemeier Hansson 3f87af5ef4 Quote Omarchy paths in commands 2026-07-18 10:08:43 -07:00
David Heinemeier Hansson 8862fb22bd Use Omarchy command helpers consistently 2026-07-18 10:08:43 -07:00
David Heinemeier Hansson bd34704f7b Clarify privilege escalation guidance 2026-07-18 10:08:43 -07:00
David Heinemeier Hansson 77353e9670 Slim down celebration text 2026-07-18 10:03:15 -07:00
David Heinemeier Hansson 784996c378 Scale webcam overlay to monitor resolution 2026-07-17 18:28:44 -07:00
David Heinemeier Hansson ca0cf8bff9 Fix webcam resize controls and placement 2026-07-17 18:28:44 -07:00
David Heinemeier Hansson 1174f2a70b Add live webcam overlay sizing 2026-07-17 18:28:44 -07:00
David Heinemeier Hansson 0b7c440009 Use gum to prompt for consent 2026-07-17 18:27:32 -07:00
David Heinemeier Hansson 839fb547e3 Update the skill to talk about pkexec 2026-07-17 17:50:52 -07:00
David Heinemeier Hansson 73e5968c64 Show context in polkit prompt 2026-07-17 17:45:29 -07:00
David Heinemeier Hansson 28d853402e Make the Copy URL extension reliable across install and upgrade
The Copy URL extension was intermittently failing to copy anything, and
its notification looked oversized with no icon. Several distinct problems:

- The MV3 service worker was pinned to stale cached code. Chromium caches
  the worker script for a --load-extension command-line extension and does
  NOT re-register it when the file changes in place — not on restart, not on
  a manifest version bump, not even after a clean shutdown. So updated code
  never took effect: the old worker kept calling chrome.scripting.executeScript,
  which throws once the scripting permission is gone, and the copy silently
  failed. Renaming the worker to a versioned filename (background-2.js) is a
  new script URL, which forces a fresh registration for everyone — new
  installs and existing installs alike. Rename it again on any future worker
  change (see the note at the top of background-2.js).

- Clipboard writes now go through an offscreen document (MV3's sanctioned
  path) using a textarea + execCommand('copy'), replacing executeScript +
  navigator.clipboard. This works on chrome:// pages and needs no scripting
  permission. execCommand is used deliberately: navigator.clipboard.writeText
  rejects in an unfocused offscreen document.

- Add a toolbar action (chrome.action.onClicked) so the extension is
  clickable, not keyboard-only — it was greyed out in the extensions menu
  with nothing to invoke.

- Slim the "URL copied" notification: lead the summary with a glyph so the
  omarchy notification shell collapses it to a single-line toast with an
  icon, instead of an oversized card with a blank icon slot.

- Guard the Quattro shortcut-repair migration: it edits Chromium Preferences
  to move the Alt+Shift+L binding to the new extension id, but a running
  browser rewrites Preferences on exit and reverts the edit. Prompt (via gum)
  to close the browser first, only when a browser is running and there is
  actually a stale binding to repair.
2026-07-17 16:28:18 -07:00
David Heinemeier Hansson 182330465a Simplify omarchy-bar into a bar-settings and bar-plugin split
The omarchy-bar command had grown three overlapping ways to inspect the
bar (show/layout/list/options, plus selected/active/available/widgets
aliases) and mixed layout mutation in with bar-level settings. Untangle
it into two focused commands:

- omarchy-bar keeps only the bar-level settings that write shell.json:
  use, reset, position, transparent, and settings. reset now delegates
  to `use omarchy.bar` rather than duplicating the del(.bar.id) write.
- omarchy-bar-plugin owns all layout mutation: add, move, remove, set,
  and replace, with the placement flags and jq resolve/anchor helpers.
  `omarchy bar plugin ...` routes here via the dispatcher.

Drop the inspection commands entirely: the layout is visible on the bar,
the config is shell.json, and widget/option ids come from
`omarchy plugin list`. Nothing consumed the show output programmatically
except tests. This also removes omarchy-bar-position, whose jq write was
a duplicate of `omarchy bar position`.

Strip environment-invariant guards (require_command, require_omarchy_path)
that defended against jq or OMARCHY_PATH being absent — neither happens on
a real system. Keep the user-input validation (--section/--index) and the
atomic shell.json write.

Update callers (service install/remove, refresh-shell, plugin-clone,
plugin enable), keybindings, the menu, tests, and docs to the new split.
2026-07-17 16:28:17 -07:00
David Heinemeier Hansson f8fec7cccf Tighten compact status icon spacing 2026-07-17 16:17:49 -07:00
David Heinemeier Hansson 8211b86ac6 Restore compact status icon spacing 2026-07-17 16:15:01 -07:00
David Heinemeier Hansson 6867f16b78 Restore compact bar indicator sizing 2026-07-17 16:08:33 -07:00
David Heinemeier Hansson 22791803ed Align vertical bar widgets to the icon grid 2026-07-17 16:03:49 -07:00
David Heinemeier Hansson 0c8c4ea26a Align bar icons on a shared baseline 2026-07-17 15:37:01 -07:00
David Heinemeier Hansson 6e3b69b8da Standardize bar icon geometry 2026-07-17 15:20:55 -07:00
David Heinemeier Hansson fe48e83222 Repair Tailscale authorization flow 2026-07-17 10:20:08 -07:00
David Heinemeier Hansson 16b5f2157f Preserve user state during theme setup 2026-07-17 07:59:20 -07:00
David Heinemeier Hansson 09aac40eae Gate first-run setup as one lifecycle 2026-07-17 07:59:16 -07:00
David Heinemeier Hansson 39756d485d Synchronize weather location updates 2026-07-16 21:54:57 -07:00
David Heinemeier Hansson e82df1d4d0 Track one-time setup with completion markers 2026-07-16 21:53:15 -07:00
David Heinemeier Hansson 7b824b6e1b Fix saving typed weather locations 2026-07-16 21:23:32 -07:00
David Heinemeier Hansson b79ae75833 Fix graceful window closing before reboot 2026-07-16 21:19:28 -07:00