Commit Graph
22 Commits
Author SHA1 Message Date
David Heinemeier HanssonandClaude Opus 5.5 c05d90196f Switch between several Claude and Codex subscriptions, and build apps the Omarchy way (#13770)
* Plan multiple Claude and Codex accounts with manual or automatic switching

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep several Claude and Codex accounts and start new sessions as the active one

Each added account gets its own home holding only its login, with history,
settings and skills linked back to ~/.claude or ~/.codex so --continue works
across a switch. Accounts are added through the CLI's own login, and cx, cy,
plain claude/codex and omarchy-agent all start as the active account unless
CLAUDE_CONFIG_DIR or CODEX_HOME is already set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Report limits for every Claude and Codex account in the usage records

Each registered account is probed with its own sign-in and cached on its own,
and a parked account whose sign-in lapsed keeps its last-known numbers marked
stale. The record's top-level limits keep describing the active account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Switch accounts automatically near a limit, or notify with a one-click switch

After each usage update, an active account at or over its provider's
threshold (95% by default) moves new sessions to the account with the most
headroom in auto mode, or offers that switch as a notification in manual mode.
It never flaps back to an account that just reset, and says once when every
account is over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Show every subscription account's limits in the agents panel

With several Claude or Codex accounts, the limits become one card per account
with the active one badged. Pick a card with its number and press Enter (or
click Use) to move new sessions to it, press a to add an account, and m to
toggle automatic switching. Limits refresh every minute while an active
account is above 80%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add Setup > Agent Accounts to list, switch and add Claude and Codex accounts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Document switching between several Claude and Codex subscriptions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Count a rested parked account as available, and pin Main to its own home

A parked Claude account whose windows all reset now reads as 0% instead of
unknown, so switching can pick it. Main's Codex limits come from ~/.codex even
when CODEX_HOME is set, and duplicate logins are checked against who each home
is signed in as now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Key limits caches by subscription and report when an account truly frees up

An added account's limits cache follows its account id, so a new account
reusing a removed one's label never inherits its allowance. The all-accounts
notice now names when an account's blocking windows have all reset, not the
earliest reset of any window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep account ids clear of routing keywords and refresh the panel after removal

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Share Codex plugins and hooks across accounts, and key Claude caches by current sign-in

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop the key hint from the Add account button

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sign new agent accounts in through a private browser window

The main browser is almost certainly signed in to the account you already
have, and the login would silently reuse it. Both CLIs open their login page
through $BROWSER, so it now points at omarchy-launch-browser --private.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Let agent account commands default to your default agent's provider

With Claude or Codex as the default agent, the provider can be left out:
omarchy agent account use work, and primary names the primary account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop the primary alias, which shadowed an account named Primary

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Replace the auto switch button with a small Notify / Autoswitch toggle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add accounts from a small + beside the switch toggle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Fix the punctuation of the switch toggle's README line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop the border around the add account +

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rename Claude and Codex accounts without moving their homes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Lay out agent accounts on accent rails instead of boxed cards

The active account gets an accent rail and the others a quiet one, each
window is a single compact line, and the switch toggle, add, and Use are text.
Clicking an account's name renames it in place. A window without a reset time
no longer leaves an empty line, and last-known numbers are only red when the
sign-in needs attention.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Read Codex limits without waiting on account/read

Codex 0.158's app-server can leave account/read unanswered, and asking it
first lost the limits whenever it did, leaving the agents panel showing
"Codex limits unavailable". The limits name the plan themselves, so they're
asked first and account/read is only a short fallback when they don't.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Switch agent providers from their marks in the panel header

The row of provider buttons gives way to a small mark per provider in the
hero's corner, the selected one at full strength, with the add account +
beside them in place of the + by the switch toggle and the full-width Add
account button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the agents panel's scrollbar off its contents

The panel's content narrows to leave the scrollbar its own strip whenever it
scrolls, and the add account + leads the provider marks instead of sitting at
the very edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add Claude, Codex, or Grok subscriptions from one Add Account menu

The first account for a provider installs its CLI if needed and signs in to
the CLI's own home through the normal browser; only additional accounts get a
home of their own and a private window. Grok signs in its first account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Reveal Autoswitch beside Use instead of a Notify / Autoswitch row

The panel's + now opens the Add Account menu for any provider.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Split agent accounts with plain separators instead of rails

ACTIVE already marks the account new sessions use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Only call Claude limits stale once they're old, and poll near a limit less

Anthropic rate-limits its usage endpoint, and polling two accounts every
minute near a limit got every re-check refused, so both accounts read
"Last known" with numbers a minute old. A refused check of numbers under
15 minutes old now counts as current, older ones say how old they are,
and near-limit polling is every three minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Show every agent's limits on one page under an Agents hero

The panel stops switching between one provider at a time and lists every
agent and account with its limits, dropping the tokens-by-day and by-model
charts. The hero carries the agents robot and rotates through what the token
counts add up to: tokens this week and today, the most used model, the
busiest day, and today's prompts and sessions. Middle-clicking the bar icon
refreshes, since there's no provider left to advance to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Report Codex's free rate-limit resets in its usage record

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Give the agents panel more room, and show Codex's free resets

Limit lines are a notch larger with more space between them, each account's
limits sit a clear step below its name, and sections breathe. Codex has one
limit on Pro, so its section now also says how many free full resets are
waiting and when the next one lapses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Mark Claude's Fable limit on the Weekly meter instead of its own row

A model-scoped allowance on the same clock as a base window is drawn as a
tick on that window's meter and named in the row's tooltip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Let omarchy-default-agent set the default without launching it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Let the agents panel drive adding an account without a terminal

--check says whether adding one now would be each provider's first sign-in
or an additional account, and --events reports progress as tagged lines
alongside the CLI's own output, notifies with the result, and cleans up the
login and its scratch home when cancelled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add subscriptions and pick the default agent right in the agents panel

The + is a proper accent button, and it swaps the list for a picker of
Claude, Codex, and Grok that signs in without a terminal: name a further
account, then follow the sign-in with its status, Grok's confirmation code, a
field for Claude's pasted code, and a link to reopen the page. A dropdown at
the bottom sets the default agent without launching it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Draw the Fable tick in its meter's own color

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Revert "Let omarchy-default-agent set the default without launching it"

This reverts commit da96261f7d26bb76774cbdc1cb9e0abde92bb841.

* Make the first agent signed in the default when none is picked

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the agents panel in the bar, with setup, starters, and adding in it

A machine with no agent opens the panel on setting one up. Once set up, the
list ends with starter prompts for a new theme, plugin, or app, and a quiet
Add a subscription. The panel no longer sets the default agent, and the hero
drops its add button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Offer the starter prompts as tiles, and adding as a row beneath them

Theme, Plugin, and App each get a tile with its glyph, and Add a
subscription a matching row with the + in a tinted square. The panel is
allowed to grow tall enough to show it all without scrolling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Put the tinted add button in the agents panel's hero corner

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Show when a limit resets in small type under its meter

The percentage keeps the right edge to itself, so the meter runs longer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Revert "Show when a limit resets in small type under its meter"

This reverts commit 108d9de59da1af12cddbf232b0b5333ad8994c64.

* Put each account's plan beside its name, and its email in a tooltip

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Stack each limit's percentage over its time left, so the meter runs longer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Show only each limit's time left, with the exact percentage on hover

The meter already says how full a window is. Dropping the percentage beside
it leaves one calm figure per row, and the row's tooltip carries the number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sign an existing account in again with omarchy-agent-account-add --reauth

It signs in where the account already lives: the CLI's own home (:primary)
through the normal browser, an added one through a private window. The usage
records now say which account is the primary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Offer Sign-in required in the agents panel instead of how old the numbers are

A lapsed sign-in shows as a link that signs that account in again right in
the panel. The "as of" and "last known" notes are gone; trouble that isn't
about signing in still shows as text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the separator dot out of the Sign-in required link

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop the Setup > Agent Accounts menu and the stale plan

The agents panel now lists, switches, and adds accounts, so the menu's
duplicate of it goes, and the plan written before the design settled no
longer describes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Install the compiler and Qt pieces for building Omarchy-style apps

base-devel plus qt6-base, qt6-declarative, qt6-multimedia, and qt6-wayland,
which is what Hype, Monologue, and Omacut build with through qmake6 and make.
Qt was only there as a dependency of those apps, and the compiler not at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add an omarchy-app agent skill for building apps the Omarchy way

It teaches how Hype, Monologue, and Omacut are built: C++ and Qt Quick in
one flat project, qmake6 and make into a single binary, a theme that follows
Omarchy's accent live, portal dialogs, keyboard-first conventions, Qt Test
offscreen, and a PKGBUILD that puts the app in the launcher, with starter
files that build and pass their tests as written. The agents panel's App
starter uses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Link the omarchy-app skill on existing installs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Let Cancel stop a waiting login, and list a lone account's limits

Bash holds a trap until the foreground command finishes, so a login waiting
on the browser outlived Cancel. It now runs behind an interruptible wait.
With one account the usage record keeps its limits at the top level, which
omarchy agent account list now reads for the primary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Re-read identity even when signed out, and count Grok as set up

A home whose login is gone no longer keeps the identity the registry saved,
so it reads as signed out and can be added again. The agents panel leaves its
setup screen once any agent is signed in, not only once one has usage to
show, since Grok has no usage collector.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Save each account's current identity before collecting usage

A home signed in to someone else since it was added kept the old email in
the registry, which the usage records name accounts by. The usage update now
refreshes the registry from each home first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Offer Claude's paste field from the start, and keep providers with accounts

Claude's login prompts for a pasted code without a newline, so the panel's
line reader never saw it; the field is simply there for Claude sign-ins. A
provider with accounts stays listed even when the active one's limits are
unavailable, so its other accounts can still be switched to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Never autoswitch to a signed-out account, and report Codex's missing sign-in

An account nobody is signed in to is left out of switching, however much
room its cached numbers show. Codex answers a home without a login with an
error, which now reads as Waiting for auth, so the panel offers Sign-in
required for Codex accounts too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Link shared files before they exist, and only call every account over when it is

A shared file the primary home didn't have yet was left unlinked, so an
added account made its own copy and the two diverged for good; it's linked
up front now, and written in the primary home by whichever account writes it
first. The all-accounts-over notice waits until every account's limits are
actually known.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Make the agent starter tiles compact and call the section Make something cool

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hold the agents hero line until its next fade

Every usage record that landed rebuilt the summary phrases, and the hero
indexed that live list, so opening the panel could swap the line several
times between fades. It now keeps what it shows until the timed swap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Start the default agent from the agents panel hero

A console button beside the add button runs the same launcher as the
right click: the default agent, or the picker when none is set. It hides
while adding a subscription, where the add button becomes the way back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Put the add button before the agent launcher in the hero corner

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bring keyboard navigation back to the agents panel

The one-page redesign dropped left and right with the per-agent pages,
leaving the arrows only to scroll. They now walk everything that does
something, row by row: the hero's add and launch buttons, each
switchable account, and the starter tiles. Enter acts on the cursor,
the cursor scrolls into view, and hovering moves the same cursor so only
one thing is lit. Number keys still jump to an account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Let adding an account take over the agents hero

While adding, the hero's line reads "Add an account" in place of the
rotating summary, and the X in its corner is the only way back, so the
add view drops its own title and Back link. Each agent to add is just its
mark and name; one that can't be added is dimmed and says why on hover.
The arrows walk that list too, and Enter picks one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Show the agents to add as large marks, three across

Each agent is a large mark over its name with no box around it, in one
row the arrows move along. The chosen one turns accent and grows a touch.
The reason an agent can't be added is shortened to fit inside the panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move between Autoswitch and Use on an account with the arrows

An account that isn't active is now two stops, Autoswitch then Use, so
left and right move between them and Enter acts on the one that's lit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Land on Use when moving up or down onto an account

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hide Use on an autoswitching account until you're on its line

With Autoswitch on, the line shows only Autoswitch. Use appears when the
line is hovered anywhere or the keyboard is on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Start adding an account with the first agent focused

Opening the add screen puts the keyboard cursor on the first agent, so
Enter picks it straight away. A focused agent lights up even before the
check says whether it can be added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop the Sign in link under the account name field

Enter in the field already starts the sign-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Key the primary Claude account's limits cache by its subscription

The primary home always used claude-limits.json, so signing it in to
another subscription could carry the old one's numbers over when the
first probe failed, and autoswitch would act on them. Once the home says
who it's signed in as, its cache is keyed by that like every other
account's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Leave Qt Multimedia out of the base packages again

Quattro dropped it once the shell no longer needed it, and the app skill
already has an app that plays audio or video add it and list it in its
own depends. The compiler and the rest of Qt stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Render the agents panel's dynamic text as plain text

Sign-in status, help text, and provider names come from outside the
shell, so none of them should be read as markup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep an account's plan and trouble clear of its Use and Autoswitch links

The details beside an account's name grew to their full width, so a long
plan or warning could run under the links on the right. They now shorten
with an ellipsis instead, and Sign-in required keeps its whole width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Let primary name the first account, as the manual says

`omarchy agent account rename primary Hey` was documented but failed,
since the primary account's id is main and lookups took exact ids only.
primary now reaches the account marked primary, whatever it's been
renamed to, and no new account can take primary as its id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Install everything an Omarchy app needs by default

The app skill builds with Qt Multimedia, SVG icons, and ffmpeg as well as
the compiler and the rest of Qt, so qt6-multimedia, qt6-svg, and ffmpeg
join the base packages and the migration. The shell still plays no video
through Qt Multimedia, which is what its test now checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Dim agent limits kept from an earlier check, with their age on hover

When a Claude probe fails, the last numbers carry on and looked just like
fresh ones. Those meters now dim, and their tooltip says how old they
are. The record carries limitsStale and limitsFetchedAt for this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Give the app skill templates for every file its build needs

The templates named src/backend.{h,cpp} and a test file without showing
them, so each app had to invent its own. They're now templated, with a
starter icon, a note that LICENSE and the icon must exist for package(),
and qt6-wayland in the PKGBUILD's depends. Scaffolded from the templates
alone, the app builds and its tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Start the agents panel cursor over when the agent list comes or goes

Right after the shell starts, the panel can briefly look like a first
setup and focus the first agent to add. When the records land the rows
change under the cursor, which then lit an account nobody had picked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop dead hover and limit checks from the agents panel

The tiles and hero buttons fell back on their own hover when there were
no keyboard rows, but the hero always has one, so hover only ever moves
the cursor. Stale meters only exist when there are limits, so neither
the panel nor the record needs to check for some.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop the a hotkey for adding an agent subscription

The + in the hero is the way in, by mouse or by arrowing to it. The
plugin README also catches up with the panel: the launcher, dimmed stale
limits, the new add screen, and the arrows walking a cursor rather than
scrolling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* List a command family that sits under a flags-only command

`omarchy agent account` reached omarchy-agent, which takes only flags,
and failed on the word instead of listing the account commands. When the
command matched so far takes only flags and the next word names visible
commands, the router now lists them. `omarchy update aur` likewise lists
the update aur commands rather than running a full update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Refuse to remove an agent account a running session uses

Removing an account deleted its home at once, pulling the login out from
under any session started in it, though running sessions are never meant
to be touched. It now says to quit that session first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Prefer an account checked just now when switching near a limit

Autoswitch weighed numbers kept from an earlier check like fresh ones.
A parked account's sign-in lapses within hours, so a stale one stays a
candidate, but an account checked just now wins over it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Leave a user's own omarchy-app skill in place when linking ours

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Reach Sign-in required with the keyboard in the agents panel

Both the link on a lapsed account and the one on a single-account agent
are now stops in the cursor's walk, and Enter signs in again. A picked
link scrolls into view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bring the manual's agent accounts paragraph up to date

Near-limit checks run every three minutes, not every minute, and
Autoswitch now appears on hovering an account's line and takes Use's
place while it's on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep the agents panel cursor on things you can act on

The active account was a stop with nothing to do, so the cursor seemed to
vanish there. It now only stops on it to sign in again. The hero's
buttons also show the cursor plainly, with an accent border and a deeper
tint instead of a shade's difference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Never leave an added agent account's login outside the registry

Registering moved the login into its home before carrying settings over
and saving the registry, so a failure in either stranded a home holding
a sign-in that the account commands couldn't see. Settings are now
carried while the login is still pending, and a failed save moves the
home back there for the add command to clean up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Put room before freshness when picking an account to switch to

Preferring accounts checked just now outright could pick a fresh one at
94% over a stale one at 10%. An account within 15 points of the
threshold now counts as near its limit however fresh, so accounts with
room come first and freshness only decides among them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Check agent limits more often relative to the switch threshold

Faster checks started at a fixed 80%, so a threshold set lower could be
crossed and wait out the 15-minute interval. They now start 15 points
below the threshold, which is still 80% at the default 95%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 13:36:22 +02:00
David Heinemeier HanssonandClaude Opus 5.5 6762769bbf Open shell menus and panels through Hyprland global shortcuts (#13418)
Every binding that opened a menu or panel ran omarchy-menu or
omarchy-shell, which starts a qs client just to deliver one IPC call:
~60ms before the shell heard about the keypress.

The shell now registers a Hyprland global shortcut for each menu route
and panel in default/omarchy/shortcuts, and o.bind turns { menu = ... }
and { panel = ... } into hl.dsp.global for those, so a keypress spawns
nothing. A route or panel missing from the list binds through the
command as before. The default menu and panel bindings use the new form.

SUPER+SPACE opens the menu in ~31ms instead of ~94ms, measured from a
simulated keypress until the menu layer maps.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 18:02:01 +02:00
Erik Melton d201fb9564 Merge pull request #9467 from AFOliveira/codex/om-sec-12-update-inhibitor-identity
[codex] OM-SEC-12: Bind update inhibitor cleanup to process identity

Reported-by: Afonso "AFOliveira" Oliveira
2026-09-25 15:56:39 +02:00
David Heinemeier Hansson c599d23a39 Document automatic screenshot saving (#13218) 2026-09-25 07:28:27 -05:00
Afonso Oliveira 56ca654dc8 Merge quattro into update security foundation 2026-09-21 14:14:59 +01:00
Ryan Hughes 95120838d3 Document Omasnap's default capture flow 2026-09-21 02:14:55 -04:00
Ryan Hughes e265934bb1 Use Omasnap for screenshots 2026-09-20 13:18:36 -04: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 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
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
Afonso Oliveira 1f8f5bacac Integrate current quattro before security review 2026-09-06 22:56:04 +01:00
Afonso Oliveira 7f9a401bb1 Merge commit 'b71dcad96e9d0b2962b7d225828a5cb6000ad720' into codex/review-9469-20260906 2026-09-06 22:11:06 +01:00
Ryan Hughes 1d466c4003 Add o.rebind for replacing Hyprland keybindings 2026-09-06 16:01:50 -04:00
steelcityapplianceandClaude Fable 5.1 a9eaf7978e Point the shipped agent skills at omacom/omarchy (#10532)
The repository moved from basecamp/omarchy to omacom/omarchy, but the skills
Omarchy installs into ~/.claude/skills, ~/.codex/skills and ~/.agents/skills
still name the old owner. Most gh calls follow the rename, so nothing looks
wrong in normal use. Search does not: `gh issue list --repo basecamp/omarchy
--search ...` exits 0 with no output, and the raw search API answers
"Validation Failed". An agent following contributing.md or reporting.md runs
its duplicate check before filing, sees zero matches, and files a duplicate.

Replace the owner in contributing.md, reporting.md and the issue-template
contact link, which is the same stale name on the contributor path. The git
clone and release URLs in bin/ and manual/ are left alone: GitHub redirects
those, and channel-test.sh asserts the exact clone URL, so changing them is a
separate change.

Fixes #10118

Written by Claude Fable 5.1 via Claude Code, reviewed by Marc Morriss

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 21:29:36 +02:00
David Heinemeier Hansson 4d017913d0 Update the tagline to Beautiful, Fun & Agentic (#9584)
Matches omarchy.org, the X header, and the ISO. The README and the agent skill carry their lowercase variants.
2026-09-01 11:54:15 +02:00
Afonso Oliveira 1136a715c0 OM-SEC-14: Run update hooks without reusable sudo authority 2026-08-31 21:32:42 +01:00
Omarchybot b68d4142d7 Cut the crash-mute section of the skill to what it instructs
The section had grown a paragraph per review round, each one explaining why the last was right, until one offer took a third of the file. Most of it was reassurance about what the command refuses rather than anything an agent has to do, and the command enforces that itself whatever the prose says.

What is left is the instruction: offer it and never run it unprompted, say how to lift it, which of the two names to pass and why the binary is the better one, quote it because the name is the crashed program's to choose, and name the interpreter collision before muting python or node on someone's behalf. Fifty-four lines to thirty-two, with nothing dropped that changes what the agent does.
2026-08-27 12:28:44 +02:00
OmarchybotandCodex XHigh ea6ee9440a Add omarchy-crash-mute to mute and unmute one program
The mute was reachable only as `omarchy-toggle crash-ignore/<program>`, which asks whoever runs it to know the flag layout, to reduce a binary's path to the name the watcher keys on, and to have read the rule that a name climbing out of that directory writes an unrelated toggle. All of that was carried in the skill's prose, which is the wrong place for a rule that has to hold: prose is advice, and the thing being advised about is a name the crashed program chose.

So it is a command now. `omarchy crash mute hyprland` silences that program, `off` lifts it, `toggle` flips it, and no argument lists what is muted. It takes the binary's path as readily as the name and reduces it the way the watcher does, so the `Executable:` line from `coredumpctl` can be handed straight to it; it refuses what is not one component of a name, so it cannot be talked into writing outside its own directory whatever it is given; and it re-reads the flag afterwards and reports what is now true rather than what was asked for. The listing counts only regular files, because that is all the watcher honours -- anything else in there would read as muted while the crashes kept arriving. A leading `--` is consumed so a program named `-h`, which the router would otherwise answer with its own help, can still be muted.

The watcher gained an unrelated fix that this uncovered. Its fields are read with `IFS=$'\t'`, and tab is IFS whitespace, so an empty field collapsed into the next delimiter and shifted every field after it along one: a crash whose comm was empty had a path read as its pid and was discarded as somebody else's. A process can set its comm to nothing, so that was reachable. Empty fields now arrive as a dash like missing ones, and a dash joins the empty and dot cases that fall back to `unknown`.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 11:26:28 +02:00
OmarchybotandCodex XHigh 8d14869689 Let a crash diagnosis mute that program's notifications
A crash that is understood is not a crash that stops: an upstream bug waiting on a release, a program that dumps core every time it exits. The diagnosis explains it once and the toast keeps arriving, and the only answer Omarchy had was Crash Capture, which turns off every program's notifications in order to silence one.

The watcher already resolves a name to dedupe on and announces that same name in the toast, so the mute is keyed on it: a flag file under toggles/crash-ignore/, written by the existing omarchy-toggle and read by the existing omarchy-toggle-enabled. One flag per name rather than one list, so `on` mutes, `off` un-mutes, and `ls -A` shows what is muted, with no new file format and nothing to parse. It is the executable's basename wherever one was recorded, falling back to the process name, which the kernel truncates to fifteen characters -- muting the truncated form would match nothing, forever, while looking like it worked.

The name is not always a name, though, and the mute turns it into a path. A program picks its own comm and prctl takes anything, including slashes, and the watcher falls back to comm whenever a crash carries no absolute executable. So it is stripped to its last component first: without that, `a/../bar-off` is a legal comm aimed at an unrelated Omarchy flag, letting a crashing program suppress its own notification and letting a user who accepted the offered mute hide their bar instead. Stripping does not always leave a component either -- `/` leaves an empty string, which is no kind of array subscript and no kind of toast, and `.` or `..` names a directory that omarchy-toggle would touch and report success on, leaving a mute that never matches. Both fall back to `unknown`, the word omarchy-agent-crash already uses for a name it does not have, and which mutes like any other.

The skill offers this at the end of a diagnosis and never runs it unprompted, which makes it the single change a diagnosis may make to a system it otherwise only reads. It tells the agent to use the name it was handed rather than re-derive one, since the watcher resolved that name already and the two agree for ordinary names and not for strange ones; a diagnosis started by hand from `omarchy agent crash <pid>` is given no name and gets the derivation instead. It also says to treat the name as hostile text rather than as a word -- it is whatever the crashed program's author called a file, so a single quote inside one closes the quotes around it and the rest runs as the shell -- and to check the flag arrived rather than assume it.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 10:32:10 +02:00
OmarchybotandCodex XHigh ef6d9e6605 Stop an installed theme from running code (#7884)
* Stop an installed theme from shipping code

`omarchy theme install <url>` clones a stranger's git repository into ~/.config/omarchy/themes, and omarchy-theme-set then copied that whole directory into the staged theme. Most of the files in a staged theme are code rather than colour: Hyprland requires hyprland.lua and gum_env.lua from it at login, Neovim loads neovim.lua at startup, and alacritty.toml, kitty.conf, foot.ini and ghostty.conf each name the program the terminal launches. Installing a theme was the same act as running its author's code, and nothing on disk distinguishes an installed theme from one the user wrote.

Stage only what a theme needs in order to be a theme: colors.toml, light.mode, the preview and unlock images, and image files under backgrounds/. Everything else is ignored, named on stderr, and generated from default/themed/*.tpl instead. Symlinks are never followed, because in an untrusted theme they point wherever the author chose. A theme older than colors.toml keeps its palette: its alacritty.toml is read for colours in a scratch directory and only the resulting colors.toml is staged, so the terminal config never lands.

The filter belongs in omarchy-theme-set rather than in omarchy-theme-install because staging is the choke point. It also covers themes installed before this change, themes copied in by hand, and files a theme gains later through `omarchy theme update`.

First-party themes under $OMARCHY_PATH/themes are unaffected. Per-theme overrides of a generated file are no longer available to user themes; the template at ~/.config/omarchy/themed/<file>.tpl replaces that, and icons.theme is the one setting with no replacement.

🤖 Generated by Opus 5 in Claude Code.

* Stop a theme URL or name being read as an option or a path

Three paths in the theme commands took an attacker-shaped string straight into git, into basename, or into rm.

`git clone "$REPO_URL"` passes the URL as the first positional argument, so a URL beginning with a dash is parsed as an option instead and the destination path becomes what git tries to clone. Pass `--` before the URL so a URL is always a URL. git also treats `<helper>::<address>` as a remote helper to run; git's own protocol.allow default already refuses `ext::`, so rejecting that shape here is a second line rather than the fix, and it keeps holding if that default ever moves. The helper name is a bare word at the very start of the URL, which is what the guard matches: an scp-style IPv6 host such as git@[2001:db8::1]:org/repo.git carries `::` of its own and still clones.

`basename "$REPO_PATH" .git` has the same problem one step later, after the scp-style prefix has been stripped: `host:-s/foo.git` leaves basename reading `-s` as an option and returning `.git` as the theme name. Take the name with `--`.

That name is then joined into a path that is about to be `rm -rf`'d, so a repo whose basename came out as `..` would take ~/.config/omarchy with it. omarchy-theme-remove had the same shape from its own argument, and omarchy-theme-set's sed/tr normalization does not stop a name containing a slash. Reject empty, anything starting with a dot, and anything containing `/` in all three, before the name reaches a path.

🤖 Generated by Opus 5 in Claude Code. Reviewed by Codex XHigh.

Co-Authored-By: Codex XHigh <codex@openai.com>

* Re-stage the current theme for installs that already applied one

Dropping a theme's code at staging time only takes effect the next time a theme is staged. An install that already applied an extra theme keeps that theme's hyprland.lua, gum_env.lua, neovim.lua and terminal configs in ~/.local/state/omarchy/current/theme, which Hyprland requires at login and the terminals include at launch, and nothing forces a theme change — so for those installs the fix would arrive whenever the user next happened to switch themes, which may be never.

Re-stage once through omarchy-theme-refresh. First-party themes stage identically, so the cost for everyone else is a single retint during an update they are already running.

🤖 Generated by Opus 5 in Claude Code. Reviewed by Codex XHigh.

Co-Authored-By: Codex XHigh <codex@openai.com>

* Stop a theme's unlock image republishing a file it points at

omarchy-plymouth-set-by-theme reads unlock.png straight out of ~/.config/omarchy/themes, which is an installed theme's own directory and outside the staging filter, and hands the path to omarchy-plymouth-set. That path was copied twice into world-readable /usr/share — once by the user into the Plymouth theme, and once by `sudo cp` into the SDDM theme. A symlink there was followed both times, so a theme could name a file it cannot read and have root publish it.

Refuse a symlinked logo, and copy the staged logo to SDDM instead of rereading the caller's path as root. The staged copy is made by the user, so nothing privileged opens a path the caller chose.

🤖 Generated by Opus 5 in Claude Code. Reviewed by Codex XHigh.

Co-Authored-By: Codex XHigh <codex@openai.com>

* Limit only what an installed theme could run

Two corrections to the rule this branch introduced, both narrowing it to what it was actually for.

It applied to every theme under ~/.config/omarchy/themes, which swept up themes the user wrote themselves. Their machine, their file: a theme they wrote is theirs to fill however they like, and Omarchy's own themes were never in scope. Only a theme that came from someone else needs limiting, and the repo already knows which those are — omarchy-theme-extras calls a theme with a `.git` directory an extra and a symlink someone's working copy, because that is what `omarchy theme install` leaves behind when it clones. Use the same test.

It was also an allowlist, which dropped files that carry nothing but colour and left theme authors worse off for no gain. Drop only what can run: any `*.lua`, since Hyprland requires a theme's hyprland.lua and gum_env.lua at login and Neovim loads neovim.lua at startup; the four terminal configs, since each names the program the terminal launches; and vscode.json, whose extension field reaches `code --install-extension` and a VS Code extension is arbitrary JavaScript. Everything else an installed theme ships is kept, so btop.theme, chromium.theme, helix.toml, icons.theme, keyboard.rgb and shell.toml go back to being the theme's to set.

Symlinks are still dropped, now at any depth rather than only where an allowlist happened to look.

A denylist is wrong the moment someone adds a template and does not think about it, so the decision is forced rather than remembered: the test fails on any default/themed/*.tpl whose output is recorded as neither code nor colour, and a new terminal or a new Lua-loading editor cannot be added without classifying it.

What this does not cover, and is written down in docs/theming.md rather than implied: a theme shipped as an archive and unpacked by hand looks exactly like one the user wrote. `omarchy theme install` only takes git URLs, so the supported path is always filtered, but this marks where a theme came from and is not a sandbox.

🤖 Generated by Opus 5 in Claude Code.

* Fix what the review found

Four things, all confirmed against the source before changing anything.

The migration failed permanently when the active theme had been removed. `omarchy theme remove` deletes the directory without repointing theme.name, so the name survives, the staged copy survives, and omarchy-theme-refresh exits 1 because neither source directory exists — leaving the migration pending forever and the stale staged Lua exactly where it was, which is the one thing it existed to remove. Seed the default theme in that case: there is nothing to re-stage from, and the removal should have left a working theme behind anyway.

The staging test skipped the strict-mode header that docs/testing.md makes the contract for every shell test. Adding it means the patterns that fail on purpose have to stop being bare `cmd && fail` compounds, which errexit reads as the script itself failing; the mutations were re-run afterwards to confirm the assertions still fire rather than the run dying early and looking like something else.

The guards in omarchy-theme-install and omarchy-theme-remove had no coverage — they were checked by hand and left that way. theme-install-guards-test.sh stubs git and the themes directory and proves an option-shaped URL, a transport helper, and a name that would climb out all stop before git or rm runs, that a dash inside the path no longer becomes a basename option, and that an ordinary URL still clones and applies.

The new docs/theming.md prose was hard-wrapped, which AGENTS.md forbids for docs/. Unwrapped. The rest of that file is wrapped from before and is left alone rather than churned through this change.

🤖 Generated by Opus 5 in Claude Code. Reviewed by Codex XHigh and Copilot.

---------

Co-authored-by: Codex XHigh <codex@openai.com>
2026-08-23 16:43:31 +02:00
David Heinemeier Hansson 2cc3510d2a Offer an AI diagnosis when a process crashes (#6746)
* Offer an AI diagnosis when a process crashes

systemd-coredump journals every core dump under a known MESSAGE_ID with the
crashing program, pid, and signal as structured fields. omarchy-crash-watch
follows that stream and raises a "Process crashed: <program>" toast; clicking it
opens omarchy-agent-crash, which briefs the default agent on the crash.

The toast goes through omarchy-notification-send --exec rather than a libnotify
action, because the shell runs clicks from its own omarchy-exec hint and never
emits ActionInvoked. It keeps the default "omarchy-action" app name too, the
only one shouldBypassDnd() lets through -- a crash being the last notification
worth swallowing. It stays quiet until an agent is configured, since a
diagnosis is all it offers.

The method lives in a diagnose-crash skill rather than the prompt, so it is
edited in one place and works with whichever agent is default. It covers
investigating the core, and reporting a confirmed Omarchy bug upstream: scoped
to bugs Omarchy controls, searched for duplicates first, only with the user's
agreement, and signed with the model and harness that produced it.

A migration reaches existing installs, whose skill symlinks and unit enablement
would otherwise sit behind one-time setup paths.

* Let the diagnosis clean up the core it extracted

"Do not modify or delete anything" contradicted the symbolization step right
above it, which writes a core to a temp file and deletes it on exit. Read
literally, the core survives -- and the same section warns it holds passwords
and tokens. The prohibition is about the system, not about your own scratch.

* Do not spend a crash toast on a dead notification server

The shell owns org.freedesktop.Notifications, so its own crash takes the
notification server down with it -- and a shell crash is exactly what you want
told about. The toast was sent once into that gap and the dedupe window was
recorded regardless, so the rest of the crash loop went quiet for a minute and
`journalctl -n 0` never replays what was missed.

It now waits for the restarted shell to reclaim the bus name, as
omarchy-migrate-notify already does, and only a delivered toast starts the
dedupe window.
2026-08-12 18:37:40 +02:00
David Heinemeier HanssonandClaude Fable 5 6ee243cc37 Split the end-user omarchy skill into topic guides (#6602)
* Split the end-user omarchy skill into topic guides

Move default/omarchy-skill to default/agents/skills/omarchy and break the
monolithic SKILL.md into on-demand topic files for Hyprland config, shell
plugins, theming, and hooks. Update the skill symlink wiring, relink
existing installs through a migration, and correct claims that had drifted
from the implementation: plugin hot-reload, terminal reload, menu
customization, refresh scopes, theme overlays, background locations, hook
timing, and the packaged (not git-managed) system directory.

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

* Add capture and contributing guides to the omarchy skill

Cover screenshots, screen recording, OCR text capture, and LocalSend or
Taildrop sharing, plus how to route bug reports, suggestions, and support
questions upstream with diagnostics and captures of the problem attached.

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

* Scope Hyprland reload guidance to the Lua config files

hyprsunset.conf and xdph.conf are read by separate processes, so hyprctl
neither applies nor validates them. Document restarting hyprsunset after
editing its config, including in the night light example.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 14:36:42 +02:00