Since publishing moved to CI on merge, a package whose PKGBUILD never
changes while its source moves was never rebuilt: omarchy-dev and
omarchy-settings-dev followed quattro through "#branch=" and a pkgver()
function, and nothing in this repository changed when quattro did. The
host timers that used to notice are off, so edge fell days behind.
The rule now: no git source without a commit or tag pin
(tests/pinned-sources.sh, run in CI). A package that has to follow a
branch declares a git_branch upstream watch, and the pin moves through
the same PR/build/publish path as every other version bump.
Watch (helpers/upstream-watch.py)
git_branch gains tag_pattern: the newest release tag in the pinned
commit's own history, exposed as {tag}/{version}/{distance}, so a
branch build is versioned <tag>.r<n>.g<sha>, above the release it
follows and below the next one. One blobless clone per branch per
run, shared by every package on it. min_release_age selects the
newest commit older than the window, so a push burst builds once.
Lane (helpers/package-metadata.sh, bin/sync-upstream --lane)
"auto_merge": true moves a package from the reviewed 6-hourly sync
PR to the unattended lane. Packages pinned from the same branch move
together: a failure on one restores the others and fails the group,
so the dev pair can never ship from two quattro commits.
Tracker (.github/workflows/track-branches.yml)
Every two hours: pin, open one PR with a GitHub App token, enable
auto-merge. Branch protection still gates the merge on result,
self-tests and build-isolation. A tip that fails to build stays an
open red PR until the next tick supersedes it. The App is required:
a PR opened with GITHUB_TOKEN has its checks held for approval and
its auto-merge would not fire publish.yml.
The reviewed workflows (sync-upstream, sync-rebuilds) open their PRs
with the same App so their builds start without a maintainer clicking
"Approve workflows to run"; without the App they fall back to
GITHUB_TOKEN and behave as before.
Recipes
The dev pair pins _commit and a real sha256sum, keeps the OMARCHY_SRC
override, and drops pkgver(). Its r-number stays the branch's total
commit count because the published history used it and pacman must
never see the version go down. omasnap-git is new: omacom/omasnap
main, versioned <tag>.r<distance>.g<sha>, provides/conflicts omasnap.
16 KiB
Direct upstream watches
Omarchy owns the recipes in pkgbuilds/. bin/sync-upstream discovers new
releases directly from project/vendor feeds and updates versions, declared
release variables, and the source checksums already used by the recipe. It never
imports upstream PKGBUILDs or runs downloaded build scripts. Architecture support,
root install hooks, dependencies, and build functions remain ours to maintain.
upstream.watch complements the existing declarative providers and custom hooks:
{
"source": "local",
"upstream": {
"watch": {
"github": "abenz1267/walker",
"pattern": "v(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
}
}
Watch fields
Choose exactly one provider: github (owner/repository), git_tags (repository
HTTPS URL), git_branch (repository URL plus explicit branch), npm or pypi
(package name), debian (Packages index plus exact package), json (URL plus
version path), regex (text URL), redirect (final HTTPS download URL), or
archive (inspect archive metadata without extracting/executing code).
Tag, text, redirect and archive watches use an explicit pattern with a named
version capture. Tag patterns match the entire tag. version optionally formats
those captures into an Arch pkgver; e.g. Sublime uses 4.{version}. JSON feeds can
expose additional capture values through fields, a name-to-JSON-path map.
variables maps recipe scalars such as _commit or _build to capture templates.
Only explicitly declared underscore-prefixed variables can change. GitHub
{commit} resolves the selected tag, not a moving target_commitish branch.
submodules can map a recipe variable to a gitlink in the selected GitHub tag;
RustDesk uses this for hbb_common. Downloaded repository code is never evaluated.
For upstreams that rebuild a release, declare a numeric revision template and
its revision_variable. With unchanged pkgver, only an increasing revision can
advance that variable, and the downstream pkgrel increments instead of resetting.
Cursor CLI uses sequence to preserve its date/counter/hash version convention
when the vendor publishes a second hash on the same day. A new pkgver resets
pkgrel to 1, but the complete epoch:pkgver-pkgrel must still increase.
GitHub releases exclude drafts and prereleases unless allow_prerelease is true.
Existing min_release_age policies apply: a feed without a verifiable publication
time cannot bypass a configured hold.
Branch watches
A git_branch watch treats every commit on a branch as a release and writes an
immutable pin ("_commit": "{commit}") so the recipe never carries a moving
#branch= source; tests/pinned-sources.sh enforces that. The clone is bare,
blobless and single-branch, read only with git, and shared by every package
that watches the same branch in one run, so two recipes pinned from it always
see the same commit. Values available to version:
{date}(default),{count}(commits on the branch),{commit}({commit:.7}for the short form)- with
tag_pattern(a regular expression with a namedversiongroup, matched against whole tags):{tag},{version}from that tag, and{distance}, the number of commits past it. Only tags in the pinned commit's own history count, so a release cut on another branch is ignored.
{version}.r{distance}.g{commit:.7} gives 1.21.0.r15.gabc1234, which pacman
orders above the 1.21.0 release it follows and below 1.21.1; omasnap-git
uses it. The Omarchy dev pair uses {version}.r{count}.g{commit:.7} instead
because its published history counted every commit and the number must never
go down.
min_release_age on a branch watch selects the newest commit that has been on
the branch for at least that long, so a burst of pushes builds once after it
settles rather than once per push. BYPASS_MIN_RELEASE_AGE=1 takes the tip.
Packages marked "auto_merge": true ride the unattended lane
(track-branches.yml) instead of the reviewed sync PR: their bump PR is opened
and auto-merged as soon as the build checks pass. bin/sync-upstream --lane reviewed|auto-merge|all selects a lane; the scheduled workflows each pass their
own. Packages that pin the same branch move in lockstep: if one of them fails
to update, the run restores the others and reports the group as failed.
Checksums retain their algorithms (SHA256, SHA512, BLAKE2, etc.) and source order.
Changed git sources are hashed with makepkg's git-archive convention. Unchanged
sources retain their hashes; mutable_sources explicitly names entries such as
source:0 that must be fetched again for a new version despite a stable URL.
Existing SKIP entries remain unchanged (including signed metadata verified by
the recipe); new skips are never introduced. Changed URLs are still fetched.
A matching GitHub release asset SHA256 digest avoids downloading large assets.
Missing architecture artifacts or malformed metadata fail the package atomically.
Every declared architecture must read back the same release and checksum values.
Archive watches use member to select a text member, or filenames: true to read
versions from archive member names. Debian archives are read through their control
metadata. unescape_json handles JSON strings embedded in a vendor's HTML page.
Maintenance and validation
Running watches locally requires Python 3.11+, Bash, curl, git, jq, Arch's
vercmp, and bsdtar. CI installs these in its Arch container.
- Edit packaging and architecture changes directly in PKGBUILD. The old AUR overlays have been folded into these recipes and removed.
- Keep source-code patches and install hooks checked in as ordinary package files.
- Bump pkgrel when changing a recipe at the same version. Removing a dotted AUR suffix must never lower the complete version.
- Add a watch with each new package.
bin/add-package --source auris a one-time import; it records historicaloriginmetadata and leaves an owned recipe. python helpers/upstream-watch.py check pkgbuilds/NAMEchecks release discovery without rewriting the recipe.bin/sync-upstream NAMEperforms the update.python tests/upstream-watch.pytests update atomicity, architecture coverage, version ordering, source hashes and hostile metadata using offline fixtures.
The scheduled workflow continues reviewing completed updates if another package fails. The failing recipe stays unchanged and the run still reports failure.
Migrated package watches
68 active AUR packages now use direct watches. The nine previously disabled
packages retain manual maintenance holds. Historical AUR provenance is recorded
in origin and has no effect on release selection.
Existing manual holds
grok-bot, libfprint-git, libretro-cap32-git, libretro-database-git, libretro-fbneo-git, libretro-uae-git, libretro-vice-git, quickshell-git, supergfxctl.
These packages were already excluded from automatic AUR updates. The migration preserves that policy.
linux-firmware-cirrus is a deliberate hold: a self-retiring shim that ships Arch's linux-firmware-cirrus 20260910-2 payload to stable while stable's Arch snapshot is on 20260810-2 (Dell XPS 13 DX13260 / 1028:0e54 speaker firmware). It is versioned 20260810-3 so the genuine Arch package supersedes it as soon as the snapshot advances; bumping it to the Arch version would defeat that. Delete the recipe once stable's snapshot carries linux-firmware >= 20260910.
m1n1-aurora and uboot-asahi are deliberate holds: Apple Silicon boot code, pinned by hand like linux-aurora, and bumped only after a cold boot on the qualification Macs. m1n1-aurora pins an aurora-silicon/m1n1 commit plus a local patch. uboot-asahi follows asahi-alarm's recipe and patch set (asahi-alarm/PKGBUILDs), which a tag watch on AsahiLinux/u-boot cannot carry.
Package-specific boundaries
- NVIDIA watches remain on the 580 driver branch.
- Hardware-specific packages keep their declared architectures; this migration does not invent ARM binaries for x86-only upstreams.
- iA Duospace was deleted upstream. Its four legacy font files retain their original immutable pin while the other families track the current repository.
- RustDesk reads hbb_common from the release gitlink; its existing build-time dependency/toolchain checks remain in force.
- Spotify uses HTTPS and retains its signed Release/Packages verification.
- Source and build compatibility still need review when upstream code changes. Direct watches remove AUR recipe churn, not the need to maintain packaging.