feat(claude): expose programs.claude.settings.autoMode configuration#838
Merged
Conversation
…block Setting permissions.defaultMode = "auto" turns on Anthropic's auto-mode classifier. Out of the box it trusts only the working directory and the active repo's configured remotes — cross-repo, cross-org, cloud, and homelab operations get blocked as potential exfiltration. The fix is populating autoMode.environment with prose describing the user's trusted infrastructure. Reference: https://code.claude.com/docs/en/auto-mode-config Add typed sub-options under programs.claude.settings.autoMode: * environment — trusted-infrastructure entries (highest leverage) * allow — exceptions to soft_deny rules * soft_deny — destructive actions user intent can clear * hard_deny — unconditional blocks Each defaults to [ "$defaults" ] so the classifier inherits Anthropic's built-in entries. Consumers extend by adding entries before/after "$defaults" or replace entirely by omitting "$defaults". modules/claude/settings.nix filters sub-fields exactly equal to [ "$defaults" ] at write time — semantically a no-op since the classifier uses defaults when a field is unset — so the generated settings.json stays minimal. Consumers (nix-darwin host configs, etc.) populate programs.claude.settings.autoMode.environment with their homelab / org / cloud trust context. The classifier then stops blocking routine operations against that infrastructure. Assisted-by: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces autoMode configuration options for the Claude module, enabling users to configure trusted infrastructure, allowlists, and deny rules for the auto-mode classifier. It also includes logic to keep the generated settings.json minimal by filtering out fields that only contain default values. Feedback was provided regarding the formatting of documentation strings to prevent inconsistent rendering of hyphenated words across line breaks.
Member
Author
|
@claude review this PR |
Member
Author
|
/gemini review |
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Address PR review feedback (Gemini): "natural-language" was split mid-word in the autoMode.environment description. Compound hyphenation across lines renders inconsistently in generated docs (e.g. man pages, HTML). Rewrap so the compound stays whole. Assisted-by: Claude <noreply@anthropic.com>
JacobPEvans-personal
added a commit
to dryvist/nix-darwin
that referenced
this pull request
May 25, 2026
Rebase against main regenerated flake.lock and bumped nix-ai to its post-PR-838 main, which removed the autoMode option that this PR depends on. Restore the pin to fa9680a (HEAD of JacobPEvans/nix-ai feat/automode-options branch) so this PR is buildable until dryvist/nix-ai#838 merges. Dependency: blocks on dryvist/nix-ai#838 merging first. Assisted-by: Claude <noreply@anthropic.com>
4 tasks
JacobPEvans-personal
added a commit
to dryvist/nix-claude-code
that referenced
this pull request
May 30, 2026
Consolidate Claude Code ownership in nix-claude-code so this repo becomes
the canonical home for the full `programs.claude.*` home-manager module.
Previously the option set lived in nix-ai (which also installs Gemini,
Codex, and Copilot); separation of concerns argues for the
Claude-specific schema to live here.
What's new in this PR:
- Full option set: `apiKeyHelper`, `teammateMode`, `autoUpdatesChannel`,
`showTurnDuration`, `remoteControlAtStartup`, `trustedProjectDirs`,
`model`, `effortLevel`, `attribution`, `plugins.{marketplaces,enabled,
allowRuntimeInstall}`, `commands/agents/skills/rules.{fromFlakeInputs,
local,…}`, the typed per-event `hooks.*`, `mcpServers`,
`settings.{alwaysThinkingEnabled,cleanupPeriodDays,
skillListingBudgetFraction,skillOverrides,permissions,
additionalDirectories,env,schemaUrl,sandbox}`, `features.*`,
`orphanCleanup.extraComponentDirs`, `latest.launchdLabel`,
`statusline.script`.
- `lib.ci.claudeSettingsJson` shim for byte-equivalence tests.
- `lib.claudeRegistry` (toClaudeMarketplaceFormat / mkKnownMarketplaces).
- `lib.marketplaceCatalog` (the canonical marketplace list).
- `lib.marketplaceOverrides` (synthetic marketplace derivations:
browser-use, fabric, cribl-pack-validator, jacobpevans).
- Vendored hook scripts (`last-output.sh`, `marketplace-refresh.sh`).
- Activation scripts in `modules/scripts/` (claude-json-merge,
cleanup-*, verify-cache-integrity, merge-json-settings,
claude-latest-install).
- API-key helper (`bws_helper.py` + `get-api-key.py`) wired as an
opt-in shell wrapper with its Python deps in `runtimeInputs`.
- Synthetic `programs-claude-eval` flake check that exercises a
minimal home-manager activation with `programs.claude.enable = true`.
Schema renames (`mkRenamedOptionModule` wired for back-compat):
- `programs.claude.enabledPlugins` → `programs.claude.plugins.enabled`
- `programs.claude.marketplaces` → `programs.claude.plugins.marketplaces`
- `programs.claude.statusLine.enable` → `programs.claude.statusline.enable`
- `programs.claude.statusLine.script` → `programs.claude.statusline.script`
- `programs.claude.hooks.extraHooks` → `programs.claude.settings.hooks`
`hooks.captureSessionOutput` and `hooks.refreshMarketplaces` toggles are
preserved and now auto-wire to the typed `postToolUse` / `sessionStart`
slots via `lib.mkDefault`. `programs.claude.defaultMode` remains the
canonical source of truth; `settings.permissions.defaultMode` wins only
when explicitly set (conflict #4).
`orphan-cleanup.nix` no longer hard-codes `~/.gemini/commands`; consumers
opt into extra cleanup dirs via `programs.claude.orphanCleanup.extraComponentDirs`.
Dependencies and follow-ups:
- DEPENDS ON: dryvist/nix-ai#838 (typed autoMode.environment) landing
upstream. nix-claude-code already has `autoMode` on main, so no
additional copy needed in this PR.
- FOLLOW-UP: nix-ai PR3 will delegate `programs.claude.*` to this module
via imports.
- FOLLOW-UP: nix-darwin PR4 adopts the input and closes
dryvist/nix-darwin#1141.
Refs: dryvist/nix-ai#838, dryvist/nix-darwin#1141
Assisted-by: Claude <noreply@anthropic.com>
This was referenced May 30, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
permissions.defaultMode = "auto"(already the default here) turns on Anthropic's auto-mode classifier. Out of the box the classifier trusts only the working directory and the active repo's configured remotes; cross-repo, cross-org, cloud, and homelab operations get blocked. The cure is configuringautoMode.{environment,allow,soft_deny,hard_deny}at top-level in settings.json. Reference: https://code.claude.com/docs/en/auto-mode-config.Add typed sub-options under
programs.claude.settings.autoMode:environment— trusted-infrastructure prose (highest leverage)allow— exceptions tosoft_denyrulessoft_deny— destructive actions user intent can clearhard_deny— unconditional blocksEach defaults to
[ "$defaults" ](inherit built-ins). Consumers extend by adding prose entries;$defaultsis spliced in at its position.modules/claude/settings.nixfilters sub-fields exactly equal to[ "$defaults" ]at write time — semantically a no-op since the classifier already uses defaults when a field is unset — so the generated settings.json stays minimal.First consumer
JacobPEvans/nix-darwin#feat/automode-environment populates
programs.claude.settings.autoMode.environmentfor the macbook-m4 host with the user's homelab trust context (GitHub orgs, AWS/Proxmox, MLX server, Doppler/Keychain/SOPS/Bitwarden, OTEL→Cribl→Splunk, self-hosted RunsOn runners, etc.).Test plan
nix flake checkpassesnix fmtno diffjq '.autoMode.environment' ~/.claude/settings.jsonreturns populated list;claude auto-mode configshows entries;claude auto-mode critiqueAI review surfaces ambiguity🤖 Generated with Claude Code