Imported from trly/pkgbuild (
.agents/skills/create-package/SKILL.md). Install upstream withnpx skills add trly/pkgbuild --skill create-package. Copyright stays with the author.
Create Package
Use this skill when designing a new package in this repository. Work from the repository root and keep the package in a new top-level directory. Default to only x86_64 unless instructed otherwise.
Inputs
Obtain:
- A package name matching
^[a-z0-9][a-z0-9@._+-]*$and the Arch package-name length limit. (255 characters) - Either a GitHub repository or releases URL, or an AUR package name/URL.
Choose the package name based on the available package alternatives, not only on the source format:
- Use a
-binsuffix when an unsuffixed source-built package exists in this repository or is being added as the parallel alternative. - Use the unsuffixed name when this repository has no source-built counterpart,
even if the package redistributes upstream prebuilt binaries. Do not create a
new
-binvariant solely because the release asset is a binary archive. - Before choosing the name, inspect the repository's top-level package directories for an unsuffixed source package and any related package relationships. Do not overwrite an existing package directory. Before writing the final PKGBUILD, confirm the upstream license, supported architectures, release format, and runtime, build, and test requirements.
Scaffold
Run the skill-owned scaffold script from the repository root:
bash .agents/skills/create-package/scripts/create.sh PACKAGE
It creates PKGBUILD, .SRCINFO, .gitignore, and package-local REUSE.toml.
The repository-root build.sh and lint.sh are shared CI tooling and must not
be copied into this skill's scripts/ directory.
The scaffolded .gitignore ignores pkg/, src/, built package archives, and
downloaded source archives with common extensions (*.tar.*, *.tgz,
*.zip) so that updpkgsums and makepkg downloads are never committed. If a
source uses a name:: alias or an archive extension outside those patterns,
add a matching .gitignore entry before downloading it.
The generated PKGBUILD is deliberately an incomplete scaffold. Replace every
scaffold value and make package() install the intended files before treating
the package as complete.
GitHub Releases
-
Derive
OWNER/REPOSITORYfrom the supplied URL. -
Resolve the latest release and inspect its assets, using
gh api repos/OWNER/REPOSITORY/releases/latestwhen available. -
Select the correct asset for each supported architecture. Prefer upstream release archives over generated or repacked sources. Use explicit
source_x86_64/source_aarch64arrays when assets differ by architecture, with matching checksum arrays. -
Keep download URLs and archive names derived from
pkgver, for example:${url}/releases/download/v${pkgver}/.... -
Annotate GitHub-tagged versions for Renovate:
pkgver=1.2.3 # renovate: datasource=github-tags depName=OWNER/REPOSITORY -
Generate checksums with
updpkgsumsafter the source definition is final. Prefer the strongest checksum published by upstream (b2, then SHA-512, SHA-384, SHA-256, SHA-224, SHA-1, MD5, and finally CRC32). Never useSKIPfor a downloadable release archive without documenting an unavoidable reason.updpkgsumsrewrites existing checksum entries, including intentionalSKIPentries. After running it, inspect the diff and restore documentedSKIPvalues for mutable repository metadata or other sources that cannot be reproducibly hashed.
If the release uses a tag format or asset naming scheme that cannot be safely
represented using pkgver, document the limitation rather than adding a
fragile Renovate annotation.
Existing AUR PKGBUILD
Fetch the source PKGBUILD, preferably from the AUR cgit endpoints:
https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=PACKAGE
https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=PACKAGE
When adapting it:
- Keep the local maintainer first:
# Maintainer: Travis Lyons <pkgbuild at trly dot dev>. - Copy every upstream
# Maintainer:and# Contributor:attribution as a# Contributor:line below the local maintainer. Preserve names and contact formatting; do not discard current AUR contributors. - Add an attribution note such as:
# Adapted from https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=PACKAGE. - Review all dependencies, source URLs, checksums, signatures, architecture declarations, install paths, and shell commands against current upstream.
- Add a GitHub Renovate annotation when the upstream source supports it.
PKGBUILD Requirements
Keep fields in this order:
- Maintainer and contributor comments.
pkgname, internal version variables,pkgver,pkgrel, and only an evidence-basedepochwhen version ordering requires it.pkgdesc,arch,url, andlicense.groups,depends,makedepends,checkdepends, andoptdepends.provides,conflicts, andreplaceswhen their relationships are real.options,install,backup, andchangelogwhen needed.- Sources,
noextract, architecture-specific sources, checksums, and signature keys. - Optional
prepare(),pkgver(),build(),check(),verify(), and the requiredpackage()function.
Use Bash arrays and quote expansions. Keep the file non-interactive and
compatible with makepkg's Bash execution. Do not use pkgbase for these
single-output packages; it defaults to pkgname.
Metadata
pkgnamemust match^[a-z0-9][a-z0-9@._+-]*$, must not start with a dot or hyphen, and should match the package's public name where practical.pkgvermust be a valid pacman version: no spaces or hyphens; translate an upstream hyphen to an underscore.pkgvermay contain underscores.pkgrelis normally a positive integer. Reset it to1for a new upstream version and increment it for every packaging-only change, including changes to dependencies, architecture support, install paths, relations, source handling, or license metadata. Useepochonly to repair version ordering.- Keep
pkgdescconcise, useful, and preferably no longer than 80 characters; do not write it as a self-referential sentence. Setarch=('any')only for architecture-independent output; compiled or prebuilt binaries need explicit supported architectures. - Use the official project URL and SPDX license identifiers. For a custom or
proprietary license, use
LicenseRef-*orcustom:*and install its text under/usr/share/licenses/${pkgname}. Do not claim a license merely because it is convenient for the scaffold.
Dependencies and Relations
- List every direct runtime dependency in
depends, every build-only tool inmakedepends, and test-only requirements incheckdepends. Do not duplicate runtime dependencies inmakedepends;base-develis implicit. - Disable optional upstream features whose dependencies are not packaged, or declare those dependencies explicitly. Avoid automagic features selected by whatever happens to be installed on the build host.
- Describe optional functionality as
optdepends=('package: feature')and use version constraints only where required. Inspect ELF requirements withfind-libdepsand shipped libraries withfind-libprovideswhen available. - Never add
pkgnametoprovidesorconflicts. Add versionedprovidesfor real compatibility alternatives, useconflictsonly when packages cannot coexist, and reservereplacesfor obsolete names upgraded automatically.
Sources and Integrity
- Derive URLs, archive names, and checksums from
pkgver. Use a uniquename::urlsource name when an upstream filename could collide inSRCDEST. Pin VCS sources to a tag or commit when reproducibility matters. - Use
noextractonly for sources that must remain untouched, and extract them explicitly inprepare()with the required tool inmakedepends. - When upstream publishes detached signatures, include the signature in
source, set full uppercasevalidpgpkeysfingerprints, and keep trusted keys in package-localkeys/pgp/. The host's temporary GPG keyring is not available inside clean-chroot builds, sovalidpgpkeysalone is insufficient for keys that are not in the Arch keyring. For those sources, name the downloaded signature with a.signaturesuffix rather than.sig, and useverify()to import the tracked key into a temporary--homedirand verify the archive there. Do not download keys from an untrusted build-time URL. - Keep each integrity array aligned one-for-one with its corresponding source array, including architecture-specific arrays.
.installfiles are referenced with theinstallvariable and are detected automatically by makepkg; do not redundantly add them tosource.- Keep
.SRCINFOandpkgrelupdates in the same change as the PKGBUILD.
Build Functions And Paths
Use quoted paths and standard filesystem locations:
- Executables:
/usr/bin. - Licenses:
/usr/share/licenses/${pkgname}. - Documentation:
/usr/share/doc/${pkgname}. - Desktop files and icons: their standard
/usr/sharelocations. - Configuration:
/etc, withbackupwhen appropriate.
makepkg provides absolute srcdir and pkgdir paths. Keep source changes in
prepare(), repeatable compilation in build(), tests in check(), and staged
installation in package(). package() is required; the other functions are
optional. A VCS package may use pkgver() after extraction to derive a valid
version without embedding a changing date in pkgver.
Install files with install rather than copying them, set executable modes
explicitly, and never write outside ${pkgdir}. Use DESTDIR="${pkgdir}" for
staged installs; never run make install against the live filesystem. Do not
move build outputs from ${srcdir} into ${pkgdir}, because that breaks
makepkg --repackage.
For prebuilt binaries, normally use options=('!debug' '!strip'). When the
package uses a -bin name alongside an unsuffixed source package, declare
matching versioned provides and conflicts (and replaces only for a real
package transition). Do not add those relations merely because the package
contains prebuilt files. Install upstream license and useful documentation
files. Use an install script only when a pacman lifecycle action is genuinely
required; do not end an .install script with exit.
Finalize And Validate
From the repository root:
cd PACKAGE
updpkgsums # after source and signature entries are final
makepkg --printsrcinfo > .SRCINFO
cd ..
./lint.sh PACKAGE
makepkg --cleanbuild --clean --force
lint.sh finishes with a repository-root reuse lint. That scanner only
honors ignore rules from a package-local .gitignore once the file is tracked
in git, and it scans tracked files even when they match ignore patterns, so
during development — before the package is committed and its .gitignore is
git-tracked — downloaded source archives and pkg//src/ outputs left in the
package directory fail the REUSE check. Remove them from the package directory
before running ./lint.sh on a newly created or not yet committed package
(makepkg re-downloads sources as needed), and never commit the downloaded
archives themselves.
lint.sh runs ShellCheck with SC2034, SC2154, and SC2164 excluded, verifies
.SRCINFO against makepkg --printsrcinfo, runs namcap against PKGBUILD,
and runs reuse lint; use ./lint.sh all to validate every package in one
invocation. build.sh performs the repository's clean-chroot build through
pkgctl; use it only for explicit clean-chroot validation. After a pull
request is opened, the required Check and build packages job in
.github/workflows/test-packages.yml invokes ./build.sh PACKAGE for each
changed package in a privileged Arch container. That CI job is the authoritative
clean-chroot validation. Use
makepkg --cleanbuild --clean --force for initial development and local change
validation; it runs without root but requires the necessary dependencies to be
installed in the host environment. Do not use --nodeps as normal validation.
The clean-chroot build requires an Arch base-devel environment, devtools,
and a non-root build user with passwordless or already-authenticated sudo
when invoked as a non-root user. If local clean-chroot validation cannot run,
state that clearly; a local makepkg build is useful local validation but is
not equivalent to the required pull-request CI clean-chroot build.
After a successful build, validate the archive as well:
cd PACKAGE
archive=$(makepkg --packagelist)
namcap PKGBUILD
namcap "$archive"
pacman -Qip "$archive"
pacman -Qlp "$archive"
Test the installed application and, optionally, verify reproducibility with
makerepropkg PACKAGE-*.pkg.tar.zst from devtools.
Do not leave scaffold values, unsynchronized .SRCINFO, missing checksums,
unverified available signatures, unexplained dependencies, stale package
archives, or unexplained SKIP entries in the completed package. Summarize
any checks that could not run and why. For archive inspection, use the filename
from makepkg --packagelist or remove stale archives first; do not let a
wildcard validate an older build.