Commit Graph
2441 Commits
Author SHA1 Message Date
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 6ea3215542 Merge pull request #7902 from dicemans/rdp-password-not-in-argv
[Security] Keep the Windows VM password out of the RDP client's argument list
2026-09-15 18:08:10 +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
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 HanssonandClaude Fable 5 24841ac5d2 Tell how to resume a channel switch that failed partway
omarchy-channel-set runs under set -e, so a failure after it has begun
mutating the system (dev link, pacman channel, packages) died silently
with the switch half-applied. Trap ERR once the mutation phase starts
and say how to pick the switch back up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-13 10:21:46 +02:00
David Heinemeier HanssonandClaude Fable 5 bc0753dfcb Show a failure state when a presented command exits non-zero
The floating-terminal presentation wrapper showed the green "Done!"
prompt for every exit code except Ctrl-C, so a failed update or channel
switch closed looking like a success. Pass the command's exit code
through to omarchy-show-done and render a red "Failed (exit code N)!"
prompt when it is non-zero. The pkg install/remove pickers get the same
treatment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-13 10:21:46 +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
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
David Heinemeier HanssonandClaude Fable 5.1 7e8feb047d Relay the Elgato Cam Link 4K as a 16:9 virtual camera (#10809)
* Relay the Elgato Cam Link 4K as a 16:9 virtual camera

Browser meeting apps such as Zoom's web client ask the Cam Link for a
standard-definition stream, and Chromium settles on the smallest mode it
offers, 640x480. The Cam Link fills that 4:3 frame by cropping its 16:9
input, and the app then paints the frame into a 16:9 tile, so everyone
comes out stretched wide. The web client has no HD switch to avoid it.

Hide the raw capture node from users and re-expose it through v4l2-relayd
as a 1280x720 virtual camera with the same name, so there is still just
one "Cam Link 4K" to pick and no way to negotiate 4:3 from it. udev
starts the relay whenever the Cam Link enumerates and stops it on unplug,
and the relay only pulls frames while something is watching. The sink
runs unsynced because v4l2src stamps each frame with its capture time,
which a synced sink treats as already late and drops.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Take the review fixes for the Cam Link 4K relay

Tie only the device's stop into the relay instance. A start dependency on
it left a job waiting on a device that never comes whenever the base
v4l2-relayd.service is started without a Cam Link attached, since the
package generator wants every configured instance.

Let the loopback unit rerun on each relay start, so a deleted or unloaded
device is recreated on replug instead of the oneshot staying satisfied.

Start the relay outright at the end of the migration. The udev trigger
only starts it when the rule is new to the device, and a failed module
build would otherwise pass silently with the raw camera already hidden.

Run the hardware fix after the Panther Lake kernel swap, as it pulls in a
DKMS module that would otherwise build twice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 14:09:51 +02: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 72ec724c3c Use omarchy-cmd-present 2026-09-07 12:53:10 -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 BullandGPT-6 Codex 1b4ac8380b Refuse Hermes removal while its files are in use
An open terminal can retain deleted SQLite WAL files across removal and reinstall, causing the updated desktop to refuse session writes. Check user processes before package/runtime removal and again after data confirmation, without killing sessions. Cover the failure with real SQLite writers in isolated fixtures.

Co-Authored-By: GPT-6 Codex (xhigh) <noreply@openai.com>
2026-09-07 03:56:51 -05:00
Spencer BullandGPT-6 Codex 827266fbed Prepare a consistent Hermes release for its first update
Align main with the packaged release and fetch connected history so the updater detects and rebuilds the first update. Guard local branch work before upstream installation, force only the admitted incomplete release pin, preserve existing command files, and explain incompatible packages. Exercise empty-directory publication races and delayed launches.

Co-Authored-By: GPT-6 Codex (xhigh) <noreply@openai.com>
2026-09-07 03:39:05 -05:00
Spencer BullandGPT-6 Codex aa3868b345 Prepare Hermes native desktop for in-app updates
Use the packaged upstream installer and matching prebuilt app to prepare the writable user installation before launch. Preserve existing builds and modified sources; record the upstream build stamp only for a matching prebuilt app.

Co-Authored-By: GPT-6 Codex (xhigh) <noreply@openai.com>
2026-09-07 02:55:06 -05:00
Ryan Hughes e989b5b3ee Merge pull request #7994 from Adolanium/mise-install-name-guard
Quote mise-install arguments and refuse unusable command names
2026-09-07 03:15:39 -04:00
Ryan Hughes a87d396f01 Merge pull request #9387 from omacom/security/nopasswd-expiry-fail-closed
Fail closed when passwordless sudo expiry cannot arm
2026-09-07 03:10:09 -04:00
Ryan HughesandGPT-5.6 Sol a7a4a682e5 Keep mise cleanup compatible with escaped wrappers
Co-Authored-By: GPT-5.6 Sol <noreply@openai.com>
2026-09-07 02:30:56 -04:00