Adding a package means writing one manifest.yaml. There are no templates and
no hidden magic: YAML keys map 1:1 to standard PKGBUILD fields, and the build
steps are plain bash.
If you are an AI agent working from this guide:
- This repo (
missing-aur) — proceed on your own: manifest, local assets,README.mdtable (optional — CI regenerates it),scripts/manage.py generate, commits, and PRs here. No need to ask permission for each step unless the user said otherwise. - Upstream README PR — never fork the upstream project, edit their README, or open a PR there unless the user explicitly asks you to. After adding a package here, you may briefly mention that an upstream install-doc PR is possible — then stop and wait for a clear yes/no.
packages/
<app>/
manifest.yaml ← everything goes here
icon.png ← optional, shown in README.md
<file>.desktop ← local assets (optional)
The generated subdirectories packages/<app>/<pkgname>/ (PKGBUILD, .SRCINFO)
are fully generated — never edit them by hand, and never commit them.
They are produced by scripts/manage.py on demand locally and by the CI on the server.
Committing them would cause conflicts and drift from what the generator produces.
The .gitignore is already configured to ignore them.
A manifest declares an app name and one or more variants. The variant key
is appended to the name to form the package name:
name: psst # the app
variants:
bin: # → pkgname = psst-bin
git: # → pkgname = psst-gitSome variant keys are reserved and produce no suffix — the pkgname equals
name exactly. Use them when the package follows the AUR convention of having
no suffix (i.e. it is the canonical, non-binary, non-git package):
| Key | Intended use |
|---|---|
base |
Compiled from a release tarball (default choice) |
stable |
Alias for the same intent |
release |
Alias for the same intent |
name: foo
variants:
base: # → pkgname = foo (no suffix)
bin: # → pkgname = foo-bin
git: # → pkgname = foo-gitFields written at the top level are shared by every variant. A variant can override any of them. That's the whole model.
The optional docs block is metadata for this repository only — it is
ignored by PKGBUILD generation and used to build the README table:
docs:
description: "One-line summary shown in README.md" # optional, defaults to pkgdesc
externalAur: # AUR packages we do not maintain (purple badges)
- foo-gitOptional packages/<app>/icon.png is shown in the README table; if missing, the
generator writes - in the icon column.
You do not need to edit README.md yourself — the PR Check workflow
regenerates the package table automatically. Skipping it is fine. If you update
it manually anyway, that is fine too.
Avoid duplicating fields across variants. If a field has the same value in
every variant, hoist it to the top level. Only keep in the variant what actually
differs between variants (e.g. pkgver, source).
By default, every variant is treated as an interchangeable alternative for the same app. The generator injects these PKGBUILD fields automatically — do not write them in the manifest unless you need extra entries:
| Injected field | Value |
|---|---|
provides |
the app name (e.g. foo-bin provides foo) |
conflicts |
name, every sibling variant pkgname, and every docs.externalAur entry |
Example: name: foo with variants bin and git, plus docs.externalAur: [foo-git]:
foo-bin→provides=(foo)conflicts=(foo foo-git)foo-git→provides=(foo)conflicts=(foo foo-bin)
List external AUR packages under docs.externalAur — they are added to
conflicts automatically. No need to repeat them in each variant.
For apps whose variants are independent products (not alternatives), set
providesBase: false at the top level and declare provides / conflicts
manually per variant (see packages/kissmp/manifest.yaml).
When adding a package that does not exist on the AUR yet, set pkgver: "0"
in the manifest for every new variant (-bin, -appimage, base, etc.) —
except -git. Git variants derive their version from a pkgver() function
and do not use this trick.
The nightly GitHub Action runs each variant's versionChecker, compares the
result to pkgver, and only pushes to the AUR when they differ. A brand-new
package has no AUR entry yet, so if you write the real upstream version
straight away the bot sees nothing to update and never creates the AUR
package.
Starting at 0 guarantees the bot detects a newer version, bumps the manifest,
regenerates the PKGBUILD, and performs the initial push. You do not need to
track the latest version yourself — the versionChecker and CI handle that
after merge.
If you already committed the real version by mistake, push a follow-up commit
that sets pkgver back to "0" (see fix(murmure-bin): set pkgver to 0 to trigger initial AUR push).
name: foo
url: https://github.com/author/foo
license: MIT
variants:
bin:
pkgver: "0" # new -bin package → 0; CI bumps to latest
pkgdesc: "Short description"
depends: [gtk3, openssl]
versionChecker: "curl -s https://api.github.com/repos/author/foo/releases/latest | jq -r '.tag_name' | sed 's/^v//'"
source:
- "foo-${pkgver}::${url}/releases/download/v${pkgver}/foo-linux-x86_64"
package: |
install -Dm755 "foo-${pkgver}" "${pkgdir}/usr/bin/foo"This produces packages/foo/foo-bin/PKGBUILD with pkgname foo-bin.
name: foo
url: https://github.com/author/foo
license: GPL3
arch: [x86_64, aarch64] # shared by both variants
pkgdesc: "Foo" # identical in both → hoist it
variants:
bin:
pkgver: "1.2.3"
versionChecker: "..."
source:
- "foo-${pkgver}.tar.gz::${url}/releases/download/v${pkgver}/foo-linux.tar.gz"
package: |
install -Dm755 "${srcdir}/foo" "${pkgdir}/usr/bin/foo"
git:
depends: [gcc-libs, glibc]
makedepends: [cargo, git]
source:
- "foo::git+${url}.git"
pkgver_func: |
cd "${srcdir}/foo"
git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/^v//'
build: |
cd "${srcdir}/foo"
cargo build --release
package: |
cd "${srcdir}/foo"
install -Dm755 "target/release/foo" "${pkgdir}/usr/bin/foo"Variant fields override shared ones. A git variant simply omits
versionChecker (its version is derived by the pkgver function instead).
Standard PKGBUILD fields, used as-is:
| YAML | PKGBUILD |
|---|---|
pkgname, pkgver, pkgrel, epoch |
unquoted scalars |
pkgdesc, url |
quoted scalars |
arch, depends, makedepends, optdepends, provides, conflicts, replaces, options, backup, groups |
arrays |
license |
array |
source |
array, or a per-arch map (see below) |
Build functions are written as multiline bash strings:
| YAML key | PKGBUILD function |
|---|---|
pkgver_func |
pkgver() |
prepare |
prepare() |
build |
build() |
package |
package() |
${pkgver}, ${srcdir}, ${pkgdir}, ${url}, etc. are interpolated by
makepkg at build time — write them literally.
source:
x86_64:
- "foo-${pkgver}-x86_64.tar.gz::${url}/.../foo-x86_64.tar.gz"
aarch64:
- "foo-${pkgver}-aarch64.tar.gz::${url}/.../foo-aarch64.tar.gz"Optional when you want the default:
| Field | Default |
|---|---|
pkgrel |
1 in generated PKGBUILDs — do not set it in the manifest |
arch |
[x86_64] |
pkgver |
0 (default for git variants with a pkgver_func; required for all other new packages — see New packages) |
sha256sums |
SKIP (filled in automatically by updpkgsums) |
A parenthetical suffix is appended to pkgdesc based on the pkgname ending —
don't write it yourself:
| pkgname ends with | appended |
|---|---|
-bin |
(precompiled binary) |
-git |
(git version) |
-appimage |
(AppImage) |
If the description already ends with ), nothing is appended. Base variants
(base, stable, release) never receive a suffix.
Files committed in packages/<app>/ (.desktop, .patch, icons, etc.) are
copied into the generated build dir by scripts/manage.py. Reference them in source
with a download URL — makepkg on the AUR must be able to fetch every
source file.
source:
- "foo-${pkgver}.tar.gz::https://upstream.example/foo-${pkgver}.tar.gz"
- "foo.desktop::https://raw.githubusercontent.com/Cleboost/missing-aur/main/packages/foo/foo.desktop"push-to-aur.sh can also copy bare filenames (no URL) into the AUR git repo,
but this repo does not rely on that — always use a raw URL, either from
missing-aur (for files you maintain here) or from upstream (see
packages/psst/manifest.yaml).
Do not use a heredoc in package(). scripts/manage.py indents every line inside
build functions, including heredoc content — the installed .desktop file ends
up with leading spaces on each line and launchers ignore it.
Instead, commit a packages/<app>/<app>.desktop file and reference it in
source with a raw GitHub URL so AUR users can download it with
makepkg:
source:
- "foo-${pkgver}.tar.gz::https://..."
- "foo.desktop::https://raw.githubusercontent.com/Cleboost/missing-aur/main/packages/foo/foo.desktop"
package: |
install -Dm644 "${srcdir}/foo.desktop" "${pkgdir}/usr/share/applications/foo.desktop"If upstream already ships a .desktop file, point to its raw URL instead (see
packages/psst/manifest.yaml).
Packaging-only fixes (desktop entry, install path, etc.) with no upstream version
change are handled by bumping pkgrel in the generated PKGBUILD when needed; do
not add pkgrel to the manifest. The nightly bot resets pkgrel to 1 when
pkgver changes.
A shell command printing the latest available version to stdout. If it
differs from pkgver, the manifest is updated and the PKGBUILD regenerated
automatically by the update bot.
# GitHub releases
versionChecker: "curl -s https://api.github.com/repos/author/repo/releases/latest | jq -r '.tag_name' | sed 's/^v//'"
# Web scraping
versionChecker: "curl -s https://example.com | grep -oP 'v\\K[0-9.]+' | head -1"python3 scripts/manage.py generate packages/foo # generate one app
python3 scripts/manage.py generate-all --force # regenerate everything
python3 scripts/manage.py check-updates # check + regenerate if newer
python3 scripts/manage.py clean # remove all generated files
python3 scripts/generate-readme.py check # CI: README table matches manifests
python3 scripts/generate-readme.py fix # regenerate README package table
python3 scripts/lint_manifest.py check --base origin/main [app...] # lint manifests
python3 scripts/fix_icon.py check [app...] # verify icon.png is 64x64Pull requests that touch packages/ get a welcome comment on open and a fresh
check recap comment on each update (old recaps are replaced). The workflow also
updates README.md for you — no need to do it in your PR.
- Use the PR template when adding a package. On GitHub, pick 📦 Add package
from the template chooser when opening your PR — do not open a blank PR. Your
description must keep the Package, Checklist, and Notes sections
from
.github/PULL_REQUEST_TEMPLATE/add-package.md, with the checklist items filled in. The title should followfeat: add <app>. PRs that do not follow this format will be closed automatically by the bot. - One package per PR.
- New AUR packages: set
pkgver: "0"on every variant except-git, so the GitHub Action performs the initial push (see New packages). CI auto-fixes this on new manifests. - Do not set
pkgrelin the manifest — CI removes it; PKGBUILDs default to1. - Clear commit messages:
feat: add foo-bin,fix: update kissmp versionChecker. - Run
python3 scripts/manage.py generate packages/<app>locally and check the PKGBUILD before submitting. - Add a
docsblock to the manifest (docs.descriptionis optional — defaults topkgdesc;docs.externalAurfor purple badges). The README table is updated by CI — editing it yourself is optional.
Optional follow-up after a package is live on the AUR: open a small docs PR on the upstream project so Arch users can find the package. AI agents: only when the user explicitly asks — see AI assistants.
Upstream README — use your judgment. Read the existing install section and
add the AUR option in whatever form fits (bullet, subsection, one-liner, etc.).
Same tone and formatting as the rest of the doc. Just tell users how to install;
do not mention missing-aur there.
Past PRs for inspiration: signboard#48, markamd#131.
PR title:
docs: document Arch Linux AUR installation
PR body (replace <pkgname> and <arch>):
## Summary
- Adds an Arch Linux (AUR) install option in the README
- Documents the community-maintained [`<pkgname>`](https://aur.archlinux.org/packages/<pkgname>) package for <arch>
- Includes example install commands for common AUR helpers (`yay`, `paru`)
The package is maintained in [missing-aur](https://github.com/Cleboost/missing-aur) and updated automatically from upstream releases.No test plan in the PR body.