Let's create skills for nixpkgs development

Prior PR, still open and under discussion:

3 Likes

Very much this. It’s like walking into a room waving a big gun around and wondering why everyone else pulled their gun on you.

1 Like

If anybody would like to DM me, I’d like to put together a working group on the Agents thing. I’m bummed that work in this area wasn’t handled as part of GSoC but I think we’re well at the point where a polished approach could be helpful.

DM me here on Discourse and let’s put together a team.

5 Likes

I am against the symlink. Any decent agent must support the standard locations.

1 Like

Well that’s worse:) It’s much easier to help newcomers when their slaup is obvious and quickly rejected?

12 Likes

@lucasew please do!

(PS: I’m not quite active here, but this thread got my attention.)

Nix needs proper AI skills, written by the community in a shared effort. It’d be so good for developers starting with Nix, as well as experienced ones using AI to automate tasks.

I see that there’s a lot of discussions between people, some who seems to not love AI so much, and I get it – but for those using AI to get real work done, it’d be awesome!

A model-agnostic AI skill for Nix would sure reduce errors from AI output over Nix tasks. It’s pure prompt engineering, loaded right at model’s first moments processing a user/agent prompt, and since it’s purpose-specific, it could be customized for AIs.

LLMs can read the manual, and are good at that.

I saw this argument. It’s solid, makes sense – but then, an AI would have to fire up web searches, HTTP requests, etc., just to figure out the very first steps (what’s Nix, what problem it solves, how does it work overall, its most important terminology, where to find official/accurate info like official docs and forums, official news, etc.) – which all turns into token [and context] consumption. If there’s a skill providing the basic building blocks of using/working with Nix, token usage would be optimized, and of course the time taken to get the final results would be seriously reduced.

I know it does not solve AI slopness, it won’t make AI perfect, etc., etc. – but it sure does help AI on getting closer to do things right.

Yes, but doing skills for everything would create redundancy and I don’t want to maintain that, do you? Ideally the skill/agents should be about telling where to look for information and guidelines. Perhaps a common denominator that both human docs and agents can consume in a efficient way. Perhaps even as part of CONTRIBUTING.

I am having a good time with that AGENTS, stuff where the model struggles is mostly lazyness and skimmimg that the model can do or it assuming it has a decision autonomy it doesn’t have. Nothing that a short leash and a “don’t ping people if I didn’t ask you to” policy can’t do.

In my experience, today models have a pretty good understanding out of the box about Nix. They just mess up on the guidelines without guidance. Like nixpkgs is a project that is a evolving standard, with processes and stuff, AI today already can handle that. Doing skills for every facet I think is overkill. It can figure out through human documentation, we just have to set up a basic checklist and guideline for it to give less review hassle for us. Like reviewing by asking a predefined set of questions.

For Nix itself, I think the most impactful trick to teach it is to do Nix introspection, like, instead of it fetching the source at specific checkout in TMP to then inspect the upstream code, it could just nix build .#package.src and inspect that.

1 Like

Additionally, I am working on a janitor skill. A generic thing that I think I will keep as a proprietary thing that is a process to find tech debt issues generically on repos by supporting on best practices skills and guidelines. I asked it to give me a unslopified report of the 10 most impactful issues of nixpkgs. I wasn’t aware of the issues. This was a 5 minute work essentially.

Report

nixpkgs janitor report

Tree: 8f7639a0d4d3 on upstream/master (scanned 2026-07-05).

Walked the janitor checklist on lib/, pkgs/stdenv, pkgs/build-support, pkgs/by-name, pkgs/top-level, nixos/lib, nixos/modules (spot checks), ci/, contributor docs, and maintainer scripts. Ranked by how much they cost contributors and how far the blast spreads. Package-local TODOs in pkgs/by-name were ignored unless they point at shared machinery.

Checked and set aside:

  • Vendor best-practices skills: none in the local corpus cover Nix/nixpkgs, so no “apply skill X” items.
  • AI entrypoints: no AGENTS.md, CLAUDE.md, or .github/copilot-instructions.md. Nothing to deslop there.
  • setup.sh logging: already levelled via NIX_DEBUG / NIX_LOG_FD. Noisy echo remains in failure paths; not top ten.
  • Impure getEnv / currentSystem: intentional in impure.nix and eval entrypoints.

Numbers are approximate.


1. CI turns off whole nixf rule families

Explanation

ci/treefmt.nix runs nixf-diagnose --auto-fix on *.nix, then nixfmt at a higher priority “to clean up after” it. That pairing admits the tools fight. On top of that, four unused-binding rules and four prelude/primop rules are --ignored, with TODOs that say “remove and fix” or point at open nixd issues (#761, #762). Generated Home Assistant and hackage2nix files are excluded instead of fixing the generators. ci/nixpkgs-vet.nix still carries in-tree checks marked for upstreaming (nixpkgs-vet#164, #166) and uses grep ... || true so a find failure looks like success.

At this repo size, disabled static checks mean dead formals and lets only die in review.

No change to package build output; CI starts failing on code it currently skips.

Plan of attack

Pick one ignored rule (unused let in lib/ and pkgs/build-support/ first). Enable it on a path allowlist, fix in batches, widen the list, delete the flag. Put calendar expiry comments on ignores that wait on nixd.

Upstream the <nixpkgs/ and case-conflict checks into nixpkgs-vet and drop the shell copies. Make generators emit nixfmt/yamlfmt-clean output so excludes can go. Keep nixf priority below nixfmt until auto-fix stops fighting the formatter, or drop auto-fix for rules that churn formatting.


2. Bot fallback code past its delete-by dates

Explanation

ci/github-script/bot.js still fetches pr.yml artifacts with “Remove this after 2026-02-01”. It still rebuilds package lists from maintainers.json when packages.json is missing, with “should be gone ~ February 2026”. It still passes advanced_search: true with “Remove after 2025-11-04, when it becomes the default.” Today is past all three. Extra branches mean extra API calls, harder reviews, and labels derived from the wrong artifact shape on old PRs.

merge.js still plans a more efficient touched-file download. reviewers.js and check-target-branch.js note structural overlap with prepare.js.

Behavior change for very old open PRs that only have expired artifacts; fine for current traffic.

Plan of attack

Delete the pr.yml fallback and the maintainers.json package-list fallback; run the bot test suite / a dry run on a recent PR. Drop the redundant advanced_search flag if the API default holds. File or finish the by-name path-based “changed packages” work so eval artifact expiry hurts less. Fold target-branch checks into prepare.js in one pass. Re-read every TODO: Remove after in ci/github-script/ on each release branch cut.


3. pkgs/by-name cannot express custom callPackage args

Explanation

~21.4k package.nix files live under pkgs/by-name. all-packages.nix is still ~11.2k lines with ~1.5k callPackage mentions. Examples still bind by-name paths with extra args (alacritty + withGraphics, ollama-* accelerators, etc.). by-name-overlay.nix keeps _internalCallByNamePackageFile and a TODO: until by-name owns custom call args, all-packages.nix must override and CI must detect empty {} overrides.

Only by-name PRs auto-merge. The README still points at automated migration (nixpkgs-vet#56) that cannot finish while this hatch exists. The two-letter shard prefix is documented magic; the real pain is the split brain between overlay and all-packages.nix.

Moving implicit args into the package function changes .override interfaces. Release-note those.

Plan of attack

Inventory non-empty second arguments and other by-name shadows. Split into renamed dependency parameters, real defaults, and alias/override wrappers.

Add a CI-enforced way to declare call defaults inside the package directory. When the inventory is covered, make stage.nix error on all-packages.nix shadows and delete _internalCallByNamePackageFile. Run the empty-{} migrator for the rest; keep renames in aliases.nix. Gate on ./ci/nixpkgs-vet.sh and ci/eval.


4. Language package sets never got a by-name layout

Explanation

perl-packages.nix ~40k lines, python-packages.nix ~23k lines, ~9.7k directories under pkgs/development/python-modules. by-name docs exclude python3Packages.callPackage and nested attrs. Edits collide on rebase; auto-merge does not apply; eval/review cost follows set size. Haskell already generates lists and then excludes them from yamlfmt because the generator emits churn.

Python still carries overrideStdenvCompat and __stdenvPythonCompat* hooks with removal TODOs in python-packages-base.nix and mk-python-derivation.nix, so even the builder API is mid-migration.

Overlay and withPackages behaviour must stay stable; diff eval output.

Plan of attack

Pathfind on Python. Write invariants (overlays, toPythonModule, disabledIf, cross, stubs, overridePythonAttrs). Add a sharded tree plus an overlay map with the same performance budget as by-name-overlay.nix. Reuse vet ideas: one package per dir, no out-of-tree refs, no dup attrs.

Migrate in chunks with eval diffs; shrink python-packages.nix to a shim. Finish overrideStdenvCompat removal on a named release so the new layout does not preserve the shim. Fix hackage2nix/output generators before touching Perl by hand. Update doc/languages-frameworks/ so new modules never join the monolith.


5. mkDerivation teaches two dependency languages

Explanation

make-derivation.nix marks nativeBuildInputs / buildInputs (and propagated variants) as legacy next to depsBuildHost and friends, but both work. strictDeps, configurePlatforms, and doCheck / doInstallCheck defaults still depend on platform and config flags, with TODOs citing #87909, #178468, #33599. stdenv/generic/default.nix leaves fixes commented to avoid mass rebuilds. Manual chapters still lean on the legacy names (doc/stdenv/stdenv.chapter.md alone has dozens of nativeBuildInputs hits).

Same concept, two vocabularies. Cross reviews stay harder than the offset model deserves.

Flipping defaults changes every derivation on staging.

Plan of attack

One design note: each conditional default, end state, rebuild set. Flip config.strictDepsByDefault, configurePlatformsByDefault, and check defaults one at a time on staging. Warn via problems before hard errors.

Prefer offset names in new docs and examples; keep legacy attrs as aliases. Optionally vet new stdenv code in pkgs/build-support for legacy-only style where offsets are clearer. Use ci/eval compare for rebuild proof, not guesswork. pkgsi686Linux special-casing in stage.nix belongs in the same cleanup once it can be a variant.


6. meta validation is weaker than the comments admit

Explanation

check-meta.nix documents a bug: string licenses make isUnfree return false. License type is still attrs | str with “TODO disallow str”. Maintainers and teams are listOf attrs instead of the types already prototyped in lib/tests/maintainer-module.nix. problems.nix has thinner docs/remediation than the framework needs.

~14.1k by-name packages omit mainProgram, so lib.getExe guesses. ~1.2k by-name packages still use mkDerivation rec while ~15.7k already use finalAttrs.

Invalid meta that evaluates today will warn, then error. String license policy fixes can change unfree detection for mislabeled packages (correctness fix, still user-visible).

Plan of attack

Fix the string-license isUnfree bug under tests. Warn on string licenses and freeform maintainer attrs for one release, error the next; codemod to lib.licenses.* and list entries from maintainer-list.nix.

Require mainProgram for new by-name packages that install a single obvious bin/ entry; report high reverse-dep misses for backlog PRs. Point remediation strings at real manual anchors. Codemod trivial rec to finalAttrs in by-name. Keep known-vulnerability handling fail-closed.


7. NixOS option shims and default types.str

Explanation

~1635 mkRemovedOptionModule / mkRenamedOptionModule / mkAliasOptionModule / mkChangedOptionModule uses. ~5571 types.str hits, ~458 files with bare type = types.str;. ~74 mdDoc / literalMD / mkAliasOptionModuleMD leftovers; mkAliasOptionModuleMD is warned for removal in 26.05.

Every config eval pays the rename tables. types.str accepts "" and path-like values, so mistakes show up when a service starts.

Removing aliases and narrowing types needs transition renames and release notes.

Plan of attack

Generate shim inventory with add version and delete version. On unstable, expire shims older than N releases (error, then remove) and auto-draft release notes from the list. Finish MD alias removal for 26.05.

Replace hot-path types.str with nonEmptyStr, singleLineStr, path, passwdEntry, or a submodule (users, networking, nginx, security first). CI nag on new bare types.str without a comment. Optional: thunk counts on nixos/release-small.nix before/after large deletions.


8. Contributor docs are split and partly hollow

Explanation

CONTRIBUTING.md ~965 lines, pkgs/README.md ~1264, pkgs/by-name/README.md ~219, plus doc/contributing/*. Several manual chapters are stubs that only link to GitHub (quick-start, contributing-to-documentation). Readers bounce between root, pkgs/, doc/, and nixos/README.md for the same questions (how to add a package, review norms, auto-merge rules).

That is human-facing duplication in the same spirit as AI entrypoint slop: copy instead of a single pointer map. It also hides the non-obvious rules (when all-packages.nix must stay, when inherit ({ ... }) is required for multi-version packages).

Doc-only; no eval change.

Plan of attack

Make root CONTRIBUTING.md a short map: links to pkgs/README.md, pkgs/by-name/README.md, nixos/README.md, doc/README.md, CI/eval README, modular services README. Move procedural detail once; delete repeats.

Replace stub chapters with in-tree relative links that render in the manual, not only master (Oleg Smirnov) · GitHub URLs. Add a single “where does this package file go?” decision section that includes by-name limits and language sets. Keep release-specific process out of package authoring docs.


9. Image and channel builders repeat the same FIXME

Explanation

make-disk-image.nix, make-single-disk-zfs-image.nix, and make-multi-disk-zfs-image.nix all say merge with channel.nix / make-channel.nix. make-channel.nix hardcodes officialRelease = false with a makeSourceTarball FIXME. make-iso9660-image.nix keeps a Hydra copy workaround. Fix one flavor, miss another. Release and installer paths are high-stakes for a copy-paste bug.

Internal refactors are fine; warn if out-of-tree scripts import private nixos/lib paths.

Plan of attack

Extract one helper for channel closure, registration, and ownership. One attrset for release/version metadata with tests. Assert metadata parity across image kinds in installer tests. Re-validate the ISO copy trick on current Nix/Hydra and keep it in one place. Document public entry points in nixos/README.md. Delete duplicates after linux smoke tests.


10. Module system API is deprecated in place with gaps in errors

Explanation

lib/modules.nix (~2342 lines) still accepts deprecated evalModules args / check, warns on external lib.modules.*, and ships mkAliasOptionModuleMD toward 26.05 removal. FIXME: handle mkOrder? sits in ordering logic. Merge helpers have a “merge into mergeOptionDecls” TODO. Error text sometimes omits useful opt context. nixos/lib/eval-config.nix mirrors extraArgs / check deprecations. nixos/lib/from-env.nix duplicates lib.maybeEnv (which itself lives under lib/deprecated/misc.nix while still re-exported from lib/default.nix) and is imported from nixos/default.nix, activation, and option-usages.

External frameworks and in-tree code share a blurry boundary. Weak errors turn ordinary misconfigs into long threads. maybeEnv sitting in lib/deprecated while NixOS reimplements it is inconsistent wording about what is supported.

Removing deprecated args/attrs breaks callers still on the old surface. from-env removal is straightforward if all callers switch to lib.maybeEnv.

Plan of attack

Publish the supported module-system surface in lib/README.md and the manual; stronger warnings in 26.05, removals aimed at 26.11. Migrate in-tree callers to config._module.args / config._module.check.

Fix mkOrder handling and richer invalid-option errors with tests in lib/tests/modules. Only merge declaration helpers if NixOS eval thunk counts do not regress. Remove mkAliasOptionModuleMD on schedule. Switch from-env.nix callers to lib.maybeEnv and delete the file; if maybeEnv remains supported, move it out of lib/deprecated or document why it stays. Keep a short lib changelog for home-manager and friends.


Honorable mentions

cc-wrapper (~1015 lines) plus setup hooks. Critical path, arch exceptions, env vars that need stdenv rebuilds to rename. Refactor behind tests on Darwin/musl/static/cross; schedule renames on staging.

Full ci/eval wants ~16GB RAM (chunkSize default 5000 is unexplained magic in ci/eval/default.nix). Name the default, document laptop quickTest / remote eval paths, tune chunks with measured memory curves.

maintainers/maintainer-list.nix (~31.5k lines). Shard or generate; keep team-list.nix stable.

Modular services. lib/services/* is five files and ~11 _class = "service" modules beside ~1700 nixos/modules/services files. README still says “TBD: describe best practices” and points at #428084. Write the missing practices and an exit criterion before growing dual maintenance.

Splicing shortcuts in splice.nix / stage.nix (partial splice for performance, pkgsi686Linux TODO). Needs benchmarks before uniformity.


Order to chip at this

  1. #2 delete expired bot branches (small, overdue).
  2. #1 enable one nixf rule on a narrow path.
  3. #6 fix string-license isUnfree bug + start maintainer typing warnings.
  4. #8 shrink CONTRIBUTING to a map (clarifies everything else).
  5. #3 design by-name custom call args.
  6. #4 Python sharding design after #3’s vet patterns exist.
  7. #7 shim expiry policy + hot-path types.str.
  8. #10 module API + delete from-env.nix.
  9. #5 / cc-wrapper on staging windows.
  10. #9 when already touching image code.
  11. Modular services docs/exit criteria before more ports.

Counts

Thing ~Value
TODO/FIXME/HACK/XXX in pkgs/build-support 96
same in lib/ 52
same in pkgs/top-level 45
same in pkgs/stdenv 35
lib.warn / deprecate / remove throws in core libs 1611
pkgs/by-name/**/package.nix 21416
all-packages.nix lines 11212
callPackage mentions there 1552
perl-packages.nix lines 39777
python-packages.nix lines 22626
Python module dirs 9755
NixOS compat shim calls 1635
types.str in nixos/modules 5571
files with type = types.str; 458
mdDoc-era leftovers 74
by-name without mainProgram 14123
by-name with finalAttrs 15746
by-name with mkDerivation rec 1232
mkDerivation rec across pkgs/ 2012
_class = "service" modules 11
nixos/modules/services nix files 1708
lib/modules.nix lines 2342
setup.sh lines 1834
cc-wrapper/default.nix lines 1015
maintainer-list.nix lines 31560
CONTRIBUTING.md lines 965
pkgs/README.md lines 1264

So now we’re trying to hide the fact that an LLM is doing the work for you?

6 Likes

I never hid

I read what it gives to me, ask questions when I have them, ask it to reformulate, to take more stuff into consideration, sometimes I ask it to work on a specific situation and if it makes sense I send a draft. When I think it’s ready for review I undraft the stuff.

That Janitor skill runs overnight though Jules using another trick I have because Jules by itself doesn’t support skills natively. And it’s getting really good at finding duplicated logic around a codebase. Lots of situations that would be overlooked or be too much hassle for too little benefit being slashed in the background.

If the pass is not so great then I iterate on the questions it has to answer so on the PR body I have the whole context.

I think there’s a lot of possibility for Nix + LLM: We have a huge amount of maintenance that runs every release cycle that is tedious for a human, but not something a conventional automated system can manage right away. I’ve been coming at this from a different direction: piecewise AGENTS.md files for individual nix flakes/the general ecosystem.

The skill is a good place to start! It’s a tiny addition, and it has the possibility to ease adoption and improve feature discovery, both of which are huge pain points.

We should talk in DMs!

1 Like

Came across this in a GitHub search for nixpkgs + LLM: GitHub - jpds/temporal-nixpkgs-workflows ¡ GitHub

Most people already know this one, but for those who might not:

Has most of the popular harnesses all prepped for nix in one place.

Made with Astro, DaisyUI and the impeccable skill because I am not a designer.

Do you know who wrote impeccable? Paul Bakaus, who I worked with for many years and count as a friend. He could only write that because he spent decades honing his skills including deep expertise as a Developer Advocate at Google.

Impeccable does amazing work, and it puts human judgement front and center. You still need to review and suggest corrections, and that requires taste and experience.

If you want to write agent skills for nixpkgs, you need to put in your time as a committer (with recent experience) and reviewer. Learn what’s important within the community. Make your skills small, composable, assistive, and outside the codebase where developers can choose to use them. Augment individual tasks, with a person being in charge.

Human in the loop, always.

P.S. Please read Unwritten style guides should be written ¡ Issue #387072 ¡ NixOS/nixpkgs ¡ GitHub (I linked to a specific comment s a starting point).

4 Likes

A automation around validating standardization end to end to make nitpicking 100% pointless would be the endgame. As I said, standardized formatting was a huge leap already. My dream is we only being responsible of debating technical merit and letting machines check the rest as determinisitically as possible. And AI being the tool to run the checklists so we can focus on the techincal merit of the stuff. Perhaps even delegating to AI the routinely boring tasks like dealing with simple build and update failures transforming a making problem into a reviewing problem. Instead of going through a queue of requests, going through a queue of suggested solutions well fundamented on tests and good tested hypothesis. Heck, Grok is being BEAUTIFUL for this kind of work.

1 Like

Therein lies the rub: AI is non-deterministic. Even if you set the temperature to 0, you’ll get an inconsistent result when 1) the LLM updates, 2) somebody updates an AGENTS.md, etc.

It’s also hugely inefficient and expensive (the foundation already has a huge Github bill, it doesn’t need an AI bill that’s orders of magnitude higher).

If you ever write a PRD (Product Requirements Document), the first rule is specify outcomes, not implementation. AI is an implementation detail and comes with enough ethical baggage that it needs to be opt-in (read: up to the individual maintainer). This also aligns with our current AI policy.

On requiring everyone to use AI:

It’s like the poor lord who went around giving everybody liver pate for Winterfair and wondering why nobody ever returned the favor. - Lois McMaster Bujold, Winterfair Gifts

4 Likes

AI wouldn’t be required. It’s just a matter of how much time vs tokens you are willing to spend on details.

But there are facets of the guidelines, like formatting, that can be checked by deterministic processes. The less we have to do checklists manually the less time we waste.

AI would give a good v0, but over time we could check the most common issues using deterministic processes, like how nixpkgs-vet is doing.

2 Likes

Please read AI is burning out the people who keep open source alive (one of a great many examples)

1 Like

That’s completely irrelevant to this discussion. If you have automation to contribute, then do so. AI is not automation.

3 Likes