Concrete examples for each of the four principles in CLAUDE.md,
grounded in real slpkgs scenarios (xbps-src templates, the rebrand, upstream
syncs). Snippets use the template shell format and diffs.
Derived from forrestchang/andrej-karpathy-skills (MIT). Examples rewritten for xbps-src packaging + slpkgs.
User request: "Add a package for foo."
What LLMs often do (wrong assumption):
# srcpkgs/foo/template
pkgname=foo
version=1.0
revision=1
do_build() {
make
}
do_install() {
make install
}Problem: several decisions are made silently, and each is a real choice:
- What build system? If
foouses autotools/cmake/meson, abuild_stylehandles configure/build/install correctly — a baremakeusually won't. - Dependency kinds: what goes in
depends(runtime) vsmakedepends(build) vshostmakedepends(e.g.pkg-config)? - Source + checksum: there's no
distfiles/checksum— the package fetches nothing. - Subpackages: does
fooship headers (foo-devel)?
What should happen (surface the choice):
Before I write the template:
- What build system does
foouse? (I'd setbuild_styleaccordingly, e.g.gnu-configure/cmake/meson.)- Runtime vs build dependencies?
- Upstream tarball URL + checksum?
- Any
-devel/-docsubpackage needed?I'll model it on an existing
srcpkgs/<similar>/template.
User request: "Bump foo."
What LLMs often do (pick silently):
-revision=1
+revision=2(Bumps the packaging revision when the user meant a new upstream version — or vice versa.)
What should happen:
"Bump" is ambiguous:
- New upstream release → change
version, resetrevision=1, and updatechecksumfor the new tarball.- Packaging-only rebuild (patch, dep fix) → bump
revisiononly.Which one? If it's a new version, I'll also re-fetch and update the checksum — never carry an old checksum forward.
User request: "Package bar, which uses CMake."
What LLMs often do (overengineered):
do_configure() {
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release ..
}
do_build() {
cd build && make ${makejobs}
}
do_install() {
cd build && make DESTDIR=${DESTDIR} install
}Problem: xbps-src has build_style=cmake that does exactly this, with the
right flags and out-of-tree build, consistently across the whole tree.
What should happen (minimum template):
build_style=cmake
# configure_args only if bar needs something non-defaultLet the build_style do its job. Hand-write do_* only when no style fits.
User request: "Package the baz library."
What LLMs often do (feature creep):
baz-devel_package() { ... }
baz-doc_package() { ... }
baz-static_package(){ ... }
baz-dbg_package() { ... } # dbg is automatic in xbps-srcProblem: -dbg is produced automatically; -doc/-static may not apply.
Inventing subpackages that have nothing to put in them fails the build or ships
empties.
What should happen:
Ship the library, plus a -devel subpackage only if headers/.so symlinks
are actually installed:
baz-devel_package() {
depends="${sourcepkg}>=${version}_${revision}"
short_desc+=" - development files"
pkg_install() {
vmove usr/include
vmove "usr/lib/*.so"
}
}Add -doc/-static only when there's content for them.
User request: "Update qux to 2.0."
What LLMs often do (too much):
-pkgname=qux
-version=1.4
-revision=3
-build_style=gnu-configure
-short_desc="A qux tool"
-maintainer="x <x@y>"
-license="MIT"
-homepage="https://example.org"
-distfiles="https://example.org/qux-${version}.tar.gz"
-checksum=abc123...
+pkgname=qux
+version=2.0
+revision=1
+build_style=gnu-configure
+configure_args="--enable-everything" # not requested
+short_desc="A qux tool (the best one)" # reworded
+maintainer="x <x@y>"
+license="MIT"
+homepage="https://example.org"
+distfiles="https://example.org/qux-${version}.tar.gz"
+checksum=def456...
+# ...fields reorderedProblems:
- Added
configure_argsnobody asked for. - Reworded
short_descand reordered fields — noise in the diff. - The real change is three lines.
What should happen (surgical):
-version=1.4
-revision=3
+version=2.0
+revision=1
-checksum=abc123...
+checksum=def456...Version, revision reset to 1, new checksum. Nothing else.
User request: "Rebrand the distro name in base-files."
What LLMs often do (mass rename):
# Runs across the whole tree:
grep -rl void srcpkgs/ | xargs sed -i 's/void/sunlight/g'Problem: this rewrites package names (void- packages), upstream URLs,
mirror hostnames, kernel/module references, and vlogo-type asset names — most
of which must match upstream. It breaks builds and turns every future
void-packages sync into a conflict storm.
What should happen:
Change only the intended branding string in the intended file:
# srcpkgs/base-files/files/os-release
-NAME="Void"
-PRETTY_NAME="Void Linux"
+NAME="Sunlight"
+PRETTY_NAME="Sunlight Linux"
-HOME_URL="https://voidlinux.org/"
+HOME_URL="https://sunlightlinux.org/"The rebrand stays concentrated; package names and upstream references are untouched.
User request: "foo fails to build."
What LLMs often do (fix without reproducing):
+hostmakedepends="pkg-config automake libtool gettext flex bison"(Throws a pile of build deps at it on a hunch.)
What should happen (reproduce in a clean masterdir):
Plan:
1. Reproduce: ./xbps-src pkg foo (clean masterdir).
Verify: capture the actual error (e.g. "configure: error: pkg-config not
found" or a missing header).
2. Map the error to one missing piece (a hostmakedepends like pkg-config, or a
makedepends like libfoo-devel).
Verify: the error names exactly what's missing.
3. Add just that dependency.
Verify: ./xbps-src pkg foo now builds; xlint clean.
Add the one dependency the build actually needs — not a grab-bag.
User request: "Sync slpkgs with the latest void-packages."
What LLMs often do (all at once):
git merge upstream/master, blindly accept all conflict resolutions, and push —
without rebuilding anything or checking the rebrand survived.
What should happen (incremental):
Plan:
1. Add upstream remote and fetch:
git remote add upstream https://github.com/void-linux/void-packages.git
git fetch upstream
Verify: upstream/master is available.
2. Merge; resolve conflicts only in the rebranded packages (base-files, GRUB,
efibootmgr, …) — keep Sunlight branding, take upstream elsewhere.
Verify: git diff shows the rebrand intact and a small delta.
3. Rebuild the packages touched by the merge.
Verify: ./xbps-src pkg <changed> succeeds; xlint clean.
4. Smoke-test the base-system packages (ideally in a VM).
Verify: os-release/branding correct; system boots.
Each step is checkable; the concentrated rebrand is what makes step 2 tractable.
| Principle | Anti-pattern | Fix |
|---|---|---|
| Think Before Coding | Bare do_build(){ make } for "add package foo" |
Ask build system + deps + source/checksum; use a build_style |
| Simplicity First | Hand-written cmake do_* steps |
build_style=cmake |
| Surgical Changes | sed -i s/void/sunlight/g across srcpkgs/ |
Change only the intended branding string in the intended file |
| Goal-Driven | Pile of hostmakedepends on a hunch for a build failure |
Reproduce in a clean masterdir; add the one missing dep |
The "overcomplicated" examples aren't obviously wrong — explicit build steps, extra subpackages, and broad renames all look thorough. The problem is timing and blast radius: in a packaging fork, premature breadth and incidental edits either break the build, ship empty/wrong packages, or — worst for a fork — inflate the delta from upstream so every void-packages sync becomes a conflict storm.
- Match upstream void-packages idiom; the smaller the diff, the easier the merges.
- Keep the rebrand concentrated; never mass-rename
void→sunlight. - The real test is
./xbps-src pkgin a clean masterdir, plusxlint.
Good slpkgs changes are the smallest template/rebrand delta that solves the need while staying buildable and mergeable with upstream void-packages.