The launcher only delegated to omarchy-install-hermes-cli and, when that was
absent, printed a warning to stderr -- which nothing sees under a graphical
launch -- and started the app anyway. The app then offered to install Hermes
itself, and that copy wins permanently: it checks ~/.hermes/hermes-agent
before it checks PATH, so installing the CLI afterwards changes nothing until
that directory is deleted.
So install it here when omarchy's script isn't around, with the same
interpreter pin and the same exported cooldown, and hand the app the real
executable by putting the mise install's bin directory on PATH instead of
leaving it to search. Its probe allows 15 seconds; resolving this way takes
0.2. mise and uv become dependencies, which is what makes the package
self-sufficient on a machine without Omarchy.
Pin the build stamp. write-build-stamp.mjs resolves the commit the app pins
its first-launch bootstrap to, preferring $GITHUB_SHA and otherwise running
`git rev-parse`. That fallback is wrong under makepkg: the build happens
inside this repository, so git ascends out of srcdir and stamps the app with
an omarchy-pkgs commit that means nothing upstream. Confirmed by rebuilding --
the stamp now reads the tag's own commit rather than this repo's HEAD.
Ship upstream's MIT licence. The package declares MIT and was installing only
Electron's licence text.
Repair a drifted CLI before launching rather than only a missing one. `mise
up` can leave Hermes rebuilt against the system Python, and a stub can be
there but cold; either way the wrapper's own repair takes minutes while the
app allows 15 seconds before bootstrapping its own copy. Running the installer
unconditionally costs nothing when Hermes is healthy.
Register the hermes:// scheme. The desktop entry took %U while declaring no
MimeType, so the scheme electron-builder configures went unhandled.
Chromium falls back to XWayland often enough to matter, and the result is a
blurry window on every scaled display -- the same reason the ChatGPT and Grok
Bot launchers set this. Skipped when the caller has already named a platform.
Install > AI is for GUI apps, so the package becomes the desktop shell and the
terminal agent moves to a lazy mise stub that omarchy installs itself.
Nous builds Hermes Desktop for macOS and Windows only -- their download page
offers a .dmg and an .exe and points Linux users at a terminal install -- so
there is no vendor binary to repackage the way grok-bot repackages xAI's deb.
Their electron-builder config does carry a Linux target though, untested by
upstream but working: npm ci at the workspace root, npm run pack in
apps/desktop, and electron-builder stages node-pty and get-windows for
linux-x64 on its own. 337 MB unpacked, 129 MB packaged.
The app is only a shell -- it runs `hermes serve` against a CLI it does not
ship, and clones its own unpinned copy into ~/.hermes when it finds none. So
/usr/bin/hermes-desktop makes sure the CLI is there before handing over, and
says so plainly rather than bootstrapping a second Hermes where Omarchy's
installer isn't around to do it properly.
Both files changed after the sums were generated -- the wrapper learned to
fall back to hermes when invoked under an unknown name, and the desktop entry
dropped its second main category -- so makepkg rejected them.
Hermes pins every one of its ~120 dependencies with == and declares
Requires-Python >=3.11,<3.14, so it can neither be built against Arch's
Python 3.14 nor share the python-* packages, and Arch's next Python bump
would break any venv this package built. So it ships a wrapper instead and
lets mise give Hermes a private environment -- the arrangement
omarchy-mise-install already makes for the other coding agents.
Two things the wrapper has to work around. mise reads [...] as its own tool
options rather than as Python extras, so the extras have to be spelled
[extras=all]; written [all] they are dropped without a word and the install
comes out byte-identical to a bare one. And given no compatible interpreter
to hand, uv builds the venv against the system Python in violation of
Hermes' own bound, reports success, and leaves the breakage to surface later
inside some dependency. The interpreter is therefore pinned on install and
re-checked on every run, since mise up reinstalls without the pin.
The icon is upstream's own 1024x1024 app icon -- the mark the site serves as
its favicon -- downscaled at build time so menus don't smudge it themselves.
A second review pass found the PKGBUILD rewriting could still go wrong in ways
the pattern matching did not anticipate: an array element carrying a ")" in a
comment left the tail of the old array behind, and jq's "$" also matches before
a trailing newline, so a pkgver of "1.0\n" passed validation and then broke sed
after the checksum arrays had already been written.
Rather than chase each shape, prove the result. Every edit now lands on a
scratch copy that is parsed with bash -n and read back to confirm it holds the
version and checksums we meant to write, and only then replaces the PKGBUILD in
a single rename. Corruption that slips past the matching fails loudly with the
original untouched instead of landing in a pull request.
The validation anchors are \A and \z accordingly, empty checksum lists are
rejected rather than written as '', and the hook picks the newest stanza with
vercmp so it agrees with the comparator the updater uses.
Also stop the launcher probing /.config when HOME and XDG_CONFIG_HOME are both
unset, and require a regular file, so a directory at that path is skipped
instead of crashing the app on startup.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
OpenAI ships the ChatGPT desktop app several times a week and the AUR
packaging trails it -- as of this commit by a full version, 26.803.81509
against 26.810.52044. Every sync we took from there was a sync we could have
taken from OpenAI directly.
So track OpenAI's own Debian repository instead. Its per-architecture package
index carries the version and SHA256 of every deb, which makes an update two
small HTTP requests rather than a 750 MB download, and the pool keeps old
versions, so the URLs pinned here stay resolvable after the next release.
Omarchy now maintains the package outright: the max-zstd patch is simply part
of the PKGBUILD, chatgpt-launcher.sh is ours, and the Arch REUSE files are
gone -- they annotated packaging paths (.SRCINFO, keys/**, .nvchecker.toml)
that do not exist here. The app's own license still ships; package() installs
upstream's copyright file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Some vendors publish a release feed of their own that is faster and more
precise than anyone's packaging of it. A package opts in with an
.omarchy/upstream.sh hook that reports the newest release as JSON, and the
driver rewrites pkgver, the checksum arrays the hook names, and pkgrel.
Writes are guarded on both ends: every assignment the update will touch is
verified to exist before anything is written, so a hook naming an array the
PKGBUILD lacks fails with the file untouched rather than half rewritten; and
pkgver is held to pacman's character set, because it lands in a file makepkg
sources as shell.
Ordering is vercmp's, not sort -V's -- they disagree about whether 1.0a
precedes 1.0, and pacman is what decides if a published package is an upgrade.
That is also why the workflow runs in an Arch container rather than straight on
the runner.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Package the official Grok Bot Linux .deb (internal name: sand) for Arch.
Wraps /opt/Grok Bot/sand with a Wayland launcher and grok-bot desktop entry.
Linux has no latest feed; update-pkgver.sh resolves version+commit from the
darwin-arm64 sand feed and HEAD-checks the Linux deb before pinning.
Omarchy 4 generates most theme specs from default/themed/neovim.lua.tpl on
top of aether, pinned as `name = "aether", branch = "v3"`. lazy indexes
specs by url and lets an explicit name rename the merged plugin, so the
bare "bjarneo/aether.nvim" entry here built the cache into lazy/aether.nvim
while every aether-themed install renamed that same plugin to lazy/aether at
runtime -- a directory the package never shipped. Picking one of those themes
on a fresh install cloned aether over the network at first launch and left
the session on tokyonight until nvim was restarted. Six stock Omarchy 4
themes route through the template, plus last-horizon.
Naming the entry to match builds the cache into lazy/aether directly. There
is still only one clone: Omarchy 3.8's hackerman theme depends on the bare
"bjarneo/aether.nvim" url, which merges into the same plugin, so 3.8 keeps
resolving offline as before.
Also keep refs/remotes/origin/HEAD when slimming. It pins no objects, but
lazy.nvim resolves the default branch through it for plugins parked on a
detached HEAD by a version pin -- lazy.nvim, LazyVim and blink.cmp. Without
it get_branch() returns nil and every lockfile write asserts, so :Lazy
install/update/sync died with E5113 on a fresh install, taking out the usual
self-heal path too. Regression from 45ca871.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#6746 added the unit, the binary, the enable-user-units.sh entry, and a
migration, but not the install line here -- so omarchy-settings shipped
omarchy-crash-watch.service only into the default/ template tree and never
into the search path systemd actually reads.
install/user/first-run/enable-user-units.sh enables its six units in a single
`systemctl --user enable --now` call, so the missing unit failed the whole
call. omarchy-provision-first-run only marks first-run-user when every step
succeeds, which meant first-run never completed and replayed on every login,
re-firing the "Learn Keybindings" and "Update System" notifications. Because
enable is atomic, it also left the other five units disabled -- no bluetooth
agent, sleep lock, monitor recovery, migrate notifier, or fcitx5.
Migration 1786539345 falls back to writing the wants symlink by hand when
there is no live user manager, pointing at the /usr/lib path this omission
left empty, so existing installs got a dangling symlink too.
No new migration is needed: affected installs retry first-run on the next
login and succeed, and the dangling symlinks resolve as soon as the file
exists at that path.
test/shell.d/config-test.sh already asserts this install and fails without it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jm1hEGtGRUrfqxMbTi1fWe