A plugin is now just a git repo cloned into ~/.config/omarchy/plugins/<id>/.
That one idea replaces the entire homegrown package-manager half of the
plugin suite: trusted-source registry, clone cache, catalog scanning,
semver comparison, staging dirs, and timestamped backups — 1,025 lines
across five binaries whose jobs git already does.
Gone:
- omarchy-plugin-source: the trusted-repo registry (sources.json) and its
clone cache under ~/.cache/omarchy/plugin-sources/. The trust decision
now happens once, at add time, with the same unsandboxed-code warning.
- omarchy-plugin-scan + omarchy-plugin-available: the catalog machinery
over cached clones. Discovery belongs on a web page, not in the CLI.
- omarchy-plugin-add: copying folders out of cached source clones with
hand-rolled staging and .bak backups. Replaced by a git clone.
- omarchy-plugin-update: manifest version comparison via sort -V and
re-installs. Replaced by fetch + diff + fast-forward; git is the version
and git is the backup.
- omarchy-plugin-remove and omarchy-plugin-edit as separate binaries:
folded into omarchy-plugin, much slimmer.
The consolidated omarchy-plugin now handles the full lifecycle:
- add <git-url>: warn, clone into a dot-prefixed staging dir (invisible
to the plugin scanner), validate, then move into place named by the
manifest id. Plugins land disabled — enabling is the single consent
moment, replacing the old review-before-copy flow.
- update [id | --all]: fetch origin HEAD, show the diff (delta when
available), confirm, fast-forward. Updates are code the shell will run,
so the result is re-validated and rolled back to ORIG_HEAD if upstream
turned invalid (e.g. smuggled a symlink).
- remove [id]: git checkouts are deleted outright since upstream keeps
the history; hand-made plugin folders still get a backup, and dev
symlinks are just unlinked.
- edit [id]: opens the user plugin directory in a shell.
All commands keep the interactive/unattended split: gum prompts in a
terminal, hard refusal without --yes otherwise, so scripts and agents
never hang on a hidden prompt.
Kept as siblings: omarchy-plugin-catalog (omarchy-bar reads it),
omarchy-plugin-validate (the security boundary, now pruning .git from its
symlink scan since installs are git checkouts), and omarchy-plugin-clone
(local development of built-in widgets, a separate concern).
Trade-offs accepted: one repo = one plugin (no more multi-plugin source
repos), and ref pinning or branch switching is no longer a CLI feature —
an installed plugin is a plain checkout, so that is ordinary git in the
plugin directory.
None of the removed machinery ever shipped: it existed only on this
branch, so there is no migration. The net effect is 11 scripts / 2,040
lines down to 4 scripts / 1,080 lines, and one less concept for users to
learn — everyone already knows what a git repo is.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the three-layer process management (trap cleanup, PPID-polling
watchdog subshell, /proc-scanning reaper) with kernel-level lifetime
binding: each wl-paste watcher is spawned under setpriv --pdeathsig TERM,
so it dies with the shell no matter how the shell exits.
- Delete watch.sh: the shell now spawns both watchers directly as
declarative Process commands instead of a wrapper script with traps
and a 1s polling loop
- Delete init.sh: reaping stale watchers from a crashed pre-pdeathsig
shell is a single pkill at startup
- Collapse capture.sh's dual stream/snapshot modes: wl-paste forwards
arguments to its watch command, so the mime rides along as $1 instead
of an env var, letting both modes share one emit_image function
- Turn the six-branch image mime chain into a loop
Net: two fewer files, three fewer runtime processes, and the watch-mode
capture tests now exercise the same argument protocol the shell uses.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
omarchy-plugin mixed plugin lifecycle, clone/edit, and bar-layout mutation.
The bar layout was mutated by two separate engines (an embedded Python
mutate_bar here and jq in omarchy-config-shell-bar), each with its own
manifest walker.
- omarchy-plugin is now a ~220-line router; clone and edit move to
omarchy-plugin-clone and omarchy-plugin-edit, matching the existing
plugin-{source,add,update,remove,available,validate,scan} sibling pattern
- omarchy-config-shell-bar is replaced by omarchy-bar, the single bar engine
(show/layout/list/options/use/reset/add/move/remove/set/replace/position/
transparent/settings) with one jq pipeline; the Python mutate_bar and its
python3 dependency are gone
- omarchy-plugin-catalog is the shared manifest scanner used by omarchy-bar
(widget/option enumeration, add validation) and omarchy-plugin-clone
(source enumeration), replacing three find|jq re-implementations
- service install/remove and refresh-shell call omarchy-bar; docs and tests
updated to the new command surface
The May 17 picker performance change made activated thumbnail loads asynchronous, which undid the earlier anti-flicker fix and let carousel movement flash blank thumbnails. Keep lazy activation, but load activated thumbnails synchronously so theme/background picker navigation remains stable. Add regression coverage for the thumbnail loading mode.
The launcher resolves each entry's icon through Quickshell.iconPath(),
which bottoms out in Qt's QIconLoader / QIcon::fromTheme. That engine
caches the theme's directory listing — and null results — for the life
of the process, and only re-scans when the icon theme or search paths
change. Nothing in Quickshell 0.3 exposes a way to invalidate it, and a
QML reload doesn't reset it either (QIconLoader is a QtGui process
global, not tied to the QML engine).
So when a user installs a new app while the shell is running, its
.desktop file is picked up live (DesktopEntries is file-watched and the
name appears immediately), but its icon resolves to the cached miss and
renders blank until the whole shell is restarted. That's a poor "I just
installed this" experience.
Fix it without a restart by keeping our own on-disk icon index as a
fallback. When themed lookup returns empty, iconSource() consults a
name->path map built by scanning the XDG icon dirs and /usr/share/
pixmaps (SVGs first, so scalable wins). The scan runs on startup and on
a debounced DesktopEntries change — the same signal that already makes
names appear — and swapping the iconIndex property re-evaluates every
iconSource() binding, so freshly installed icons show up live. Icons Qt
can already resolve are untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>