Commit Graph
728 Commits
Author SHA1 Message Date
Afonso OliveiraandClaude Fable 5.1 b34b117fd0 Recover the session lock before waiting for notifications
Restarting the shell waited for the notification bus name to reappear
before it would re-acquire a lock whose client had died. A slow or
failed notification plugin then left the user stranded behind
Hyprland's failsafe even though the lock service worked.

Wait for the shell's core IPC, re-secure the lock immediately, and only
then wait for a previously running notification service, reporting it
separately if it never returns. Cover the never-returning case: the lock
comes back and the restart still reports the missing service.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 17:02:43 +01:00
Afonso OliveiraandClaude Fable 5.1 13a4306a8e Run the refresh hook before its transaction and keep the inhibitor through user work
Three review findings on the update-hook boundary:

The pre-refresh-pacman hook had been moved after the refresh transaction
and, during a channel switch, deferred to the very end. That defeated the
hook's purpose: custom repositories and IgnorePkg entries were not in
place when the downgrade-capable -Syyuu ran. Run the hook where it used
to run, after the package config is re-synced and before the transaction,
but cold: revoke the timestamp, run it behind the no-update wrapper with
the caller's original PATH, and revoke again before continuing. Every
later privileged command authenticates with --no-update, so a detached
child left by the hook has no reusable timestamp to wait for. Channel
switching hands the caller's PATH to the refresh the same way the updater
receives it, and no longer defers or re-runs the hook.

Stay Awake was released before AUR builds, hooks and mise, so the machine
could sleep during the longest part of an update. Releasing the inhibitor
needs no privilege because the held command already dropped to the user,
so stop it after mise and before the reboot prompt, as before.

A packaged channel destination cannot be inspected before its package is
installed, and a transaction can replace the running tree with a release
that predates the command-scoped wrapper; from then on a bare sudo would
resolve to /usr/bin/sudo and publish a timestamp, and the destination's
own updater authenticates the same way. The switch used to abort only
after the packages had changed, with generic rerun advice. Now it checks
for the wrapper after each transaction before any further privileged
step, completes what it safely can, and stops cold with instructions to
run that release's update from a fresh session instead of launching it.

Boundary tests pin the hook between the config copies and the transaction
with a cold timestamp on both sides, the older-destination stop with its
guidance and no launched updater, the new inhibitor position, and the
post-update hook staying unreached on failures and signals. Docs, the
manual and the sample hook describe the restored timing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 11:11:08 +01:00
Afonso OliveiraandClaude Fable 5.1 99ddf35138 Merge the current passwordless sudo expiry head
Bring in the legacy-grant classifier fix and the reserved-prefix
quarantine from #9457 so this branch no longer carries a stale copy of
that command.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 10:44:30 +01:00
Afonso OliveiraandClaude Fable 5.1 ea617b9126 Quarantine unrecognized policy under the generated sudoers prefix
Matching a legacy grant by its filename and rule relationship is not a
complete fingerprint: the legacy writer took the filename from $USER but
produced the rule with echo, and under BASH_ENV with xpg_echo a name such
as ali\0143e yields an alice rule in a mismatched file. Preserving that
as administrator policy let the migration certify success with an
unrestricted grant still live until the next boot.

The prefix is reserved anyway: boot cleanup and the package hook remove
everything under it. Move any file the classifier does not recognize
into a fresh root-only directory under /var/lib/omarchy/sudoers-quarantine/
as `policy`, with the original name stored beside it, so nothing there
stays live, the administrator keeps the content, and a legacy filename
already close to NAME_MAX still fits. An untrusted quarantine directory
keeps the migration pending. Cover the mismatched and maximum-length
legacy files in the unit cleanup and through the real migration runner.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 23:32:17 +01:00
Afonso OliveiraandClaude Fable 5.1 3eb3142313 Recognize legacy sudo grants for any account name
The legacy command wrote the caller's unvalidated name into both the
sudoers filename and the rule. Cleanup applied the current lower-case
account pattern to that suffix, so an exact legacy grant for an account
such as Alice was classified as administrator policy, left active, and
the machine-wide migration marker was written anyway.

Match a legacy grant by its exact filename and rule relationship instead
of the account policy, and cover it in the lifecycle suite through both
the unit cleanup and the real migration runner.

The account pattern itself stays lower-case: sudoers reads an upper-case
word such as ALICE as a User_Alias reference, and ALL as every user, so
such names must never reach the generated rule. Pin that with a test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 23:01:13 +01:00
Afonso OliveiraandClaude Fable 5.1 4bd593f4ed Merge quattro and route refreshes through omarchy-update-pacman
Upstream now runs every Omarchy-owned pacman transaction through the
hidden omarchy-update-pacman helper so a mid-transaction systemd reexec
cannot kill it. Keep the deferred pre-refresh-pacman hook and the
command-scoped sudo wrapper, and call the helper from the refresh and
channel commands; the wrapper still applies to the helper's own sudo.

The sudo boundary fixture copies the helper into its root and runs a
systemd-run stand-in that execs the wrapped pacman step in place.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 21:54:06 +01:00
Erik Melton 9c5482c58d Merge pull request #8170 from Adolanium/hook-state-name-guard
Refuse hook and state names that are paths
2026-09-16 18:09:20 +02:00
Erik Melton f6ce7c554f Merge pull request #10379 from AksharP5/fix/factory-reset-password-hashes
Erase old password hashes during factory reset
2026-09-16 18:07:22 +02:00
David Heinemeier Hansson 2fbac0c8e8 Merge pull request #11934 from omacom/claude-browser-extension
Set up browser integration when choosing Claude
2026-09-15 12:41:39 -04:00
David Heinemeier Hansson 677e69d4f1 Make Claude browser extension installation best effort 2026-09-15 12:40:25 -04:00
David Heinemeier Hansson 8fa9f4d03e Leave Claude browser integration settings unchanged 2026-09-15 12:38:00 -04:00
Erik Melton a73bcbfc0a Remove unsafe project bin PATH injection (#11336)
* Remove unsafe project bin PATH injection

* Cover customized unsafe Mise paths

* Revoke legacy Mise Work trust

* Harden legacy Mise trust cleanup

* Preserve ignored Mise Work configs

* Scope Mise path cleanup to env

* Accept paranoid Mise ignore marker

Reported-by: infosec-us-team
2026-09-15 18:02:17 +02:00
b44fb74780 [Security] Keep screen-recording state out of world-writable /tmp (#8374)
* Keep screen-recording state out of world-writable /tmp

* Compare the /tmp name across the run instead of requiring it absent

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fall back to the state directory when there is no runtime dir

* Let the /tmp snapshot come back empty

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Resolve the region file the same way in the resizer

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Protect recording fallback state and document its path

---------

Co-authored-by: Omabot <omabot@omarchy.org>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 17:53:37 +02:00
Adolanium 49418942c8 Merge pull request #7807 from Adolanium/keyring-fail-loud
Stop update-keyring from claiming success when key operations fail
2026-09-15 17:50:20 +02:00
David Heinemeier Hansson 45e32c8c2d Set up browser integration when choosing Claude 2026-09-15 08:10:58 -04:00
Ryan Hughes 24417bf191 Treat matching kernel headers as a base system guarantee 2026-09-15 00:46:30 -04:00
Ryan Hughes 662051ecde Install matching kernel headers for every DKMS setup 2026-09-15 00:06:17 -04:00
Ryan Hughes 08a875852e Leave fresh-install kernel selection to the ISO 2026-09-14 16:46:45 -04:00
Ryan Hughes ff85faf8dd Make linux-omarchy the default kernel except on T2 Macs 2026-09-14 16:32:09 -04:00
Ryan Hughes 8a972da975 Migrate Panther Lake systems to the Omarchy PTL kernel 2026-09-13 14:43:47 -04:00
David Heinemeier Hansson 8247eb36b7 Merge pull request #11637 from omacom/fix-powerprofile-poll-coredumps
Poll the active power profile over D-Bus instead of powerprofilesctl
2026-09-13 18:06:00 +02:00
David Heinemeier HanssonandClaude Fable 5.1 d78ea9e158 Point GitHub URLs at omacom/omarchy instead of basecamp/omarchy
The repo moved to the omacom org. GitHub redirects the old URLs, but
`omarchy channel set dev` was still cloning from basecamp/omarchy, which
left every dev checkout with a stale origin remote that confuses gh
(pr create fails with "No commits between omacom:quattro and
basecamp:<branch>"). Update the clone URL, the quattro upgrade tarball,
the update-confirm release link, the systemd Documentation link, and
the manual.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSFKDatumRZHB8zqk5CP5C
2026-09-13 17:20:29 +02:00
David Heinemeier Hansson 692c02cad5 Merge pull request #9140 from ogarza/center-qconsole
Center the Quake console in a 2:1 panel instead of spanning the screen.
2026-09-13 12:38:41 +02:00
David Heinemeier HanssonandClaude Opus 5 d377569edb Count only tiled windows and refit when apps move or float
A floating window on the console is not laid out by the gaps, so it no
longer stretches the panel to full width. Moving an app onto or off the
scratchpad and toggling floating now refit too, via
window.move_to_workspace and window.update_rules; both were measured on
Hyprland 0.56.2 to carry the settled count.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012UyVoFTM98Tduoxg7qZax7
2026-09-13 12:37:08 +02:00
David Heinemeier HanssonandClaude Fable 5 83c6dd230c Keep the conflict tests inside their fixture despite the scope wrapper
The update conflict tests stub sudo and pacman, but omarchy-update-pacman
now puts systemd-run between them, so on a systemd-booted host the tests
would reach for the real system manager. Stub systemd-run to drop the
wrapper's options and run the command, and cover the helper's own
invocation composition in a new test.

Raised by codex review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zcqENR1UbhuwC1v5u3Wop
2026-09-13 10:35:32 +02:00
David Heinemeier HanssonandClaude Fable 5 f5194e3ff5 Shield Omarchy pacman transactions from desktop session teardown
Upgrading systemd runs its post_upgrade scriptlet mid-transaction, which
reexecs both the system manager and every user manager. When pacman runs
inside a user-session scope (the floating update terminal), that reexec
can SIGKILL it and abandon the transaction halfway, with packages
upgraded but none of the post-transaction hooks run.

Route every Omarchy-owned system mutation through a new hidden
omarchy-update-pacman helper that registers the transaction as a PID 1
scope via systemd-run, keeping it out of the user manager's cgroups.
System scopes survive the system manager's own reexec, and as a bonus the
transaction now also survives its terminal window closing. On unbooted
systems (the installer chroot) the helper runs pacman directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-13 10:21:38 +02:00
David Heinemeier HanssonandClaude Fable 5.1 55799c4ab0 Poll the active power profile over D-Bus instead of powerprofilesctl
The battery service ran `powerprofilesctl get` every two seconds to keep the
active profile visible to the wallpaper and lock services. That command is a
PyGObject script, so the shell spawned a Python interpreter for it tens of
thousands of times a day. Roughly once a day one of those exits into a CPython
3.14 finalization race (python/cpython#124619): the GLib D-Bus worker thread
calls PyGILState_Ensure after the interpreter is torn down and the process
dies with SIGSEGV, leaving a core dump and a crash notification behind.

Read the ActiveProfile property straight from power-profiles-daemon with
busctl, the same way omarchy-powerprofiles-set already reads UPower. The
output is JSON, so an empty or malformed reply when the daemon is not running
still reads as no active profile, matching the previous behaviour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gbfh4Mi9dK6SAd1P2xMTi
2026-09-13 08:56:39 +02:00
e3392ef76f Quit the running Claude app before removing it
Electron rewrites ~/.config/Claude for as long as the app runs, so removing the package and deleting the directory while it is open leaves the app running and the directory back within the same second, holding fresh Preferences and crash-reporter state. Driven end to end on an edge worker: remove via the menu with the app open left 11 processes and a recreated ~/.config/Claude; with the app quit first the directory stayed gone. The test stubs pkill so the suite cannot take a developer's own Claude with it, and asserts the remover reached for it.

Co-Authored-By: Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-09-10 19:26:34 -05:00
Afonso Oliveira c46f321680 Simplify passwordless sudo grant lifecycle 2026-09-10 22:01:09 +01:00
9d0849f717 Add the Claude desktop app to Install > AI
Follows the ChatGPT flow: the Install > AI entry runs
omarchy-install-ai-claude in a floating terminal, which installs the
claude-desktop package (Anthropic's Linux desktop beta, repacked from
their Debian repo in omarchy-pkgs) and opens the app. Remove > AI
drops the package along with ~/.config/Claude and ~/.cache/Claude,
the Electron directories the desktop app owns, while keeping
~/.claude, ~/.claude.json, and ~/.cache/claude-cli-nodejs: those
belong to the Claude Code CLI, which ships in its own package and
survives this removal, just as the ChatGPT remover keeps the Codex
CLI.

The menu mark is a new U+E90E glyph in the Omarchy icon font, from
Simple Icons' Claude mark, so it reaches desktops through the next
omarchy-settings release.

Co-Authored-By: Fable 5 <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-09-09 22:01:35 -05:00
Spencer Bull 27f10ffd97 Fix Hermes desktop installation after module split 2026-09-08 12:50:04 -05:00
Afonso Oliveira 60ac419f8c Merge current Quattro into sudo expiry fix 2026-09-08 15:28:24 +01:00
Ryan Hughes f5cd244ed0 Retire the stock user icon font missed by Quattro upgrades 2026-09-08 02:36:58 -04:00
Afonso Oliveira 75e58f034f Integrate the shared sudo lifecycle foundation 2026-09-07 23:10:29 +01:00
Afonso Oliveira a6385e60b8 Bound sudo policy natively and guard expiry package transactions 2026-09-07 22:17:32 +01:00
Afonso Oliveira 4ae25cd4d2 Keep temporary sudo grants bounded through lifecycle failures 2026-09-07 21:50:47 +01:00
Afonso Oliveira bc235d2807 Merge remote-tracking branch 'refs/remotes/portfolio/quattro' into codex/portfolio-9457-20260907 2026-09-07 21:27:40 +01:00
Adolanium e522a18ef0 Refuse path-like names in omarchy-hook-install too
The runner already rejects a slash, a bare . or .. The installer still
joined the type into hooks/<type>.d before mkdir/cp, so a name nothing
can run could still land on disk.
2026-09-07 20:59:46 +03:00
David Heinemeier HanssonandClaude Opus 5 446fbc28b1 Start 1Password at a fixed device scale factor (#10673)
1Password reads the display scale itself, the way Electron apps do, so
on a scaled monitor it comes up oversized next to every other window.
Pin it with --force-device-scale-factor=1 and let the compositor scale
it.

The app menu is covered by the packaged .desktop, which we build
ourselves in omarchy-pkgs. This is the other route in: the hotkey runs
the binary directly and never reads that file.


Claude-Session: https://claude.ai/code/session_01JB9phxP56gnP7qSidkkUJE

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 19:56:18 +02:00
David Heinemeier HanssonandClaude Opus 5 a7486beb60 Add Super + Ctrl + Alt + F to toggle a full screen desktop (#10672)
Hiding the top bar and removing the window gaps are the two things you
do to give the screen entirely to your windows, and doing both took two
hands and two hotkeys. `omarchy toggle fullscreen desktop` does them
together.

It only leaves full screen when both halves are in it, so hitting the
hotkey with just the bar hidden (or just the gaps gone) pulls the other
half into line instead of flipping the one you already set.


Claude-Session: https://claude.ai/code/session_01JB9phxP56gnP7qSidkkUJE

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 19:39:27 +02:00
Ryan Hughes 2ea76f8fe2 Refresh the current palette before installing T3 Code 2026-09-07 12:57:08 -04:00
Ryan Hughes 79138c0e70 Follow the active theme in T3 Code
T3 Code reads themes an environment publishes into its state directory, so
a generated t3code.json carries the palette the same way claude.json and
vscode-theme.json already do, and omarchy-theme-set-t3code republishes it
on every theme change for the app to pick up live.

The template overrides only the roles a theme actually designs -- terminal
and code surfaces, text on canvas, borders, selection -- and leaves muted
text, placeholders, and status foregrounds to T3 Code, which contrast-solves
them against whatever canvas it is given. Overriding those directly cost
readability on light themes: White fell to 1.0:1 on placeholder text.

Installing from the menu now routes through omarchy-install-ai-t3-code so a
fresh install publishes the current palette and opens wearing it.
2026-09-07 12:53:10 -04:00
Afonso Oliveira 0add43f9b7 Check dev update support before changing the system 2026-09-07 17:38:36 +01:00
Afonso Oliveira c8697407cb Keep channel transitions inside command-scoped sudo 2026-09-07 17:33:33 +01:00
Afonso Oliveira 5bc41b2585 Resolve security libraries beside canonical entrypoints 2026-09-07 17:31:54 +01:00
Afonso Oliveira f37c73fa20 Bind protected update commands to their source root 2026-09-07 17:27:04 +01:00
Afonso Oliveira 5b692c5b30 Preserve user PATH across updater relaunches 2026-09-07 14:31:07 +01:00
Afonso Oliveira aa422fcd4e Merge current Quattro while preserving command checks 2026-09-07 11:50:18 +01:00
Spencer Bull a703092631 Merge pull request #10613 from spencerbull/hermes-desktop-in-app-updates
Enable Hermes in-app updates and guard removal
2026-09-07 04:26:22 -05:00
Spencer Bull 9fb73b0051 Hide the upstream Hermes launcher in Omarchy
Keep the package launcher visible when Hermes builds register a second desktop entry. Use the existing launcher hide list so in-app updates cannot restore the duplicate menu row.
2026-09-07 04:20:13 -05:00