feat(nix): expose declarative outputs and a home-manager module (task 0045) #54
Reference in New Issue
Block a user
Delete Branch "task-0045-declarative-nix-outputs-and-hm-module"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements
.claude/tasks/0045-declarative-nix-outputs-and-hm-module.md.What was built
Two layers, the second built on the first.
The package installs the bundled Agent Skill to
share/gitea-axi/skills/gitea-axiand publishes it aspassthru.skill, alongsidepassthru.sessionStartHook. The hook entry is read fromsession-start-hook.json, a committed declaration the fast tier reads too — so a new test drivessetup hooksagainst a temporary home and asserts what it writes deep-equals what the file declares, failing if either side drifts (including if the agent SDK changes its envelope).The flake exposes
homeModules.gitea-axi, a wiring layer declaring both from those attributes. It goes through home-manager's ownprograms.claude-codeoptions rather than writingsettings.jsondirectly, so an operator's existing skills and SessionStart hooks compose instead of colliding.Verified against real home-manager on five configurations: importing without enabling yields a byte-identical generation to never importing at all; enabling alongside a config that already declares its own hook and skill yields both of each;
package = nullinstalls no binary but still declares the Skill; the skill-only toggle declares no hook; and omittingprograms.claude-code.enablefails the assertion with the intended message.nix buildis green and bit-reproducible under--rebuild; the full fast tier passes (434 tests).Deviations
session-start-hook.jsonholds the settings entry verbatim, not the fields it is assembled from — declaring the fields would have left the grouping restated in both the Nix expression and the test.package = nullstill sources the Skill from the default build. The task settled where the binary comes from, not where the Skill's bytes do. Documented on the option rather than designed away.programs.claude-code.skills' bare-path form cannot have an entry merged into it.README.md, soINSTALL.md— following the existing convention of topic-scoped root documents alongsidePUBLISHING.md— is discoverable only by browsing the repo, and does not ship in the npm tarball. Adding a README is its own piece of work.A
## Gotchasentry was added toCLAUDE.mdfor anix flake checkfailure mode hit during this work: on a dirty tree it intermittently reports the filtered source path as invalid, which reads as an allowlist bug but is an eval-cache artefact.Review
Risk
Overall: MEDIUM
package.nixtofinalAttrsform with a newpassthrusurface, though existing behaviour is preserved.homeModules.gitea-axiand thepassthruattributes are a published Nix interface downstream configurations can pin, so removing them later is breaking rather than a revert.nix flake check(ADR 0020).Unaddressed findings
Spec —
INSTALL.mdis not in the npmfilesallowlist, so it does not ship in the tarball. Left as a flagged follow-up: the real discoverability gap is the absentREADME.md, and installation instructions inside an already-installed tarball are of little use.Risk — the module is exercised by no automated test. Accepted deliberately and recorded in ADR 0020: covering it means taking home-manager as a flake input purely to test against, and this matches the spec's existing position that the flake's consumption from a system configuration is verified by the maintainer's rebuild.
Standards findings (test duplication, an inaccurate default in the options table) were fixed and are in the diff.