Skip to content

refactor(claude): delegate programs.claude.* to nix-claude-code#851

Merged
JacobPEvans-personal merged 3 commits into
mainfrom
refactor/delegate-claude-to-nix-claude-code
May 30, 2026
Merged

refactor(claude): delegate programs.claude.* to nix-claude-code#851
JacobPEvans-personal merged 3 commits into
mainfrom
refactor/delegate-claude-to-nix-claude-code

Conversation

@JacobPEvans-personal
Copy link
Copy Markdown
Member

Summary

PR3 of the nix-ai → nix-claude-code migration (Checkpoint 2/4 per
docs/migration-from-nix-ai.md).
nix-ai now consumes the Claude module from dryvist/nix-claude-code instead of
defining its own.

  • Add nix-claude-code as a flake input with nixpkgs/home-manager/
    ai-assistant-instructions/claude-code-plugins follows overrides.
  • Drop 20 marketplace flake inputs (anthropic-agent-skills, bills-claude-skills,
    bitwarden-marketplace, browser-use-skills, cc-dev-tools, cc-marketplace,
    claude-code-plugins-plus, claude-code-workflows, claude-plugins-official,
    claude-skills, jacobpevans-cc-plugins, lunar-claude, obsidian-skills,
    openai-codex, axton-obsidian-visual-skills, superpowers-marketplace,
    visual-explainer-marketplace, wakatime, huggingface-skills,
    vct-cribl-pack-validator-skills) plus claude-cookbooks. They're now transitive
    inputs through nix-claude-code; surfaced to non-Claude consumers via
    nix-claude-code.inputs in flake/home-manager-modules.nix. karpathy-skills
    stays in nix-ai (newly added to main while PR3 was in flight; not yet in
    nix-claude-code's catalog).
  • Delete the migrated Claude code (~30 files, ~4500 deletions) and its
    CI-only generators:
    • modules/claude/{options-*.nix, settings.nix, plugins.nix, components.nix, registry.nix, orphan-cleanup.nix, marketplace-overrides.nix, default.nix, README.md, bws_helper.py, get-api-key.py, bws-env.example, fabric-curated-patterns.json, hooks/, scripts/, statusline/}
    • modules/{claude-plugins.nix, claude-latest.nix}
    • modules/claude/plugins/marketplaces.nix (tier files
      01-official.nix..05-specialty.nix stay; default.nix rewritten to a
      smaller tier aggregator)
    • modules/permissions/claude-permissions-{allow,ask,deny}.nix
    • lib/{claude-settings.nix, claude-registry.nix}
  • Rewrite modules/claude-config.nix as a pure-values module (model,
    marketplaces, hooks, settings.*). Marketplaces come from
    nix-claude-code.lib.{marketplaceCatalog, marketplaceOverrides};
    settings.permissions still flows through nix-ai's modules/common
    formatter engine so Codex/Gemini share the source of truth.
  • Add modules/claude/automode-environment.nix (homelab-trust prose for
    Claude's auto-mode classifier, sourced from userConfig.user.fullName).
  • Update flake/home-manager-modules.nix to import
    nix-claude-code.homeModules.claude alongside ../modules/default.nix
    for the default module and ../modules/claude-config.nix for the
    standalone claude module. The import lives at this layer (not inside
    default.nix) so the import list resolves without depending on
    _module.args.nix-claude-code — module imports run before args are
    wired, which would otherwise cause infinite recursion.
  • Rewrite lib/checks/claude.nix to drop tests that referenced deleted
    lib/claude-settings.nix; structural settings.json validation is now
    covered by nix-claude-code's own CI. Trim fabric-marketplace-build
    from lib/checks/fabric.nix (now lives in nix-claude-code).
  • Rebuild lib.ci.claudeSettingsJson from nix-claude-code.lib helpers
    • nix-ai's plugin tier files + permission formatters so downstream
      consumers (nix-darwin's _claude-settings.yml CI gate) see byte-
      identical output.

Why

Separation of concerns: nix-claude-code is the canonical owner of
programs.claude.* schema, the marketplace catalog, synthetic marketplace
derivations, the settings.json renderer, and hooks/MCP/statusline wiring.
nix-ai keeps the cross-tool surface (Codex, Gemini, Copilot, MCP, MLX,
Fabric, plugin enablement tiers, auto-mode trust prose).

This is Checkpoint 2/4 of the migration plan, executed without the
intermediate useExternalModule toggle because PR2
(dryvist/nix-claude-code#26)
already landed every option, hook, lib helper, and CI shim nix-ai needs.

Byte-equivalence (the safety contract)

diff <(nix eval --raw '/path/to/nix-ai/main#lib.ci.claudeSettingsJson' | jq -S .) \
     <(nix eval --raw '.#lib.ci.claudeSettingsJson' | jq -S .)
# → empty (0 lines)
# 716 lines on both sides

The CI fixture is byte-identical to current main. Downstream nix-darwin's
_claude-settings.yml workflow will see the same generated settings.json.

Test plan

  • Local nix flake check --no-build --all-systems --refresh passes
    every Claude-relevant check (module-eval, options-regression,
    defaults-regression, etc.).
  • Three baseline failures (agent-skills-home-files,
    fabric-version-sync, gemini-policy-engine) are pre-existing on
    main and unrelated to PR3 — verified by stashing this PR's changes
    and re-running flake check.
  • nix eval --raw .#lib.ci.claudeSettingsJson produces byte-identical
    output to main.
  • CI on x86_64-linux runs and passes (where the eval-cached drvs
    actually build).
  • Local darwin-rebuild build --flake ${HOME}/git/public/nix-darwin/main
    with this branch as the nix-ai input to validate end-to-end activation.

Deviations from the original plan

  • Kept karpathy-skills as a nix-ai-side flake input. It was added to
    main (PR feat(agent-skills): add karpathy-skills + auto-discover all marketplaces #831) while PR3 was in flight and isn't in nix-claude-code's
    marketplace catalog yet — promote upstream as a follow-up.
  • Schema renames are handled transparently by
    lib.mkRenamedOptionModule shims inside nix-claude-code's module
    (enabledPlugins → plugins.enabled, marketplaces → plugins.marketplaces,
    statusLine → statusline, hooks.extraHooks → settings.hooks), so no
    nix-ai-side renames were needed.
  • hooks.captureSessionOutput and hooks.refreshMarketplaces toggles
    replace the explicit postToolUse/sessionStart script paths
    (last-output.sh/marketplace-refresh.sh are vendored inside
    nix-claude-code now).

Refs: dryvist/nix-claude-code#26, #838, dryvist/nix-darwin#1141

What changed
- Add nix-claude-code as a flake input with nixpkgs/home-manager/
  ai-assistant-instructions/claude-code-plugins follows overrides.
- Drop 20 marketplace flake inputs (anthropic-agent-skills,
  bills-claude-skills, bitwarden-marketplace, browser-use-skills,
  cc-dev-tools, cc-marketplace, claude-code-plugins-plus,
  claude-code-workflows, claude-plugins-official, claude-skills,
  jacobpevans-cc-plugins, lunar-claude, obsidian-skills, openai-codex,
  axton-obsidian-visual-skills, superpowers-marketplace,
  visual-explainer-marketplace, wakatime, huggingface-skills,
  vct-cribl-pack-validator-skills) and claude-cookbooks. All are now
  transitive inputs through nix-claude-code; surface what nix-ai still
  needs via nix-claude-code.inputs in flake/home-manager-modules.nix.
- Delete the migrated Claude code from nix-ai:
  - modules/claude/{options-*.nix, settings.nix, plugins.nix,
    components.nix, registry.nix, orphan-cleanup.nix,
    marketplace-overrides.nix, default.nix, README.md}
  - modules/claude/{bws_helper.py, get-api-key.py, bws-env.example,
    fabric-curated-patterns.json, hooks/, scripts/, statusline/}
  - modules/claude/plugins/{marketplaces.nix} (tier files
    01-official..05-specialty stay; default.nix rewritten to a
    smaller tier aggregator)
  - modules/{claude-plugins.nix, claude-latest.nix}
  - modules/permissions/claude-permissions-{allow,ask,deny}.nix
  - lib/{claude-settings.nix, claude-registry.nix}
- Rewrite modules/claude-config.nix as a pure-values module (model,
  marketplaces, hooks, settings.*). Marketplaces use nix-claude-code's
  marketplaceCatalog + marketplaceOverrides; settings.permissions still
  flow through nix-ai's modules/common formatter engine so Codex/Gemini
  share the source of truth.
- Add modules/claude/automode-environment.nix (homelab trust prose for
  Claude's auto-mode classifier, sourced from userConfig.user.fullName).
- Update flake/home-manager-modules.nix to import
  nix-claude-code.homeModules.claude alongside ../modules/default.nix
  for the `default` module and ../modules/claude-config.nix for the
  standalone `claude` module. Module imports run before _module.args
  are wired, so the import goes at this layer (not inside default.nix)
  to avoid infinite recursion.
- Rewrite lib/checks/claude.nix to drop tests that referenced deleted
  lib/claude-settings.nix; structural settings.json validation is
  covered by nix-claude-code's CI. Trim fabric-marketplace-build from
  lib/checks/fabric.nix (now lives in nix-claude-code).
- Rebuild lib.ci.claudeSettingsJson from nix-claude-code.lib helpers
  + nix-ai's pluginTiers + permission formatters so downstream
  consumers (nix-darwin's _claude-settings.yml CI gate) see the same
  byte output as pre-PR3.

Why
- Separation of concerns: nix-claude-code is the canonical owner of
  programs.claude.* schema, marketplace catalog, synthetic marketplace
  derivations, settings.json renderer, and hooks/MCP/statusline wiring.
  nix-ai keeps the cross-tool surface (Codex, Gemini, Copilot, MCP,
  MLX, Fabric, plugin enablement tiers, auto-mode trust prose).
- This is Checkpoint 2/4 of the migration plan in
  nix-claude-code/docs/migration-from-nix-ai.md, executed without the
  intermediate useExternalModule toggle since PR2 already landed every
  option, hook, and CI shim nix-ai needs.

Byte-equivalence check
- `diff <(nix eval --raw '..main#lib.ci.claudeSettingsJson' | jq -S)
       <(nix eval --raw '.#lib.ci.claudeSettingsJson' | jq -S)`
  → empty. settings.json output is byte-identical to pre-PR3.

CI failures
- agent-skills-home-files, fabric-version-sync, gemini-policy-engine
  are pre-existing baseline failures (verified by stashing this PR's
  changes and re-running flake check on main). Not caused by PR3.
- All claude-specific checks pass (module-eval, options-regression,
  defaults-regression).

Refs: dryvist/nix-claude-code#26, #838, dryvist/nix-darwin#1141
@github-actions
Copy link
Copy Markdown

CI Auto-Fix Attempt 1/2

Claude is analyzing the CI failure and attempting a fix...

@JacobPEvans-personal JacobPEvans-personal marked this pull request as ready for review May 30, 2026 16:28
Resolves 4 statix warnings and 4 deadnix unused-binding warnings the
CI flake-check caught after PR3 was opened.

statix (flake.nix):
- Consolidate repeated `inputs.*.follows` into nested form
- Use `inherit (nixpkgs) lib` over `lib = nixpkgs.lib`
- Drop redundant parentheses around `ncc.claudeRegistry.toClaudeMarketplaceFormat`
- Convert `enabledPlugins = pluginTiers.enabledPlugins` to `inherit`

deadnix:
- flake.nix: drop unused `claude-code-plugins` from outputs destructure
  (it's still imported via `inputs.claude-code-plugins.follows`)
- flake/home-manager-modules.nix: drop unused `claude-code-plugins`,
  `fabric-src` args and the unused `claude-cookbooks` let binding
- lib/checks.nix + lib/checks/fabric.nix: drop unused `fabric-src` arg

No behavior change. All four checks now pass on CI parity flags
(`deadnix -L --fail .`, `statix check .`, `nixfmt-tree --fail-on-change`).
@github-actions
Copy link
Copy Markdown

CI Auto-Fix Attempt 2/2

Claude is analyzing the CI failure and attempting a fix...

Local statix 0-unstable-2026-05-14 missed this; CI's statix 0.5.8
flags it as "Assignment instead of inherit from".

Assisted-by: Claude <noreply@anthropic.com>
@JacobPEvans-personal JacobPEvans-personal merged commit 20fbd45 into main May 30, 2026
12 checks passed
@JacobPEvans-personal JacobPEvans-personal deleted the refactor/delegate-claude-to-nix-claude-code branch May 30, 2026 17:38
JacobPEvans-personal added a commit to dryvist/nix-darwin that referenced this pull request May 30, 2026
nix-ai PR #851 (refactor/delegate-claude-to-nix-claude-code) merged at
20fbd459106a. Bumping the lock to that SHA picks up the delegation so
nix-darwin now consumes programs.claude.* via nix-claude-code through
nix-ai's `imports`.

Resolves the prior `inputs.nix-claude-code.follows` warning on
non-existent input — PR3 added the input to nix-ai.

Refs: dryvist/nix-ai#851

Assisted-by: Claude <noreply@anthropic.com>
JacobPEvans-personal added a commit to dryvist/nix-darwin that referenced this pull request May 30, 2026
Three corrections to the migration's adoption shape, from review feedback:

1. **Drop nix-claude-code top-level input.** nix-darwin should not pull
   AI flakes directly — nix-ai is the only AI flake nix-darwin imports.
   nix-claude-code now flows transitively via nix-ai's input chain
   (dryvist/nix-ai#851 made nix-ai consume nix-claude-code), so this
   was strictly a leakage of Claude config concerns into nix-darwin's
   top-level. Removes the unhelpful "marketplace edge-pins cascade"
   comment too — that was the wrong design.

2. **Renovate: use dryvist as canonical org.** Switch
   `local>JacobPEvans-personal/.github:renovate-presets` →
   `local>dryvist/.github` (dryvist/.github/renovate.json extends the
   JacobPEvans preset chain via redirect; canonical owner is dryvist).

3. **Renovate: split internal-flakes off external groups.** dryvist
   and JacobPEvans-personal flakes merge immediately — never wait for
   release age on first-party repos. Critical-infrastructure group
   keeps its 2-day delay for nixpkgs-25.11-darwin Hydra cache lag;
   ai-tools-external keeps daily updates for anthropics/obra. New
   internal-flakes rule sits LAST so its minimumReleaseAge=0 +
   automerge=true override the prior groups for dryvist/**,
   JacobPEvans/**, JacobPEvans-personal/** matches.

Also drops the Claude config block (playwright disable + 10 MCP
server disables + splunk MCP definition) from
hosts/macbook-m4/home.nix. These moved to nix-ai/modules/claude-config.nix
in dryvist/nix-ai#853 — Claude config doesn't belong in nix-darwin.
home.nix shrinks 12406 → 10886 bytes, below the 12KB file-size CI limit.

nix-ai input bumped to 110a4a6 (PR #853 merge SHA) so the new MCP +
playwright defaults take effect.

Refs: dryvist/nix-ai#853

Assisted-by: Claude <noreply@anthropic.com>
JacobPEvans-personal added a commit to dryvist/nix-darwin that referenced this pull request May 30, 2026
* feat(claude): adopt nix-claude-code module

Add dryvist/nix-claude-code as a direct flake input and route
nix-ai's nix-claude-code instance through it via `follows`, so a
single Renovate PR cascades through both consumers.

Changes:
- flake.nix: add nix-claude-code input with follows for nixpkgs,
  home-manager, ai-assistant-instructions, claude-code-plugins,
  jacobpevans-cc-plugins; channel nix-ai.inputs.nix-claude-code
  through it
- flake.lock: pin nix-claude-code at PR2's merge SHA
  (5276fb566c8cf8078f808d8dbd5923bcd0e00c1a)
- lib/user-config.nix: drop unused `ai.claudeSchemaUrl` (the schema
  URL is now embedded in nix-claude-code's lib/to-settings-json.nix)
- renovate.json5: add dryvist/nix-claude-code to the ai-tools group
  with minimumReleaseAge=1 day so nix-ai leads, nix-darwin trails

Deferred to follow-up:
- The 10-server `mcpServers = {...}` block + splunk config in
  `hosts/macbook-m4/home.nix:62-95` is user-host opinion (which MCP
  servers this Mac wants disabled). Plan suggested moving it to
  nix-ai's MCP catalog, but that's a separate cross-repo change and
  the existing block continues to work through nix-claude-code's
  `mkRenamedOptionModule` shims.

Verified end-to-end: `darwin-rebuild build --flake .#jevans-mbp
--override-input nix-ai <PR3 branch>` succeeds with this flake.nix
+ PR3 merged content. Once PR3 merges, this branch's flake.lock
will also need a nix-ai bump (manual step before merge).

Refs: dryvist/nix-claude-code#26, dryvist/nix-ai#838, dryvist/nix-ai#851

Assisted-by: Claude <noreply@anthropic.com>

* chore(flake): bump nix-ai to PR3 merge

nix-ai PR #851 (refactor/delegate-claude-to-nix-claude-code) merged at
20fbd459106a. Bumping the lock to that SHA picks up the delegation so
nix-darwin now consumes programs.claude.* via nix-claude-code through
nix-ai's `imports`.

Resolves the prior `inputs.nix-claude-code.follows` warning on
non-existent input — PR3 added the input to nix-ai.

Refs: dryvist/nix-ai#851

Assisted-by: Claude <noreply@anthropic.com>

* fix(user-config): restore ai.claudeSchemaUrl

nix-ai/modules/default.nix:106 still references userConfig.ai.claudeSchemaUrl
in its validateClaudeSettings activation hook. The plan called for deleting
this on both sides, but PR3 didn't drop the nix-ai consumer — so deleting
just the nix-darwin definition breaks CI's Nix Build with "attribute 'ai'
missing".

Restoring the attribute. Delete in a follow-up after nix-ai stops
consuming it (move to inline constant or read from nix-claude-code.lib).

Assisted-by: Claude <noreply@anthropic.com>

* chore(deps): align flake.nix + renovate owners with current GitHub state

Per the JacobPEvans → dryvist org migration, four nix-darwin flake
inputs and their renovate matchPackageNames now use the canonical
dryvist owner. The previous JacobPEvans/* URLs worked via GitHub's
repo-rename redirect, but the literal owner string is what Renovate
matches — keeping flake and renovate in lockstep avoids mismatch.

Changes:
- flake.nix: `github:JacobPEvans/{ai-assistant-instructions,
  claude-code-plugins,nix-ai,nix-home}` → `github:dryvist/...`
- renovate.json5: matchPackageNames updated to match
- renovate.json5: extends `local>JacobPEvans/.github:renovate-presets`
  → `local>JacobPEvans-personal/.github:renovate-presets`
  (the .github repo stayed with the renamed personal account, not the
  dryvist org; verified `gh api repos/dryvist/.github/contents/renovate-presets.json` returns 404)
- renovate.json5: `@JacobPEvans` assignees/reviewers
  → `@JacobPEvans-personal` (bare JacobPEvans login is now 404; mentions
  don't follow GitHub's repo-rename redirect)
- flake.lock: re-resolved against dryvist URLs; nix-ai/nix-home SHAs
  unchanged (same commit, different owner), ai-assistant-instructions
  and claude-code-plugins picked up fresher SHAs

Assisted-by: Claude <noreply@anthropic.com>

* feat(user-config): drop ai.claudeSchemaUrl (single source in nix-claude-code)

The schemastore URL is a hard-coded constant that will never change;
the canonical home is dryvist/nix-claude-code's lib/to-settings-json.nix
where it's embedded as the generated settings.json's "$schema" field.

nix-ai stopped consuming `userConfig.ai.claudeSchemaUrl` in
dryvist/nix-ai#852 (merged), so deleting this
nix-darwin definition is now safe — the validateClaudeSettings
activation hook in nix-ai inlines the same constant.

Also bumps nix-ai input to the PR #852 merge SHA so the eval finds the
inlined URL constant.

Refs: dryvist/nix-ai#852

Assisted-by: Claude <noreply@anthropic.com>

* refactor(flake): keep nix-darwin AI-free; consolidate renovate policy

Three corrections to the migration's adoption shape, from review feedback:

1. **Drop nix-claude-code top-level input.** nix-darwin should not pull
   AI flakes directly — nix-ai is the only AI flake nix-darwin imports.
   nix-claude-code now flows transitively via nix-ai's input chain
   (dryvist/nix-ai#851 made nix-ai consume nix-claude-code), so this
   was strictly a leakage of Claude config concerns into nix-darwin's
   top-level. Removes the unhelpful "marketplace edge-pins cascade"
   comment too — that was the wrong design.

2. **Renovate: use dryvist as canonical org.** Switch
   `local>JacobPEvans-personal/.github:renovate-presets` →
   `local>dryvist/.github` (dryvist/.github/renovate.json extends the
   JacobPEvans preset chain via redirect; canonical owner is dryvist).

3. **Renovate: split internal-flakes off external groups.** dryvist
   and JacobPEvans-personal flakes merge immediately — never wait for
   release age on first-party repos. Critical-infrastructure group
   keeps its 2-day delay for nixpkgs-25.11-darwin Hydra cache lag;
   ai-tools-external keeps daily updates for anthropics/obra. New
   internal-flakes rule sits LAST so its minimumReleaseAge=0 +
   automerge=true override the prior groups for dryvist/**,
   JacobPEvans/**, JacobPEvans-personal/** matches.

Also drops the Claude config block (playwright disable + 10 MCP
server disables + splunk MCP definition) from
hosts/macbook-m4/home.nix. These moved to nix-ai/modules/claude-config.nix
in dryvist/nix-ai#853 — Claude config doesn't belong in nix-darwin.
home.nix shrinks 12406 → 10886 bytes, below the 12KB file-size CI limit.

nix-ai input bumped to 110a4a6 (PR #853 merge SHA) so the new MCP +
playwright defaults take effect.

Refs: dryvist/nix-ai#853

Assisted-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant