Download the current page's video with yt-dlp via Alt+Shift+D or a click
on the toolbar icon. A native-messaging host runs the download, shows live
progress on the Quickshell OSD, and posts a clickable "Download complete"
toast that opens the file in mpv.
- Extension: pinned key for a stable id, green download-video icon,
keyboard command + toolbar action (reads the active tab URL).
- Native host (omarchy-chromium-ytdlp-host): verifies the URL with
yt-dlp --simulate (else "No video found"), streams progress to the OSD
(time-throttled to ~4/s), saves to ~/Videos, opens mpv on click.
- Installer (omarchy-install-chromium-ytdlp) writes the native-messaging
manifest into installed Chromium/Chrome/Brave/Edge profiles; wired into
browser install and chromium refresh, with a migration for existing users.
- omarchy-osd: add -d/--duration so the OSD can persist during a download.
- Add yt-dlp to base packages, load the extension via --load-extension,
and document the Alt+Shift+D binding.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Let users add trusted plugin source repos and add/update/remove plugins
from them, alongside the existing in-shell plugin commands:
omarchy plugin source <add|list|remove|refresh>
omarchy plugin available
omarchy plugin add | update | remove | validate
Each command is interactive (gum/fzf pickers, confirmation, an update
diff) in a TTY and fully flag-driven with --yes for scripts and agents.
Sources live in ~/.config/omarchy/plugins/sources.json and clone into
~/.cache/omarchy/plugin-sources/. The installer only copies files,
validates manifests against the shell's schema, and toggles enabled
state over IPC -- it never runs plugin code, hooks, or sudo.
Also guard 'plugin bar add' so only known bar-widget ids enter the
layout (rejecting typos/non-widgets like a stray '--help').
Restore the clipboard watcher behavior that drops CLIPBOARD_STATE=sensitive events, which password managers use for copied secrets.
Use the same sensitive foreground clipboard path for emoji insertion instead of a custom history marker, and keep the password-manager MIME hint ignored as a fallback.
Keep the first emoji result selected whenever results exist, including after search filtering, so Enter inserts immediately.
Route emoji insertion through a hidden helper that serves a transient sensitive clipboard entry long enough for Shift+Insert, then stops that clipboard owner.
Mark transient emoji inserts so clipboard history skips only that event while continuing to record normal terminal copies.
Update existing terminal configs to encode Shift+Return as CSI-u so Codex and other TUIs can distinguish it from Return without tmux seeing it as Alt+Return. Also ensures Alt+Shift+Return CSI-u bindings remain present for tmux horizontal splits across Kitty, Ghostty, and Foot.
Encode Shift+Return as CSI-u across supported terminals so TUIs such as Codex can distinguish it from plain Return. This replaces Alacritty's ambiguous ESC+Return mapping, which tmux interpreted as Alt+Return and used to split panes, while preserving Alt+Shift+Return as CSI-u for tmux's M-S-Enter binding.
Clipboard history selections passed the full selected text as a process argument to omarchy-clipboard-paste-text. Large entries can exceed Linux's per-argument exec limit, so the helper never starts reliably for big copied blocks.
Pass the original history index instead and have the helper read that entry from clipboard-history.json before wl-copy and Shift+Insert. Also focus the first row when opening the manager, keep filtered rows mapped to their original history indexes, and drop whitespace-only text entries.
The Hyprland gaps_out value (10px out of the box) reads well as a
window-to-window gap but felt cavernous when used as the screen-edge
margin for panels and notifications. Halve it at the source — panels
that anchor via PopupCard.margin, the launcher / clipboard / emojis /
polkit / menu / settings card-width clamps, and the notification popup
margins all read Style.gapsOut, so one tweak moves them in lockstep.
Revert the per-call /2 in the notifications service, since
Style.gapsOut now already encodes the smaller value.
Sit notifications closer to the top and right edges than the default
gapsOut. The bar-height clearance still applies to the top — only the
free gap portion is halved.
Set the default formatAlt to "dd MMMM 'W'ww yyyy" (was "dd MMMM yyyy")
in shell-defaults.json, the bundled settings-panel defaults, and the
form placeholder text — clock's own widget fallback already used this
spec but the shipped config overrode it.
Qt.formatDateTime doesn't recognize `ww` and renders it literally
(`20 May Www 2026`), so add an `isoWeek` helper to clock.qml that
pre-substitutes `ww` with a Qt-quoted literal of the ISO 8601 week
number before handing the format off to Qt. Users get `20 May W21 2026`
without anyone needing to know about the substitution.
Clock and daytime were near-duplicates with different click semantics
(clock toggles between formats on left-click and opens the timezone
selector on right-click; daytime was non-pressable with a hover tooltip).
Standardize on clock, since it's the more capable of the two.
- Delete widgets/daytime.qml and its FirstPartyWidgets entry.
- Migrate shell-defaults.json, shell.qml's builtin fallback, Bar.qml's
fallback bar config, and the settings panel's builtin defaults so the
center anchor and center-section entry both reference "clock".
- Rename the daytimeSettings form to clockSettings and rephrase
"Tooltip format" → "Alternate format (click to toggle)" so the field
label matches clock's actual behavior.
- Update the gallery dropdown options and bar/README docs.
TextField, NumberField, Dropdown, SearchableDropdown, and Toggle all
painted their background, border color, and border width with the same
three-line ternary ladder (`_focused ? focusFill : _hot ? hoverFill :
normalFill`). Five components × three properties × three branches is a
lot of room for one of them to drift from the others when a new state
ever gets added.
Add controlFill / controlBorder / controlBorderWidth on Style and rewrite
each call site as a single binding. No visual change.
OSD reimplemented clamp() inline when Util already has one.
PanelSlider's knob-scale binding read `mouseArea.containsMouse` directly
instead of going through a `_hot` like the other interactive controls
(TextField, NumberField, Dropdown). Mirror them so future style work
has a single property to override.
ModuleButton was a near-duplicate of WidgetButton with the same text /
active / keepSpace / tooltip / fontSize / fixedWidth / fixedHeight /
pressed signal surface, only differing in that it closed over the
enclosing root via QML's scoping rules instead of taking `bar` as a
property. Switch CustomCommandModule onto WidgetButton with
`bar: root` so we have one bar button component to maintain.
Five plugins (menu, launcher, clipboard, emojis, polkit) each looked up
OMARCHY_MENU_FONT with the same env-or-monospace fallback. Hoist the
resolution into Style so plugins read one source of truth, and so the
fallback follows the real fontconfig family Style already tracks instead
of the literal string "monospace".
Five sites hardcoded "#cacccc" or "JetBrainsMono Nerd Font" as the
fallback when no bar context was available. Those magic strings are
the *current* palette defaults — they diverge silently when the theme
changes. Bind to the Color / Style singletons so the fallback tracks
whatever the theme says the foreground / monospace family should be.
Color.qml itself keeps the literal "#cacccc" — that's the seed value
the singleton is bootstrapped with before the theme loads.
Matches the BarWidget extraction in the previous commit. The weather
panel was the only panel reimplementing the helper inline; future
panels with inline settings get it for free.
Six widgets (clock, daytime, keyboardLayout, lockKeys, activeWindow,
media) shipped identical copies of `function setting(name, fallback)`.
Eight widgets reimplemented `readonly property bool vertical`, and
three reimplemented `readonly property int barSize`. Move all three
onto the BarWidget base so widgets read the same wiring everyone else
gets for free.
While in here, drop the dead `setting()` declaration on media.qml — it
was defined but never called.
LockView hardcoded font.family to "monospace" in two places, ignoring
the user's OMARCHY_MENU_FONT / fontconfig choice that every other
summoned surface (menu, launcher, polkit, emojis, clipboard) respects.
Bind to Style.font.family so a font change via omarchy-font-set or
fontconfig propagates to the lock screen too.
CustomCommandModule.update() in Bar.qml called root.parseModuleJson(raw)
but the function was removed in 3b970068 (the indicator split). Any
custom command module emitting waybar-style JSON would have crashed on
first poll.
Hoist the helper into Util so both call sites — the bar's custom command
module and BarIndicator.extractData — share one definition.
Based entirely on the work of @robzolkos in #5711. That attempt was
adapted to better fit the standard templating system while also adding
color mixing for use in other themes.
The udev power_supply rule fires before sysfs `online` is updated on
some laptops (notably Lenovo Yoga Pro 7 14IAH10 with USB-C charging).
The autodetect branch reads the stale value and sets the wrong profile,
so the system stays on `performance` after unplug (or vice versa).
A single plug/unplug typically fires 3-4 udev events within ~1s (ACAD +
each USB-C port). With `systemd-run --unit=omarchy-power-profile
--collect`, duplicate invocations against the same unit name can be
dropped while the first is still running, so the surviving event isn't
guaranteed to be the latest one.
This adds a 0.3s settle delay at the top of the autodetect branch only.
Explicit `ac` and `battery` invocations remain instant.
Tested on Lenovo Yoga Pro 7 14IAH10 (Intel Core Ultra 9 285H, Omarchy
3.8.1).
Co-authored-by: Iqbal Attila <iqbal@kcmon.id>
The custom PositionButtonGroup component wrapped Repeater + Button
directly without setting bordered: true on the delegates. After the
recent Button changes (idle non-bordered Buttons have zero border
width), the non-selected position chips lost their visible chip
structure entirely \u2014 they rendered as floating text labels and read
as unclickable.
Replace the bespoke component with qs.Ui.ButtonGroup (which sets
bordered: true on each chip) inside a Column with a 'Position' label,
and drop the now-unused PositionButtonGroup definition. All four
options now read as clickable chips and the chosen value still paints
the accent fill+border.
Pass a section name to open the gallery with the cursor already on
that component instead of scrolling from the top. Useful when
iterating on a single widget.
omarchy dev ui-preview # default position
omarchy dev ui-preview button # land on the Button section
omarchy dev ui-preview button-group # land on ButtonGroup
omarchy dev ui-preview slider # land on Slider, etc.
The bin script forwards the argument as {"section": "..."} in the
shell summon payload. The gallery's open(payloadJson) parses it,
clamps against visibleSections (unknown names fall back to default),
and sets focusSection + selectedIndex inside the existing Qt.callLater
so the cursor's hasCursor bindings fire ensureCursorVisible
automatically.
Three small fixes around the new Button + ButtonGroup so the cursor is
always visible and the section reads as a single Button showing flag
combinations.
ButtonGroup now exposes cursorIndex + hovered(index, isHovered) so
panels can drive a single Button's hasCursor without reaching past
ButtonGroup's API. Every chip gets bordered: true so the row reads as
a real picker — distinct outlines, not just a tinted fill that vanishes
into the background.
Button's border treatment grows two paths so the cursor is always
visible regardless of other state: bordered + hot recolors the border
to the accent and thickens to the focus-ring width, and selected + hot
thickens the existing accent border to the focus-ring width (so the
cursor landing on the chosen option still reads as cursor presence,
instead of disappearing into the selected fill).
Gallery's Button section pairs each demo button with a small caption
('idle', 'active', 'icon only', 'icon + active', 'bordered +
focusable') so the row reads as one Button with its state flags side
by side rather than five unrelated buttons. The ButtonGroup section
gets the cursor wiring (cursorIndex + onHovered) plus an
onFocusedChanged auto-scroll so the cursor visual is reachable via
j/k h/l from the panel cursor model.
Wide content rows (slider rows in audio / monitor panels) opted out of
the cursor fill by setting fill: "transparent" on their CursorSurface,
which left them with no cursor visual at all — j/k landed there
silently with no way to know what was selected.
Add an `outline: bool` flag to CursorSurface. When true, hasCursor
paints an accent border (Style.focusBorderColor at
Style.focusBorderWidth) instead of a fill, leaving the row's chrome
fully visible underneath. Use for slider rows where a fill would
obscure the track.
Audio output / input slider rows and the monitor brightness row opt
in. The dev gallery's slider section replaces its bespoke Rectangle
wrapper with the same CursorSurface { outline: true }, so what the
gallery documents is what the panels ship.
The three components were three takes on the same shape \u2014 a clickable
rectangle with text/icon, a hot/hover state, an optional persistent
border, and an optional 'selected' or 'active' highlight. CursorPill
was a 30-line PillButton wrapper that added a hovered() signal;
ChoiceButton was effectively PillButton with selected: bool painting
an accent fill+border.
Collapse them into a single qs.Ui.Button. State flags compose
independently:
hasCursor / hover hot fill
active persistent foreground-tint fill
selected accent fill + accent border
bordered: true persistent 1px idle border (form primaries)
focusable: true Tab focus paints the accent ring
pressed pressed fill
The hovered(bool) signal is now built-in, so CursorPill's wrapper is
unnecessary. ButtonGroup wraps a Row+Repeater for the form-style
'pick one of N' pattern; panel-cursor-driven cases still compose
Buttons directly in a Row with per-instance hasCursor wiring.
Theme tokens move into a new [style] section in shell.toml:
border-width = 1
focus-border-width = 3
idle-border-alpha = 0.4
hot-fill-alpha = 0.08
selected-fill-alpha = 0.18
pressed-fill-alpha = 0.22
focus-fill-alpha = 0.22
Style.qml parses these out of the same shell.toml [font] / [bar]
already reads, and exposes pre-computed Style.hotFill / selectedFill /
pressedFill / idleBorderColor / selectedAccentFill / borderWidth +
the existing focusBorder* tokens. Themes that don't ship a [style]
section get the previous defaults unchanged.
Dev gallery consolidates three sections (PillButton, CursorPill,
ChoiceButton) into Button + ButtonGroup, with the cursor model
sections renamed accordingly.
CursorSurface defines the canonical cursor chrome: a tinted fill, no
border. Three components had inconsistent treatments that the recent
standardization pass left half-finished:
- PillButton kept a 1px foreground border on hot (cursor or hover)
via a cursorBordered: true default.
- CursorPill specifically had to override cursorBordered: false to
match the rest of the kit.
- ChoiceButton thickened its border to 2px on hasCursor, which mixed
the cursor visual with the Tab-focus visual.
Drop the cursorBordered escape hatch from PillButton (no caller other
than CursorPill ever used it), drop CursorPill's now-redundant
override, and remove hasCursor from ChoiceButton's border.width
thickening. Update Toggle's class comment (it still claimed cursor
mirrored Tab focus, which f3ba5055 broke without updating the doc).
Now: hot/hasCursor = fill only, activeFocus = accent border ring,
selected/active = stronger fill or accent border per component
semantic. One canonical pattern across the kit.
Themes now drive typography the same way they drive colors: one [font]
base-size in shell.toml is the rem root, and every Style.font.<token>
(caption, bodySmall, body, subtitle, title, heading, display,
displayLarge, iconSmall, icon, iconLarge) derives from it via a fixed
multiplier. Themes can also pin individual tokens for stylistic
emphasis. base-size is clamped 11..13 until row-height tokens exist.
Bar dimensions move to the same singleton: [bar] size-horizontal /
size-vertical replace the hardcoded 26/28 in Bar.qml, exposed as
Style.bar.sizeHorizontal / sizeVertical.
Style.qml also resolves the fontconfig 'monospace' alias via fc-match
and exposes Style.font.resolvedFamily so panels can display the
concrete family. Watches ~/.config/fontconfig/fonts.conf so it tracks
'omarchy font set <name>'.
The qs.Ui kit (PillButton, Dropdown, Toggle, TextField, etc.) and
every first-party plugin (bar widgets, settings, menu, clipboard,
emoji, polkit, notifications, osd, image-picker, dev-gallery) now
bind to Style.font.* instead of pixel literals. Only three deliberate
display-scale outliers remain: the notification empty-state glyph and
the weather flyout's hero temperature pair, all commented.
Background plugin's applyTheme IPC fast-path also pushes shell.toml to
Style so theme swaps update typography and bar size without waiting
for inotify debounce.
Dev gallery (omarchy dev ui-preview) now ships a Typography section
that renders the full scale and theme tokens live, and its summon
command is fixed (omarchy-shell-ipc -> omarchy-shell).
The wifi panel now has full keyboard nav over both sections:
h/l walk the DNS provider pills
j/k walk the wifi network list (j from DNS drops into the
list; k from the top row goes back to DNS)
Enter/Space apply the highlighted DNS provider / connect to the
highlighted wifi network
Esc close the panel
Single-cursor model. The visible cursor lives at the panel root via
focusSection + dnsIndex + selectedIndex. Mouse hover doesn't draw its
own highlight — onContainsMouseChanged on each row/pill MOVES the
cursor instead. Mouse leaving doesn't clear it (the cursor stays where
attention was last; subsequent j/k pick up from there). Last action
wins, whether mouse or keyboard.
New Common.CursorSurface holds the shared chrome (fill + 1px border +
fade) and is the base for both NetworkRow and the new local
DnsProviderPill. Items pass only hasCursor + current and let the
surface render. Contract: items never read containsMouse for visuals.
That's what guarantees exactly one highlight on screen at any time.
DnsProviderPill replaces Common.PillButton for the DNS row because
PillButton's hover > active > background cascade fights the
single-cursor model — its built-in hover would draw a parallel
highlight on whatever pill the pointer is parked on, even after the
cursor moved elsewhere. PillButton stays where it fits (refresh icon,
other bar widgets) and is unchanged here.
The wifi panel was a bar-widget xdg-popup which Hyprland doesn't grant
keyboard focus to until the user clicks or hovers it — keys typed after
a SUPER+CTRL+W summon went to whatever previously had focus.
New shared Common.KeyboardPanel scaffolding: layer-shell PanelWindow
with WlrKeyboardFocus.Exclusive (granted at map time, the protocol-level
equivalent of focus-on-launch for xdg-toplevels), full-screen anchored
with a Region mask that subtracts the bar strip so bar widgets stay
clickable, MouseArea for outside-click dismissal, TransformWatcher for
reactive anchor-position tracking. API is a subset of Common.PopupCard
(no centerOnBar / triggerMode / containsMouse yet — adding when the
other bar popups migrate).
networkPanel.qml uses it. Adds full keyboard navigation:
j/k or Up/Down — move selection
Return/Space — connect (or disconnect if already connected)
x — forget the highlighted network
r — refresh scan
Esc — close
ListView (with positionViewAtIndex on currentIndex) replaces the
Repeater+Column inside Flickable so the selected row stays visible as
j/k walks past the cap. A 1.5s Timer re-polls detailsProc while open
so the connection details (IP, gateway, signal) populate when routing
actually comes up after a connect rather than waiting for re-summon.
Rows: lock glyph on the right for protected-and-not-connected, X
(forget) for connected — aligned to the same 22-wide column. Connect
glyph in the passphrase prompt switched to a check, no separate cancel
(Esc handles it).
SUPER+CTRL+W in utilities.lua now toggles this panel via
omarchy-shell-ipc instead of launching Impala. Right-click on the bar
icon still launches Impala as a fallback for hidden SSIDs / enterprise
auth / iwd edge cases.
quickshell kill currently trips Quickshell #539 (notifyInternal2 event
loop crash via IpcKillCommand::exec), which leaves the Wayland surface
lingering long enough that the new instance starts on top of the dying
one — a duplicate bar. SIGKILL drops the client connection and the
compositor cleans up surfaces immediately; the shell has no persistent
state to flush. Sub-20ms restart, no duplicates.
Keep only the non-obvious bits: the override mechanism, what counts as
"active" on the bar, the flyout text-color constraint, the
notifications-border convention, and the image-picker alpha modulation.
Drop comments that just restated the key names.
Five plugins each owned their own colors.toml watcher with subtly
different parsers, plus two ad-hoc per-theme override files
(notifications.json, image-picker-colors.json). This collapses all of
that into one source of truth: Commons/Color.qml watches colors.toml +
shell.toml and exposes Color.bar.*, Color.popups.*, Color.notifications.*,
Color.menu.*, Color.imagePicker.* for every surface to bind to.
shell.toml is generated by the existing template pipeline from
default/themed/shell.toml.tpl. Themes can ship their own shell.toml to
override individual keys; everything missing falls back to the
foundational palette via root.pick(). Settings panel is intentionally
not themable beyond the foundational tokens.
last-horizon and solitude ship a minimal shell.toml to preserve their
historical 'notification border matches Hyprland active border'
behavior, which previously came from parsing the theme's hyprland.conf
(now removed).
Quickshell's UPowerDevice.percentage is a 0.0-1.0 real (energy /
energyCapacity), not 0-100. The bar was treating it as 0-100, so a 99%
charge picked the lowest icon, the tooltip read "1%", and the
low-battery active state was always true.
Settings dialogs were rendering text/spin/combo controls with Qt's
default light style, which clashed with the dark Omarchy theme — black
text on dark fills, white dropdown popups, rounded corners, and a
pill-style toggle that didn't match the native StyleToggleRow switch.
- Style.qml: collapse all radius tokens to 0 so Noctalia-compat widgets
inherit Omarchy's sharp-corner convention
- NToggle: rewrite to mirror the native 48x22 switch with accent fill
and a sliding 16x16 thumb
- NComboBox: skin contentItem, indicator, popup, and delegate so the
dropdown reads on dark themes
- NSpinBox: add a styled background, contentItem, and up/down indicators
- SettingsPanel calendar form + DynamicSettingsForm string field: drop
default TextField chrome for the same translucent foreground fill used
by WidgetCard, accent border on focus
Replace the inline detail flyout with a two-column hero: location chip
and large temperature on the left, big condition icon on the right.
Stats (Feels / Wind / Humidity) move below as caps-labeled columns,
separated from the forecast by a thin divider. Forecast cells now lead
with the day icon and put the day name above hi/lo temps.
Drop the Refresh and wttr.in pill buttons; a Timer refreshes the
forecast every refreshMinutes (default 15). The interval is exposed
through the Settings panel — Bar -> Weather has a gear that opens a
SpinBox-backed form, persisted as "settings": { "refreshMinutes": N }
in shell.json.
Replace the hover-driven detail flyout with a click-toggled popup that
includes a Noctalia-style row of upcoming days. Switching the wttr.in
fetch to the j1 JSON gives us structured current conditions plus a
3-day forecast; each day's representative icon comes from the hourly
entry nearest noon, mapped through the same code → glyph table as the
bar pill.
Text.implicitWidth/Height can be fractional. Passing those values
straight to the PopupWindow rounded the Wayland surface down, clipping
the 1px right/bottom border of the bubble.
Same logic as the waybar/mako sweep: migration 1778321093 converted the
user's top-level hypr configs (autostart/bindings/hyprland/input/
looknfeel/monitors + envs + apps/*) from hyprlang `.conf` to Lua, so
any earlier migration that seds those files is editing a path that no
longer exists on the new layout.
These were already applied on existing systems and skipped on fresh
installs (preflight marks them done before they would run), so the
change is purely repo cleanliness — the migrations dir stops mentioning
files the new omarchy doesn't have.
Deleted 18 migrations that only touched dead .conf paths:
1754389057 1755870033 1757866485 1757877123 1757877852 1760462260
1763386443 1767138576 1769543550 1770159912 1770375655 1771606249
1771847961 1772293693 1776410469 1776781957 1777620904 1778008689
Stripped dead .conf sed/cp blocks from 5 mixed migrations whose
remaining work still matters (webapp launcher fixup, uwsm env/term
config, xdg-terminal-exec install, Obsidian flags relocation, swayosd
systemd service):
1755507891 1758019332 1762121828 1776434586 1778171768
The four genuinely-alive .conf files (hyprlock.conf, hypridle.conf,
xdph.conf, hyprsunset.conf) are untouched. The converter migration
(1778321093) is untouched. The lua-targeting migration 1757879836 is
untouched.
The dev -> omarchy-shell flip migration (1778743515.sh) uninstalls
waybar and mako and moves both user-config dirs aside, so any older
migration that tweaks ~/.config/waybar/ or invokes
omarchy-{restart,refresh}-waybar / omarchy-restart-mako is editing
something that's about to be removed.
These migrations are already marked applied on existing systems and
skipped on fresh installs (preflight touches every migration name into
the state dir before they would run), so removing/editing them is a
no-op for anyone currently on omarchy. What it does fix is the repo
itself referring to commands that no longer exist on disk.
Deleted 26 migrations that were entirely waybar/mako tweaks:
1752793122 1754228071 1754331529 1756371020 1757279511 1757511571
1760693222 1760787158 1761269603 1763409505 1763560161 1763634099
1763653692 1764067068 1767227973 1767685679 1767716691 1768270644
1771602477 1771602647 1775208227 1777017528 1777464602 1777578316
1778139028 1778539119
Stripped the waybar/mako bits from 10 mixed migrations whose real work
is still relevant (impala install, light themes, wiremix, tzupdate,
xdg-terminal-exec, bluetui, terminal app-ids, voxtype GPU, walker
toggle):
1751887718 1752725616 1752896442 1753495989 1762121828 1762417304
1763386443 1773506226 1775241210 1778405462
Two leftover spots still pointed at command names that were renamed in
this branch:
- default/quickshell/omarchy-shell/README.md:124 said
`omarchy restart quickshell` (renamed to `omarchy restart shell`).
- config/hypr/bindings.lua:35 had a commented-out example using bare
`omarchy-menu`. The wrapper still works that way for now, but the
canonical hot path is `omarchy-shell-ipc menu toggle root` \u2014 update
the example so users copying it learn the right pattern.
`omarchy-shell-ipc menu toggle root` is what the keybinds use \u2014 it
skips the omarchy CLI dispatch hop and stays sub-ms. But humans don't
want to type that. New tiny wrapper restores `omarchy menu …` as the
CLI entry point:
omarchy menu → toggle root (bare invocation)
omarchy menu toggle [route] → toggle, route defaults to root
omarchy menu summon [route] → always open
omarchy menu close → close if open
omarchy menu refresh → re-parse the menu JSONCs
omarchy menu ping → health check
Internally each verb just execs `omarchy-shell-ipc menu …`. The
omarchy-CLI dispatcher overhead measures ~2ms on top of the direct IPC
path (32ms → 34ms keybind-to-visible), so the wrapper is fine for any
human-typed invocation; keybinds and the bar icon stay on
omarchy-shell-ipc to keep that ~30ms hot path.
Sibling `omarchy menu file`, `omarchy menu input`, etc. still resolve
through their own bins \u2014 the dispatcher picks the longest matching
prefix, so longer routes ("omarchy menu file") win over the bare
"omarchy menu" entry.
The old bash bin short-circuited with close_visible_quickshell_menu at
the top of open_quickshell_menu, so pressing any menu keybind while the
menu was open just closed it. The IPC path I introduced summoned every
time, so keyboard shortcuts couldn't dismiss \u2014 only outside clicks did
(which is why the bar icon appeared to toggle: clicking it while the
menu was open hit the menu's outer-click MouseArea, not the icon).
Add a menu.toggle IPC method:
- if root.opened: cancel() and return "closed"
- otherwise: behaves exactly like summon
Switch every Hyprland binding and the two bar-icon click handlers
(omarchy logo, battery right-click \u2192 power menu) to toggle. summon stays
as the always-open primitive for callers that want explicit summon
semantics (rare \u2014 right now nothing internal uses it).
With bin/omarchy-menu gone there's no caller that summons the menu by
writing a JSON tempfile and polling a done file. Drop everything that
existed only to support that handshake:
- menuJsonFile / menuJsonFileView / loadMenuJson / openMenu(json,...)
- pendingSelectionFile / pendingDoneFile / selectionFile / doneFile
- mergeProviderJson (the JSON-wrapper for provider output)
- applyProc / releaseProc / doneFilesToRelease / finishDoneFile /
releaseNextDoneFile / resetRequest / requestActive / closeMenu
- the menuBin property pointing at the deleted bin
applySelected is now four lines (close + execDetached); cancel is two
(close + clear filter). open() takes either {menu: id} or a bare initial
menu name, and hands off to openExistingMenu which uses the cached items
from the JSONC FileViews.
Net: 91 lines smaller, no perf change.
The shell now owns the menu — both data and dispatch. The 821-line bash
bin was carrying the open path (cold spawn + jq pipeline + tempfile dance
+ IPC + poll) and a grab-bag of helpers that only existed inside it. Both
go away in this commit.
New bins for the few composite helpers that were genuinely worth keeping:
- omarchy-install-app NAME PKG
- omarchy-install-and-launch NAME PKG DESKTOP_ID
- omarchy-install-font LABEL PKG FAMILY
- omarchy-launch-config-editor PATH
- omarchy-reminder-set-interactive
- omarchy-capture-screenrecording-with-webcam
Sweep through default/omarchy/omarchy-menu.jsonc rewrites:
- present_terminal X -> omarchy-launch-floating-terminal-with-presentation X
- install_terminal X -> omarchy-launch-floating-terminal-with-presentation 'omarchy-install-terminal X'
- install / install_and_launch / install_font / open_in_editor -> new bins above
- terminal X -> xdg-terminal-exec --app-id=org.omarchy.terminal X
- default_browser_is X -> [[ "$(omarchy-default-browser)" == "X" ]]
- default_terminal_is X / default_editor_is X / haptic_touchpad_is X same shape
- $(hypr_config_file X) -> ~/.config/hypr/X.lua
- show_custom_reminder_input -> omarchy-reminder-set-interactive
- screenrecord_with_webcam -> omarchy-capture-screenrecording-with-webcam
- stop_active_screenrecording -> omarchy-capture-screenrecording --stop-recording
Hyprland bindings switch from `omarchy-menu X` to
`omarchy-shell-ipc menu summon X` (the keybind hot path now skips bash
entirely). The Bar.qml omarchy widget and the battery right-click do the
same. ALT+PRINT becomes a one-liner: stop the recording if one is going,
otherwise summon the screenrecord submenu.
Measured: keybind-to-visible is ~30ms (was ~235ms). The shell's plugin
keepLoaded:true stops being theoretical \u2014 the menu data lives in memory
across opens, and the only work between keypress and paint is the IPC
roundtrip and the layer-shell window mount.
omarchy-menu used to spawn an 821-line bash bin on every keybind: 11 jq
invocations against omarchy-menu.jsonc, mktemp dance, summon, poll. The
shell waited ~235ms (keybind to visible) before painting the first row.
The bar plugin host is already a persistent process with the menu plugin
loaded (keepLoaded: true) — it just wasn't allowed to own the menu data.
Now it does:
- parseMenuJsonc / normalizeItem ports the bash bin's jq pipeline to
JS: strip // comments + trailing commas, infer parent from dotted
ids, dedupe keyword tokens across id/aliases/keywords, fill defaults.
- Two FileViews with watchChanges: true on the default and user
extension JSONCs. Edit either file and the in-memory item map
refreshes without a restart.
- IpcHandler exposes menu.summon(initialMenu) / refresh() / close() /
ping(). summon resolves aliases the way the old bash route_target
did, including the leaf-alias-is-an-action shortcut.
- Action dispatch is now direct: when summoned via IPC (no selection
or done file), Quickshell.execDetached(['bash','-lc', action]) runs
the action and the menu closes. The legacy tempfile dance is kept
only for the duration of the migration window.
- provider sub-menus (fonts, power-profiles) are inline: tab-delimited
bash one-liner per provider, parsed by mergeProviderRows.
- when:/checked: bash expressions are batched into one Process at
shell startup (and again whenever the JSONCs change). The menu
opens instantly; visibility/check marks settle within ~50ms.
Measured: keybind-to-visible via the new IPC path is ~30ms (was ~235ms).
The bash bin still works for now and is removed in the next commit.
Replace the mako-only migration with a single "complete the flip"
migration that handles everything needed to bring a dev-channel user
onto omarchy-shell:
- install quickshell if it isn't already on the box
- stop and uninstall mako; pacman -Rns deletes the .service unit too,
so D-Bus activation can't conjure it back into existence
- stop and uninstall waybar with the same uninstall-not-mask approach
- move ~/.config/{mako,waybar} aside (timestamped backup) rather than
rm -rf, so anyone with hand-tuned rules can mine them
- clear the stale toggle-state markers
- call omarchy-restart-shell so the bar and notification daemon come
up mid-session without a relog
Drop migrations/1778715864.sh: shell.json hasn't shipped to any user
yet, so a migration removing widgets nobody has is dead code.
- omarchy-bar-settings.lua is gone: the Hyprland rules it carried for
the old standalone bar-settings window no longer match anything,
since settings is now a panel plugin summoned via IPC. The still-
needed "Widget settings" sub-dialog rules move into
omarchy-shell.lua next to the existing "Omarchy Settings" rules.
- plugins README documents the `bar` plugin kind so third-party
plugin authors aren't surprised to see it on the first-party
omarchy.bar manifest. The note also calls out that they should ship
`bar-widget`s, not replace the host bar.
- omarchy-style-bar-position seeds from shell-defaults.json before
mutating, so a user without a shell.json (or with a malformed one)
no longer ends up with a stub config that blanks the bar layout.
omarchy-font-set already updates ~/.config/fontconfig/fonts.conf, which
is what fc-match, Qt, and every other XDG app reads from. Storing the
same family in shell.json gives the same value two homes that can drift
apart, and stops the bar from picking up font changes without a shell
restart.
- omarchy-font-set stops writing bar.fontFamily to shell.json and stops
poking ~/.config/waybar/style.css. fontconfig + terminals + hyprlock
+ swayosd are still updated as before.
- omarchy-font-current reads fc-match monospace -f '%{family}' and
takes the first comma-separated entry; the old jq-on-shell.json
path is gone.
- Bar / SettingsPanel / NDropdown.qml default fontFamily to
"monospace" and stop reading config.fontFamily. Qt resolves the
family through fontconfig at paint time, so omarchy-font-set updates
the bar live with no reload.
- shell-defaults.json drops bar.fontFamily.
User-visible effect: pick a Nerd Font, the bar follows it. Pick a font
without glyphs and you get tofu — same failure mode the terminals and
hyprlock already had.
The bin names should reflect the thing they manage. `refresh bar` is
misleading because the command resets the entire shell.json (which holds
plugins beyond just the bar), and `restart quickshell` names the runtime
rather than the product. Both now end in `-shell` to match the rest of
omarchy-shell.
Updates every caller in autostart, the menu, voxtype helpers, and the
shell README. No behavior changes.
omarchy-shell's bar plugin replaces waybar on every default path, so the
waybar package, configs, indicator scripts, and toggle/restart/refresh
binaries all go away in this commit.
The four small helper scripts that Bar.qml shells out to (weather.sh and
indicators/*.sh) move with the shell rather than disappear \u2014 they live
at default/quickshell/omarchy-shell/scripts/ now, alongside the rest of
the shell code.
Companion script changes:
- omarchy-shell-ipc gains --if-running so fire-and-forget refresh
callers (toggle-idle, toggle-notification-silencing,
update-available-reset, capture-screenrecording) don't accidentally
spawn the shell when it isn't already up.
- omarchy-theme-set, omarchy-tz-select, omarchy-voxtype-{install,model},
omarchy-toggle-nightlight, omarchy-voxtype-config drop their waybar
branches and comments.
- omarchy-voxtype-status's summary stops claiming it's a Waybar helper.
- omarchy-base.packages drops waybar; install/packaging/fonts.sh's
comment points at the new bar consumer.
- SKILL.md / AGENTS.md / omarchy-menu.jsonc lose their waybar entries.
- test/omarchy-cli-test.sh substitutes a remaining toggle command.
Chat apps (Vesktop, etc.) can rapid-fire the same Notify D-Bus call when
they sync, leaving the pending tab with hundreds of byte-identical rows
because the old handler appended unconditionally and never re-entered the
`markSeenByOriginalId` path for follow-up arrivals.
- addToPending + popup-insert now remove any existing row matching the
same `originalId` before insertion, honoring the freedesktop
"replaces_id" semantics that chat apps rely on.
- loadHistory dedupes by originalId on hydration, so existing on-disk
files with the old duplicate-laden schema collapse on next start.
- loadHistory also guards against re-entry: FileView fires onLoaded
more than once during startup (initial preload + Component.onCompleted
reload), and the old version would double the model each fire.
While in here, move the persistent notifications.json out of `~/.cache`
to `~/.local/state/omarchy` so a "clear cache" habit no longer drops
DND preference and notification history. The image thumbnail cache stays
in ~/.cache where regeneratable artifacts belong.
- Discovered devices now populate via a new `discoveredDevices` filter; the
Repeater was referencing a property that did not exist.
- Pairing chains into trust + connect at root scope, so freshly-paired
devices (especially audio headphones) persist in BlueZ and actually
finish connecting instead of flashing "Connected" and disappearing.
- Wrap the device list in a Flickable capped at 400px with a scroll bar
so crowded RF environments do not grow the popup off-screen.
- Reorder MouseAreas so the per-row X button receives clicks instead of
the full-row click handler swallowing them.
Adds first-party omarchy.notifications service plugin that hosts a
freedesktop notification server and renders popups + a history popup
inside the shell. Uninstalls mako and retargets every helper, keybind,
indicator, and migration entry to the new daemon.
Plugin (default/quickshell/omarchy-shell/plugins/notifications/):
- Service.qml: NotificationServer, popupModel + pendingModel + pastModel
(two-tier history, see below), DND via PersistentProperties +
cache-file backstop, image cache for /tmp screenshots, IpcHandler with
toggleDnd/setDnd/isDnd/showHistory/clear/clearPending/markAllSeen/
dismissAll/dismissOne/invokeLast/dismiss, per-theme override file
~/.config/omarchy/current/theme/notifications.json honoring
borderColor/backgroundColor/textColor/countdownColor.
- components/NotificationCard.qml: theme-driven card (Color.foreground/
background/border tokens from Commons/Color.qml), 32x32 icon slot,
Nerd Font glyph fallback via omarchy-glyph hint, hero image strip
for screenshot/image-path notifications, hover-pause progress bar,
uses bar.fontFamily so all surfaces share one font.
Filtering and DND:
- transient hint and CLI-style senders (app_name in notify-send /
omarchy-action) bypass history but still pop.
- DND only allows omarchy-action toasts and notify-send -u critical
through; real-app urgency=critical (Discord, Slack, Vesktop) is
silenced and lands in pending instead.
- Pending vs past split surfaced via tabs in the bar widget popup;
past tab is auto-pruned at the 15-minute mark.
- Click-to-jump: notifications without a libnotify default action focus
the matching Hyprland window via class lookup.
Shell host:
- shell.qml: generic first-party service loader (mirrors the existing
noctalia-compat path) and an alias for the bar so plugins can read
barSize / barHidden / position for anchoring.
- Commons/Color.qml: parses the theme's hyprland.conf for
$activeBorderColor so notifications match Hyprland window borders;
picks the explicit accent= key over the color4= alias.
Bar widget rebase (plugins/bar/widgets/notificationCenter.qml):
- Drops the chunk-1 stub server, binds count/dnd state to the service,
hosts the history popup via PopupCard so it drops down from the
notification glyph the same way Quick Settings does.
- Pending/Past tabs, dismiss-individual close X, mark-all-as-seen and
clear-recent action buttons, theme-driven palette.
Quick Settings rework (plugins/bar/widgets/controlCenter.qml):
- DND tile binds directly to service.doNotDisturb for instant feedback.
- Drops the volume slider (already in audioPanel) and the no-op Theme
tile; adds a Bluetooth toggle bound to Quickshell.Bluetooth.
- Bigger 44x44 wallet was scaled back to 32x32 for tighter rows.
Notification scripts (bin/omarchy-*):
- omarchy-notification-send: passes glyph as a custom hint instead of
prepending to the summary; adds -a omarchy-action and -u urgency
automatically; supports -e/--transient passthrough.
- User-action toasts in the capture / toggle / hyprland / default-*
scripts and bindings/utilities.lua now tag themselves
-a omarchy-action so DND treats them as intent-based bypass.
- omarchy-toggle-notification-silencing, omarchy-notification-dismiss,
default/waybar/indicators/notification-silencing.sh, and the Hyprland
comma-keybinds all route through omarchy-shell-ipc notifications.
- omarchy-capture-screenshot / -screenrecording set the image-path
hint properly so the hero-image rendering kicks in.
Mako removal (migrations/1778743515.sh):
- pkill -x mako, systemctl --user stop mako.service, pacman -Rns mako
(uninstalling deletes /usr/lib/systemd/user/mako.service so D-Bus
activation can't respawn it). Removes ~/.config/mako/ and the legacy
toggle file. Restarts quickshell so it claims the bus name.
- Drops mako from install/omarchy-base.packages, autostart.lua,
install/config/theme.sh + toggles.sh, default/themed/mako.ini.tpl,
default/mako/, the omarchy-menu Mako restart row, bin/omarchy
GROUP_DESCRIPTIONS, the settings panel catalogue, and the
default/omarchy-skill paths table.
- Removed scripts: bin/omarchy-restart-mako,
bin/omarchy-style-corners-mako.
- bin/omarchy-style-corners summary updated; corner radius for the
notification card reads ~/.local/state/omarchy/toggles/quickshell-menu.json
alongside the rest of the shell.
GitHub's default branch on basecamp/omarchy is no longer master, so
a plain clone pulls the development branch. Pass --branch master so
reinstalls always land on stable regardless of repo default.
Pad the percent text to 3 chars with printf so " 5%", " 50%", and
"100%" render at identical width in the JetBrainsMono monospace label.
Previously the popup container resized between events because the
label string varied between 2 and 4 characters, which caused the
popup to visibly jump in width on consecutive brightness key presses.
Builds on #5525, which made the percent values themselves step
uniformly; this completes the loop by making the rendered popup match.
Co-authored-by: Mateus Pegorim <14262063+Pegorim@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The tray drawer reserves space for its slide-in animation; placed
mid-section that gap was always visible. Now:
- normalizeLayout moves any tray entry to the section's inner edge
(start of right, end of left/center) so the reserved gap sits next
to the bar center instead of stranded mid-section.
- TrayModule reads its own entry settings to support pinned[] and
hidden[] arrays of SNI ids. Pinned icons render to the right of the
chevron (always visible); hidden icons never render; the rest fall
into the drawer.
- Right-click the chevron opens a management popup listing every
reporting tray item with Pin/Unpin and Hide/Show pills. Toggles
persist via shell.updateEntryInline.
- Bar imports common/ as BarCommon so the tray can reach PopupCard
and PillButton for the popup.
Bar now shows just the chip glyph; hover opens the existing CPU+Memory
graphs popup, left-click launches btop. Removes the inline sparklines,
the right-click→alacritty binding, and the redundant Open btop pill.
Rename apps/quickshell.lua to apps/omarchy-shell.lua and gather every
rule that targets a Quickshell surface owned by the shell:
- menu and image-selector layer rules (image-selector moved out of
apps/system.lua, where it didn't belong with generic floating /
media / idle rules)
- new window rules so the settings panel floats centered at 960x700
instead of tiling
The settings panel is a transient dialog, not a workspace surface, so
tiling it disrupts the layout and leaves it awkwardly tall when it lands
in a half-screen split. Class+title scoping keeps the rule from leaking
into other org.quickshell windows (menu, image picker, etc.).
The previous clearBodyFocus() set focus = false on navRoot.activeFocusItem
and called navRoot.forceActiveFocus(), which works for plain Rectangles
but not for Controls 2 widgets like ComboBox: the combo keeps an internal
focused child that the surrounding FocusScope happily restores, so the
accent focus border on the Position/Center anchor dropdowns lingered
after backing out to the sidebar.
Add an invisible 1x1 navFocusSink Item inside navRoot and force focus
onto it whenever the user leaves the body (h/Esc/Shift-Tab, category
changes from sidebar nav, or panel reopens). The sink reliably owns
activeFocus so every body control \u2014 ComboBox included \u2014 falls back to
its unfocused style.
Two related fixes from user feedback on the keyboard nav:
1. Focused and selected controls were drawing the same 2px accent border
so it was impossible to tell where the keyboard cursor was on a row
that happened to also be the current value. Focused now uses a 3px
accent border plus a translucent accent fill; selected keeps its 2px
border with no fill. Centralized into focusBorderColor /
focusBorderWidth / focusFillColor so all components share the look.
2. Backing out of the body to the sidebar (h/Left/Esc) left the focus
ring lingering on the body item. FocusScope was restoring activeFocus
to its remembered descendant when navRoot reclaimed focus.
exitBodyZone (and onActiveCategoryChanged when not in body mode) now
clears focus from the previously active descendant before forcing
focus back onto navRoot.
Two zones — sidebar and body — with vim-style bindings:
sidebar j/Down next category
k/Up previous category
l/Right/Tab/Enter/Ctrl-L enter body
Esc close panel
body j/Down/Tab next focusable
k/Up/Shift-Tab previous focusable
Enter/Space activate focused control
h/Left/Esc/Ctrl-H back to sidebar
Wraps panel content in a FocusScope with Keys.priority: Keys.BeforeItem
so j/k always reach the nav handler even when a child control has focus.
Body focusables are gathered by walking the visible subtree of the active
category for items with activeFocusOnTab — automatically excluding
hidden category branches. Sidebar shows an accent-tinted highlight when
focused; each interactive control (DefaultsRow, StyleOptionTile,
StyleChip, FontRow, StyleToggleRow, ActionPill, IconButton, PluginRow)
renders an accent focus ring while focused.
Consolidates bar-settings into a single 'settings' plugin with sidebar
categories: Defaults, Style, Bar, System, Plugins. Updates supporting
commands (omarchy-launch-settings, omarchy-style-corners-quickshell,
omarchy-theme-list-with-previews, omarchy-hyprland-monitor-scaling-set)
and refreshes sidebar glyphs to Nerd Font icons.
Network panel now polls 'ip route get 1.1.1.1' for the active interface
and renders a key/value grid with IP/CIDR, gateway, link speed +
duplex (ethernet) or signal/freq/bitrate (Wi-Fi). One bash script
collects everything in TSV.
Wi-Fi list now works on Omarchy's default iwd+impala stack: when
nmcli isn't installed, falls back to 'iwctl station <dev> get-networks'
and parses the connected/SSID/signal/security columns. The list is
hidden entirely when no Wi-Fi station device exists (ethernet-only
machines).
Right-click on the bar widget and the bottom 'Open Wi-Fi manager
(Impala)' button both run omarchy-launch-wifi directly (was wrapped
in extra OMARCHY_PATH= env that wasn't actually doing anything).
Was gated on isConnected; users with paired-but-disconnected devices
(or devices Quickshell hasn't flagged as connected yet) saw no button
at all. Now shows on every known device. Action follows state:
connected -> disconnect, otherwise -> forget. Tooltip label flips to
match.
Bluetooth rows no longer hover-show a tooltip — clicking to connect
or pair is self-evident from the layout. Connected rows now ignore
their own click and surface a small × button on the right that
disconnects (with its own tooltip + urgent-color hover affordance).
Right-click still forgets the device.
PillButton's attached ToolTip is now a styled instance — uses the
widget's foreground color for text + border and a configurable
tooltipBackground (defaults to a near-black, overridable to
bar.background). No more stock OS chrome inside our popups.
Bluetooth panel passes bar.background/foreground through to its
header pills and replaces the row tooltip with the same themed style.
Each device row is now a two-line entry: name on top, status on the
bottom (Connected · 80%, Connecting…, Pairing…, Disconnecting…, Failed,
Available · click to pair, or Paired). Status text and the bluetooth
icon both color-code by state — connected/active draws in foreground,
idle in dim, failed in urgent.
Pending click attempts arm a 10s timer; if the device hasn't reached
the expected state by then the row flips to 'Failed' with an urgent
color so you can see the connect attempt didn't take. State change
listeners clear the pending flag the moment the device actually
connects or pairs.
Hover tooltips and right-click-to-forget moved into the row so the
behavior is self-contained.
- Scan and Manage are now small icon-only buttons in the header beside
the On/Off pill, with hover tooltips via the new PillButton.tooltipText
prop (backed by QtQuick.Controls ToolTip).
- New discoveredDevices list pulls everything in Bluetooth.devices that
isn't paired/connected/bonded/trusted. While scanning, those appear
under a 'Discovered' header. Click pairs and connects.
- Empty-state text only shows when there are no known and no
discovered devices, otherwise it would push down real entries.
- Header now uses anchors so the on/off pill sits cleanly at the right
instead of relying on a fixed-width spacer that drifted as content
grew.
- Discovery toggle moved out of the header and into a labeled action
row alongside a new 'Manage…' button that launches
omarchy-launch-bluetooth (the Impala TUI).
- Empty-state message tells you what to do based on adapter state
(off / scanning / no paired devices) instead of one generic line.
wttr.in query switched from one-blob format to pipe-delimited fields
(location|condition|temp|feels|wind|humidity). The popup parses each
piece into its own property and renders a clean key/value grid:
fort lauderdale, florida, us
Partly cloudy
Temperature +82°F (feels +91°F)
Wind ↗15mph
Humidity 82%
[Refresh] [wttr.in]
PopupCard gains a triggerMode property — "click" stays as the default
(focus-grab dismissal), "hover" skips the grab so the cursor can move
freely between the trigger and the card. PopupCard also exposes a
containsMouse alias for widgets that want to coordinate hover state.
Weather widget now shows on hover and hides 220ms after the cursor
leaves both the trigger and the popup. The redundant tooltip is gone —
the popup is the detail view. Click is still wired for refresh
(middle) and notification dump (right).
PopupCard now uses HyprlandFocusGrab so any popup in the shell closes
when the user clicks outside it (or any other window in the listed set).
Single primitive — every widget gets it for free.
Weather popup rewritten:
- Smaller cloud glyph beside the city name on one row, both vertically
centered.
- Condition string flows on its own line and wraps inside the popup.
- Refresh and wttr.in pills sit side by side instead of stacked, no
more dead vertical space.
- contentHeight tracks the actual content height so the popup is no
taller than it needs to be.
The legacy 'workspaces' built-in renders cleaner than the animated
workspacesPro file widget. Removed the widget file, its first-party
registration in Bar.qml, and updated the default layouts and docs.
'workspaces' loses the (legacy) tag in the catalog since there's no
alternative anymore.
omarchy.bar-settings and omarchy.image-picker are shell infrastructure —
the customizer and image picker themselves. Listing them in 'Other
plugins' with move/remove arrows is misleading: removing the panel
plugin doesn't disable anything (it's summoned on demand via IPC), and
adding them never made sense.
Dropped them from shell-defaults.json's plugins[] and from the inline
builtinShellConfig fallback. normalizeDraft and availableToAdd now skip
manifests with __isFirstParty so existing user shell.json files
self-heal on next load.
Two handlers were declared for the same property-change signal — QML
refuses to load the file with 'Property value set multiple times', so
summoning omarchy.bar-settings failed silently. Merged the debug log
into the existing catalogRevision++ handler.
suppressReload was eating the file-watch callback that would have
called loadConfig and refreshed the draft from disk, so the GUI stayed
on the pre-reset layout even though bar.json was already correct.
Apply the reset payload directly to draft (and bump draftRevision) so
section editors re-render in the same frame.
Every layout mutation (add/remove/reorder, settings dialog Apply,
position or centerAnchor change) now writes ~/.config/omarchy/bar.json
immediately. No more Save button — replaced with an inline 'Auto-saving
to ...' status line next to Reset to defaults.
To stop the FileView feedback loop (write → inotify → reload → set
draft → write again) the shell keeps a one-shot suppressReload flag
that swallows the userFile.onLoaded triggered by our own setText.
Reset previously could zero the bar out when defaultConfig was empty —
either because bar-defaults.json hadn't finished loading or because the
resolved path was wrong. The shell now carries an inline builtinBarConfig
that mirrors bar-defaults.json, and Reset uses it whenever the on-disk
defaults aren't yet populated.
Also: log the resolved omarchyPath / defaultsPath / userConfigPath at
startup, and route FileView load failures through console.warn so the
next time a user hits this they can see why.
The diff serializer would write only the sections the user touched and
rely on the bar merging defaults back in at load time. After a Reset to
Defaults the user file became {}, so the next 'Add widget' diffed
against the section and wrote ONLY the user-added entry, dropping every
default widget the user could see in the GUI.
- Reset to Defaults now writes the merged defaults verbatim so the GUI
and bar.json agree on the full widget list, and any subsequent edit
operates on that explicit list.
- Save writes the full draft, not a diff. The user gets a predictable
what-you-see-is-what-you-save customizer at the cost of Omarchy
defaults changes not silently propagating after the first save.
Quickshell.shellDir points at the directory holding the loaded
shell.qml, so the bar can find its own widgets and bar-defaults.json
without depending on OMARCHY_PATH being set in the environment. The
old behaviour silently fell back to ~/.local/share/omarchy when the
env var was unset, which is fine for the installed shell but caused
'No such file or directory' for every first-party widget when running
quickshell -p straight from the repo.
- firstPartyWidgetSource now uses Qt.resolvedUrl("widgets/<name>.qml")
so the resolution is anchored to shell.qml itself.
- deriveOmarchyPath() in both bar/shell.qml and bar-settings/shell.qml
walks back from Quickshell.shellDir to find the omarchy root, with
OMARCHY_PATH still allowed as an explicit override and the install
default as a final fallback.
CRITICAL:
- Re-inject working entry into the settings form every time the dialog
opens. Previously the Loader's onLoaded only fires when the
sourceComponent identity changes, so reopening the dialog on the same
widget id (or on a second instance of the same id, e.g. two spacers)
showed stale field values.
- 'Add widget' menu and the centerAnchor dropdown both read
draft.layout[section] without depending on the section array
identity. Mutating the array in place did not invalidate those
bindings, so the menu would show a stale availability list and let
non-spacer widgets be added twice. Layout mutations now replace the
whole object so any binding that reads it re-evaluates.
WARNINGS:
- Save now writes only the diff against the merged defaults so future
bar-defaults changes are not silently shadowed by a stale snapshot.
- FileView onFileChanged handlers simplified to a single reload() —
the explicit second loader call was duplicating loadConfig and
bumping barConfigSerial twice per change (visible flicker).
- userFile onLoaded ignores reloads while the user has an unsaved
working draft so external edits during editing do not clobber the
in-progress state.
- SpinBox forms switched from onValueChanged to onValueModified so the
initial-value bind no longer fires fieldChanged.
- Hyprland window-rule sizes aligned with the FloatingWindow
implicitWidth/Height values (720 main, 380 dialog).
- omarchy-launch-bar-settings falls back to initialTitle when focusing,
so a dialog that has not yet had its title applied still surfaces
the existing instance.
Each layout entry is now an object — {id, ...inline settings} — instead
of a (name, separate modules map) pair. Multiple instances of the same
widget are trivially supported (spacer is the main beneficiary). Settings
travel with the entry, so reordering keeps them attached.
shell.qml:
- normalizeLayout converts string entries to {id} and drops invalid ones
- ModuleSlot binds to a full entry; moduleName and moduleSettings derive
from it via entryId/entrySettings helpers
- centerAnchor lookup walks layoutEntries directly
- builtinBarConfig defaults use the object form
- README + bar-defaults.json updated to the new schema
bar-settings/ (new Quickshell config):
- Top toolbar with Reset / Save and Position / centerAnchor dropdowns
- Three section editors (left/center/right) with current widgets shown
as cards: name + description + move up/down/settings/remove buttons
- '+ Add widget' menu per section, sorted alphabetically by display name
(only spacer can repeat; everything else is one per bar)
- Per-widget settings dialog (FloatingWindow) loads an inline schema for
widgets in the catalog. Initial schemas: spacer (size), calendar
(formats), brightness (step)
- FileView { atomicWrites } writes to ~/.config/omarchy/bar.json on Save
omarchy-launch-bar-settings + hypr window rules pin the settings window
to a 760px floating square. controlCenter gains a 'Customize bar…' button
that launches it.
Single bar button (md-tune-vertical glyph) that opens a popup with the
controls most users reach for repeatedly throughout the day:
- Volume slider + mute toggle (Pipewire defaultAudioSink)
- Brightness slider (brightnessctl, coalesced via writeTimer)
- 2x2 tile grid: Do Not Disturb (makoctl mode), Night Light (omarchy-
toggle-nightlight, temperature probed), Keep Awake (hypridle pid
detection), Theme (current symlink + opens omarchy menu themes)
- Power-profile row (Saver / Balanced / Performance), hidden when
power-profiles-daemon is not installed
Polled every 3s via Process + StdioCollector pairs gated by !running
busy checks. Default layout adds it before powerMenu on the right.
- nightLight queries hyprctl hyprsunset temperature to detect state
instead of pgrep, since omarchy-toggle-nightlight keeps the daemon
running across toggles. Adds a 'toggling' busy flag so repeated
clicks do not stack the toggle script.
- lockKeys reads each LED individually and emits 'missing' when the
class is absent, fixing column-shift mislabels on keyboards that
only expose a subset of the locks. Hides + stops polling when no
LEDs are reported. Poll interval relaxed to 2s.
- activeWindow right-click now calls toplevel.close() against the
captured window instead of dispatching killactive against whatever
is focused at click time.
- Drop unused Common imports from activeWindow and lockKeys.
- activeWindow: shows the focused toplevel title from Quickshell.Wayland
ToplevelManager. Left-click activates, middle-click closes, right-click
killactive. Hidden in vertical bars to avoid title rotation noise.
- nightLight: toggles omarchy-toggle-nightlight; status detected via
pgrep hyprsunset. Hides when hyprsunset isn't installed.
- keyboardLayout: shows current xkb layout short code, click cycles via
hyprctl switchxkblayout. Refreshes on Hyprland activelayout events.
- lockKeys: caps/num/scroll lock indicators read from /sys/class/leds.
Uses plain A/1/S letters; hides each indicator when off.
- spacer: configurable blank space (size) for layout tuning.
Defaults add activeWindow to the left section and nightLight to the
right section between audioPanel and brightness.
- powerProfile now hides on machines without power-profiles-daemon by
checking against the published profile set rather than a never-undefined
enum, and uses mdi-scale-balance for Balanced (not battery-charging).
- networkPanel renames the QML-keyword-shadowing 'signal' property to
'signalStrength'; ethernet glyph corrected to mdi-ethernet (not the
access-point icon).
- workspacesPro indicator color guards against null bar during construction.
- Common.Slider keeps an internal liveValue so external value bindings
survive a drag; sliders fed from PipeWire/brightnessctl now follow
external changes after the user interacts.
- audioPanel drops the redundant default-sink PwObjectTracker since the
candidate-sinks tracker already covers it.
- networkPanel guards scan/connect commands against re-entry while the
previous Process is running.
- notificationCenter only instantiates its NotificationServer when the
module is opted in via settings.replaceMako (default off) so it does
not collide with mako out of the box.
- PopupCard fully opaque while open (previously 0.98) — removes a
visible ghost outline on first render.
- Drop dead code: calendar trailing MouseArea, weatherFlyout's unused
parseForecast/forecast property, idleInhibitor's holdSeconds,
media's scrollAnim.position; gate media's scroll animation off in
vertical bar mode.
- Replace nerd font glyphs that were stripped during the initial widget
writes with verified codepoints sourced from the JetBrains Mono Nerd
Font cmap (cpu-64-bit, scale-balance, notification-clear-all, etc).
- systemStats now switches to a Column layout when the bar is vertical
so the widget no longer overflows a 28px-wide side bar.
- Remove notificationCenter from defaults: it registers a notification
server and would collide with the mako daemon Omarchy autostarts.
- PopupCard owns the popout coordinator lifecycle and delegates close to
its widget owner when provided; calendar and media now pass owner.
- brightness debounces brightnessctl writes through a coalescing timer
to avoid spawning a process per slider tick.
- audioPanel tracks unfiltered Pipewire sinks/streams via PwObjectTracker
so audio metadata becomes available before filtering.
- ModuleSlot re-injects bar/moduleName/settings whenever the bar config
serial changes so widget settings update live with bar.json.
- Guard null bar references in workspacesPro and systemStats components
that are constructed before bar injection.
Introduces a widgets/ directory of first-party QML modules and a common/
helpers library. Widgets auto-load by name from
default/quickshell/bar/widgets/<name>.qml — no edits to shell.qml needed
for additions beyond the firstPartyWidgets registry.
New widgets (all orientation-aware, top/bottom/left/right):
- media: MPRIS now-playing with scrolling label, cover art popup,
play/pause/skip controls
- audioPanel: master volume slider, output device picker, per-app mixer
- networkPanel: Wi-Fi scan + connect, current connection details
- bluetoothPanel: paired device list, connect/disconnect, battery
- calendar: month grid popup keyed to today
- notificationCenter: live notification feed, DND toggle, clear all
- brightness: slider popup with scroll-to-adjust
- powerProfile: power-saver/balanced/performance picker (UPower)
- systemStats: inline CPU + RAM sparklines, expanded popup with btop
- weatherFlyout: weather popup with refresh and full report
- workspacesPro: animated focus indicator that slides between workspaces
- powerMenu: lock/suspend/log out/reboot/shutdown popup
- idleInhibitor: coffee-cup toggle wired to omarchy-toggle-idle
- microphone: mic state + mute toggle + scroll volume
Common helpers (default/quickshell/bar/common/):
- WidgetButton: hover/press scale animation, tooltip integration
- PopupCard: orientation-aware anchor + slide-in opacity transition
- Slider: drag/wheel-able linear slider with knob hover bump
- PillButton: rounded action button with icon + label
Bar root gains requestPopout/releasePopout so only one popup is open at
a time across widgets.
Updates bar-defaults.json to ship the new widgets out of the box while
keeping the legacy modules available.
* Agents should use the notification helper
* Turn a single RetroArch game into its own application launcher
* Tweak installer
* Extract selection logic into cli
* Use consistent glyph
* One more
* Persist Bluetooth power state across reboots
BlueZ defaults to AutoEnable=true, which forces controllers on at boot
regardless of the last user-set state. Setting AutoEnable=false makes
bluetoothd respect the persisted Powered state, so toggling off in
bluetui (or any DBus client) survives a reboot.
Adds the change to the install path and a migration for existing setups.
* Set reboot-required in Bluetooth persistence migration
Per review feedback, the AutoEnable=false change only takes effect on
bluetoothd startup. Without setting reboot-required, omarchy-update-restart
won't prompt the user to reboot, so the fix would only kick in at their
next organic reboot — by which time the bug may appear unfixed.
Matches the convention in migrations/1776346552.sh and similar.
* No need to ask for a reboot when this is available on the next one
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Fires after the channel template is copied to /etc/pacman.conf and before
`pacman -Syyuu` runs, letting users layer custom Pacman repositories or
IgnorePkg directives onto the freshly-written config so they're respected
by the upgrade. Useful for users running on overlay distros (CachyOS,
Chaotic-AUR, internal company repos) where a wipe-and-reinstall would
otherwise pull vanilla Arch versions.
Ships with `pre-refresh-pacman.d/add-custom-repo.sample` showing the
pattern.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Change monospace match from mode="assign" binding="strong" to
mode="append" binding="same" so the system font acts as a fallback
instead of overriding explicit app font configs like Ghostty's font-family.
Add migration to fix existing user configs.
Fixes#5675
* Trash imv deletes; add Ctrl+E to edit in Satty
Ctrl+X / Ctrl+Shift+X now move the image to the freedesktop trash via
`gio trash` instead of unconditional `rm`, so accidental presses are
recoverable from the file manager's Trash.
Adds Ctrl+E to open the current image in Satty (already in
omarchy-base.packages) and quit imv, mirroring the typical
screenshot → annotate workflow.
* Add -- separator to gio trash invocations
Prevents filenames starting with - from being parsed as options.
* Scope branding image pickers to ~/Pictures, fix About transcode mode
The "Set From Image" path in both Style → About and Style → Screensaver
was scanning all of $HOME for *.svg / *.png and feeding the result into
Walker dmenu. On a populated home directory this can be tens of thousands
of entries, leaving the picker effectively unusable.
Scope the picker to ${XDG_PICTURES_DIR:-$HOME/Pictures}, matching the
pattern already used in omarchy-capture-screenshot.
While here, drop the hardcoded --mode block from omarchy-branding-about
so the About transcode falls back to the default braille mode, matching
what omarchy-branding-screensaver does and what stock about.txt ships
with. The reduced --width 54 stays so the result fits the fastfetch
logo column.
* Explain the scope of the picker
---------
Co-authored-by: Gavin Nugent <245706154+28allday@users.noreply.github.com>
Co-authored-by: David Heinemeier Hansson <david@hey.com>
* Waybar positioning and shape
* Reveal weather again on left/right
* Fix indicators moving bar left/right
* Clean it up
* Cleanup
* One step forward, one step backwards
* Fix styles
* More style massage
* More tweaks
* Just position for now
* Fix keys
* No longer needed
* No need to reset
* Simplify
* Reset but protect waybar configs
* Not needed
* Fix glyph
* Not needed
* Cleanup
* Better wording
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
It was comparing NextElapseUSecMonotonic against /proc/uptime, but those
values aren’t in the same monotonic timeline for user timers, so valid
upcoming reminders were being skipped.
* Configure Dell XPS haptics directly
* Use packaged Dell XPS touchpad haptics service
* fix: keep one Dell haptics migration
* We already have a dedicated Trigger > Hardware menu
* Name for action
* Moved
* Need to make the package available for offline
* Simplify
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
* Split fido2 and fingerprint setups into setup and remove
Don't make one thing do two things
* Extract helpers and clean up
* No need to hide them
* Don't need these
* fix(weather): Use local units for temperature and wind
Remove the metric-to-imperial temperature conversion and display
temperature and wind values as returned for the current locale.
* Don't need this comment
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
`DefaultLimitNOFILESoft` is not a valid systemd configuration key.
systemd silently ignores it and emits this warning on every boot,
for both the system manager (PID 1) and the user manager:
Unknown key 'DefaultLimitNOFILESoft' in section [Manager], ignoring.
The consequence is that the script's stated goal of raising the soft
fd limit from 1024 to 65536 has not actually been happening: dev
tools (VS Code, Docker, dev servers, databases) continue to run with
systemd's default 1024 soft limit.
The valid key is `DefaultLimitNOFILE`, which accepts either a single
value (sets both soft and hard) or `SOFT:HARD`. Using `65536:524288`
raises the soft limit while preserving systemd's typical 524288
hard-limit default — using the bare `=65536` form would lower the
hard limit, which would be a regression.
After this change and `systemctl daemon-reexec` on both managers,
`systemctl show | grep DefaultLimitNOFILE` reports:
DefaultLimitNOFILE=524288 (hard)
DefaultLimitNOFILESoft=65536 (soft, derived display attribute)
and the boot-time "Unknown key" warnings disappear.
(The typo likely originated from someone reading `systemctl show`
output, where `DefaultLimitNOFILESoft=` appears as a read-only
display attribute for the soft component of the parsed limit.
It looks like a config key but isn't.)
* Extract notification command for using the correct spacing
* Add easy to set reminders
* More human
* Clear and direct hotkeys
* Split
* Bake reminders into the skill
* Run SwayOSD as a session service
* Restart SwayOSD after clean exits
* We don't need the input backend (as we manage the hotkeys in Hyprland)
* Ensure we cleanup the old service starter
* Not needed
* Not needed either
* Clean up migration
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
* Adjust condition to also match non-X series Panther Lake GPUs.
* Add migration to install GPU acceleration on non-X Panther Lake systems.
* Update comment with Non-Arc Panther Lake GPUs mentioned.
* Simplify conditions in the migration
* Set default terminal, browser, editor explicitly
* Consistent glyphs and setup
* Tweaks
* Always there
* Proper order
* Don't make a browser the default just because it's getting installed
2026-05-07 16:11:48 +02:00
956 changed files with 56305 additions and 7908 deletions
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
# omarchy:aliases=omarchy screenshot
```
# Runtime Environment
-`$OMARCHY_PATH` is set at the top level by the uwsm session environment and is always available to Omarchy runtime code.
- Commands in `bin/` and Quickshell QML should rely on `$OMARCHY_PATH` / `Quickshell.env("OMARCHY_PATH")`; do not derive fallback paths from `HOME`, `Quickshell.shellDir`, or re-export/default `OMARCHY_PATH` manually.
# Privileged Commands
- Whenever you need to trigger a sudo command, use `pkexec` so it results in a user prompt they can approve.
# Git
- Commits should be atomic: include only one coherent change or fix, and do not mix unrelated work.
- Commit messages should be succinct and describe the change being made.
# Install Scripts
Install entry points (`install.sh`, `boot.sh`) use `#!/bin/bash`. Many scripts under `install/` are sourced via `run_logged` and intentionally do not have shebangs.
@@ -80,8 +92,10 @@ Raw `command -v`, `pacman`, and `pacman-key` are acceptable in bootstrap/preflig
Use these instead of raw shell commands:
-`omarchy-cmd-missing` / `omarchy-cmd-present` - check for commands
-`omarchy-pkg-missing` / `omarchy-pkg-present` - check for packages
-`omarchy-pkg-missing` / `omarchy-pkg-present` - check for packages (don't use these if you can just use `omarchy-pkg-add`/`omarchy-pkg-drop`)
-`omarchy-pkg-add` - install packages (handles both pacman and AUR)
-`omarchy-pkg-drop` - remove packages; use this instead of raw `pacman -R*`
-`omarchy-notification-send` - send desktop notifications; do not call `notify-send` directly
-`omarchy-hw-asus-rog` - detect ASUS ROG hardware (and similar `hw-*` commands)
Exceptions are allowed for bootstrap, preflight, migration, and package-helper scripts where the helper may not be available yet, where the helper itself is being implemented, or where direct package-manager behavior is required.
@@ -90,7 +104,63 @@ Exceptions are allowed for bootstrap, preflight, migration, and package-helper s
-`config/` - default configs copied to `~/.config/`
-`default/themed/*.tpl` - templates with `{{ variable }}` placeholders for theme colors
-`themes/*/colors.toml` - theme color definitions (accent, background, foreground, color0-15)
-`themes/*/colors.toml` - theme color definitions (accent, background, foreground, red/green/yellow/blue/magenta/cyan and bright_* variants)
# Tests
Run focused automated tests for the area you changed. Current test entry points:
-`./test/all` - aggregate runner for CLI and shell tests
-`./test/shell` - all Omarchy shell tests under `test/shell.d/`
New Omarchy shell tests should live in `test/shell.d/*-test.sh` so `./test/shell` picks them up automatically. Source `test/shell.d/base-test.sh` for shared root-path discovery, assertions, and Node test helpers.
For visual changes, such as omarchy-shell styling, desktop appearance, screenshots, or screen recording flows, verify with the running UI in addition to automated tests. Take and analyze screenshots with `omarchy capture screenshot fullscreen save`. For animation, transitions, capture, or screen recording behavior, make a short recording with `omarchy screenrecord --fullscreen`, stop it with `omarchy screenrecord --stop-recording`, and review the output before finishing.
For interactive UI work, use `wtype` to simulate keyboard input when available. Example: start the UI in the background, wait briefly for focus, then run `wtype -k Right -k Return` to exercise keyboard selection and confirm the resulting command output or state change. Prefer this over manual-only verification when a UI returns a selected value or changes a symlink/config.
When testing layer-shell UI, capture the reference and candidate states as separate screenshots, then compare them visually before further edits. If a launched UI would otherwise remain open, keep track of its PID and stop it after the screenshot; avoid broad process kills unless checking with `ps` first.
# Omarchy shell
The Quickshell desktop runs as a single long-running process out of
`shell/`. Hyprland autostart launches it directly with `quickshell -p`; do
not start additional standalone `quickshell -p` instances for individual
components.
Run `omarchy-restart-shell` after making changes to QML files.
Plugin contract:
- Each plugin lives in its own directory under
`shell/plugins/<id>/` (first-party) or
`~/.config/omarchy/plugins/<id>/` (third-party).
- Every plugin ships a `manifest.json` declaring `id`, `kinds`,
`activation`, and `entryPoints`. The full schema is in
[`docs/omarchy-shell.md`](docs/omarchy-shell.md).
- Entry-point QML files are `Item`s (not `ShellRoot`), and accept the
shell-injected properties `omarchyPath`, `shell`, `manifest`, and
`pluginRegistry` / `barWidgetRegistry` as appropriate.
- Panel / overlay / menu plugins must expose `open(payloadJson)` and
`close()` lifecycle methods for `shell summon` and `shell hide`.
IPC:
-`bin/omarchy-shell` is the canonical IPC entry point. It forwards to
the running shell and does not start it. Prefer it over re-implementing
direct Quickshell socket calls in every CLI.
- The `shell` IPC target exposes `ping`, `summon`, `hide`, `toggle`,
`rescanPlugins`, `setPluginEnabled`, and `listPlugins`. Individual
plugins can register additional IPC targets (the bar registers `bar`,
the background switcher registers `image-selector`).
Widget files in `shell/plugins/bar/widgets/` contain Nerd Font glyphs as raw
unicode characters. The `Write` and `Edit` tools strip multi-byte
codepoints in some positions — do **not** rewrite widget files wholesale
through those tools. For glyph fixes, use the targeted `Edit` tool with
the surrounding context, or a Python script that inserts codepoints via
`chr(0xXXXXX)`.
# Refresh Pattern
@@ -116,12 +186,3 @@ New migration format:
Some older migrations predate these rules. Do not copy older migrations that start with shebangs, omit the leading `echo`, or hard-code `~/.local/share/omarchy`.
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for historical compatibility or one-off repair work.
Example:
```bash
echo"Disable fingerprint in hyprlock if fingerprint auth is not configured"
ACTION=$(notify-send "Screen recording saved" "Open with Super + Alt + , (or click this)" -t 10000 -i "${preview:-$filename}" -A "default=open")
[[ $ACTION == "default" ]] && mpv "$filename"
if [[ -n $(omarchy-notification-send "Screen recording saved" "Open with Super + Alt + , (or click this)" -t 10000 --image "${preview:-$filename}" -a) ]]; then
if [[ -n $(omarchy-notification-send "Screenshot saved to clipboard and file" "Edit with Super + Alt + , (or click this)" -t 10000 --image "$FILEPATH" -a) ]]; then
# omarchy:summary=Mutate the user shell.json bar layout and active bar option
# omarchy:args=show | options [--json] | use <plugin> | reset | list [--json] [--all] | add [plugin] [left|center|right] | remove [plugin] | drop [plugin] | position <top|bottom|left|right> | transparent <true|false>
# omarchy:examples=omarchy config shell bar show | omarchy config shell bar options | omarchy config shell bar use local.neon-bar | omarchy config shell bar reset | omarchy config shell bar list | omarchy config shell bar add omarchy.tailscale | omarchy config shell bar position top | omarchy config shell bar transparent true
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.