nix module: agentPackages attrset + extraPackages + agent tools baseline (replaces claudePackage) #74
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab#74
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Context
The NixOS module puts agent CLIs and tools on the lab unit PATH (which every spawned session inherits via the tmux server). Today that surface is claude-shaped and bare:
claudePackage(defaultnull) — one provider, no way to add the Codex CLI (#2) without the rawsystemd.services.lab.pathescape hatch.awk,tar,curl,jq,file,unzip,patch— andps/rgare present only as an accident of the nixpkgs claude-code wrapper prefixing its own PATH, so a second provider's sessions would not get them.nixon PATH, so agents cannot use a project flake's devshell for per-project toolchains and instead grovel/nix/store.Both agent CLIs exist in nixpkgs (
claude-code, unfree;codex, the OpenAI codex-cli). Design was resolved in a grilling session on 2026-07-09; the agent brief below is the contract.Relation to #2
This issue only puts the
codexbinary on the sandbox PATH and generalizes the module seam. The CodexAgentProviderimplementation stays #2 and remainsready-for-human.Agent Brief
Category: enhancement
Summary: Replace the
claudePackageoption with a provider-keyedagentPackagesattrset (claude-code + codex defaults), add an additiveextraPackageslist, and give the unit PATH a fixed baseline of standard agent tools includingnix.Current behavior:
The
services.labNixOS module assembles the systemd unit PATH from the lab package, git, tmux, openssh, util-linux, plus an optional singleclaudePackage(defaultnull). Sessions inherit this PATH. There is no way to declare a second agent CLI, no general tools baseline (awk,tar,curl,jq,file,unzip,patchare all absent),psandrgreach sessions only via the nixpkgs claude-code wrapper (so non-claude sessions would lack them), andnixis not on PATH.Desired behavior:
services.lab.agentPackages—attrsOf (nullOr package). Keys are lab provider IDs (the same strings the provider registry, DBprovidercolumn, and API use): default{ "claude-code" = pkgs.claude-code; codex = pkgs.codex; }. Every non-null value'sbin/lands on the unit PATH. Setting one key tonulldisables that CLI without touching the other defaults (attrset per-key merge). The option description must note thatclaude-codeis unfree in nixpkgs and that consumers who forbid unfree software can setagentPackages."claude-code" = null.services.lab.extraPackages—listOf package, default[], appended to the unit PATH. Purely additive: setting it must never affectagentPackagesor the baseline.gawk,gnutar,gzip,xz,zstd,unzip,curl,jq,file,patch,procps,ripgrep, and the host'sconfig.nix.package(so sessions can usenix develop/nix shellfor per-project toolchains). Deliberately no language toolchains — those come from each project's flake.claudePackagebecomes a deprecated alias: when set (non-null) it populatesagentPackages."claude-code"and emits a deprecation warning. An assertion fails eval with a clear message when bothclaudePackageand an explicitagentPackages."claude-code"definition are set.Key interfaces:
services.lab.agentPackages/services.lab.extraPackagesoption declarations as abovepathassembly in the module — merges baseline + non-nullagentPackagesvalues +extraPackagesclaudePackagewith a stand-in package — extend it to cover the new optionsAcceptance criteria:
claudeandcodexresolve on the unit PATHagentPackages."claude-code" = nullremoves claude from PATH while the codex default survives (per-key merge, not replacement)extraPackages = [ pkg ]appends without dropping any baseline tool or agent CLIawk,tar,xz,zstd,unzip,curl,jq,file,patch,ps,rg,nixclaudePackagealone still works, warns, and lands the package on PATH asagentPackages."claude-code"claudePackageandagentPackages."claude-code"fails eval with an assertion naming both optionsnullopt-outnix flake checkpasses with the updated VM testOut of scope:
AgentProviderimplementation (#2,ready-for-human)claudePackagefor the new options) and the rebuild/deploynix developin a spawned session) — one-time manual check at deploy timenode,go,python3, compilers) in the baseline — intentionally excluded in the design session; per-project flakes are the mechanismLanded PR #76 —
feat(nix): agentPackages attrset + extraPackages + agent tools baseline (ADR-0033). Verdict PASS, merged intomain.Checked:
afk/74, validCloses #74); cleanly mergeable (based on currentmain, no conflicts).agentPackagesper-keymkOptionDefaultmerge (null opt-out works), conflict assertion keys on real definition priority viamergeAttrDefinitionsWithPriowithout forcing unfree values,claudePackagedeprecated-alias//override + warning, fixed baseline +config.nix.package+ additiveextraPackages.hellovia the alias and nulls codex, keeping both real CLIs out of the realized closure, then greps serialized unit PATH.Signal relied on: both CI gates green —
ci / native(required) and the authoritative hermeticci-nix / flake-check(Successful in 14m7s), which runs thenixos-modulecheck this PR extends. Not re-run locally.Noted, non-blocking: the runtime VM test (baseline tools resolving from a live session shell) is deliberately deferred to M8 and replaced by eval + unit-text assertions — documented in the PR body and ADR-0033.