feat(config): scope-split settings precedence; project config.toml support#608
Conversation
`aube config set <known-key>` was deleting matching aliases from `~/.npmrc` so the new value in `~/.config/aube/config.toml` wouldn't be shadowed by the lower-precedence (then) `.npmrc`. That silently broke `script-shell` and any other setting shared with npm/pnpm/yarn. Flip the default file precedence to `aubeConfig > npmrc > workspaceYaml` so aube's own config wins, then drop the stale-alias cleanup from `config set` and the symmetric cleanup from `config delete`. Per-setting `precedence` overrides in `settings.toml` (e.g. `minimumReleaseAge`) continue to apply. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR establishes a principled, scope-aware settings precedence for aube, splitting the previously merged
Confidence Score: 5/5Safe to merge — the core precedence logic is correct, exhaustively tested, and the refactor is mechanically consistent across all call sites. The precedence ordering is verified at three independent layers: the code-generator in No files require special attention. Important Files Changed
Reviews (5): Last reviewed commit: "fix(settings): rank workspace yaml above..." | Re-trigger Greptile |
Settings precedence is split by scope so project-scope entries (project
`.npmrc` and the new project `<cwd>/.config/aube/config.toml`) outrank
user-scope entries, and within a scope aube's own config file outranks
`.npmrc`. The full default chain is:
cli > env
> project_aube_config (<cwd>/.config/aube/config.toml)
> project_npmrc (<cwd>/.npmrc + npmrcAuthFile)
> user_aube_config (~/.config/aube/config.toml)
> user_npmrc (~/.npmrc + pnpm auth.ini)
> workspace_yaml
`aube config set/delete --location project` for aube-known keys now
writes to `<cwd>/.config/aube/config.toml` instead of project `.npmrc`,
mirroring the user-scope behavior introduced previously. The shared
`.npmrc` is left alone so it can stay coordinated with npm/pnpm/yarn.
`ResolveCtx` is split into `{project,user}_{aube_config,npmrc}` slices
and a `FileSources::load(cwd)` helper in `commands/mod.rs` consolidates
the loading boilerplate. Per-setting `precedence` overrides in
`settings.toml` keep working: bare `npmrc` / `aubeConfig` names expand
to their project+user pair (project first).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A user upgrading from a pre-#517 aube has aube-owned keys still living in `~/.npmrc` (where old aube used to write them). `aube config delete <key>` would then fail with a bare "not set in config.toml", with no hint about the active value in `~/.npmrc`. aube still doesn't modify `.npmrc` for aube-known keys — it's shared with npm/pnpm/yarn, which is the whole point of #601. But the error now surfaces the stale entry's location and tells the user to edit it manually (or override it from `config.toml` via `aube config set`). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a project already has `pnpm-workspace.yaml` or `aube-workspace.yaml`, `aube config set/delete --location project` now writes the aube-known setting into that existing file instead of creating a separate `<cwd>/.config/aube/config.toml`. Keeps the per-project config story to a single file when one already exists. Format and surrounding comments are preserved via `aube_manifest::workspace::edit_workspace_yaml`. Settings without a `workspace_yaml` source (e.g. `scriptShell`) still fall back to project `config.toml` — there's no point writing a value the resolver wouldn't read back. User-scope writes are unchanged and keep landing in `~/.config/aube/config.toml`. `aube config get/list` now also surfaces flat-scalar entries from the workspace yaml so a value just written there round-trips through the display commands. Nested mappings (catalogs, allowBuilds, …) stay hidden — they don't fit the simple `(key, raw)` view. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two coupled fixes from review feedback on #608: `aube config delete --location project` used to short-circuit after removing the key from the workspace yaml, even when the same key also lived in project `config.toml`. The config.toml copy then silently became the active value again — the opposite of what the user asked for. Delete now sweeps both files (and errors when neither held the key). `aube config set --location project` only routes to the workspace yaml when no project `config.toml` exists. Once `config.toml` has been adopted, all project-scope writes stay there — otherwise a yaml write would be silently shadowed by the higher-precedence config.toml entry on read. This matches the user's "if it exists and no config exists" intent. Also splits a fused docstring in aube-registry: the new `load_npmrc_entries_split` doc block was directly adjacent to the existing `load_npmrc_entries` doc, so rustdoc attached the merged text to the new function and the old function lost its doc entirely. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 062f89c. Configure here.
`workspace_yaml` (`pnpm-workspace.yaml` / `aube-workspace.yaml`) lives at the project root, so by the scope-locality principle it must outrank both `~/.npmrc` and `~/.config/aube/config.toml`. The previous default left it at the bottom of the file chain, which meant a project write routed to the workspace yaml could be silently shadowed by any user-scope setting on the same key — directly contradicting the PR's own "project beats user" guarantee. New default file precedence, high-to-low: project_aube_config > project_npmrc > workspace_yaml > user_aube_config > user_npmrc Per-setting `precedence` overrides in `settings.toml` are unchanged in effect — `minimumReleaseAge` still pulls workspace_yaml first via its own override; the only difference is where unspecified sources fall in the append-missing tail. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Summary
Fixes #601. Three coupled changes that establish a principled, locality-preserving settings precedence:
aube config set/deleteno longer edits.npmrc. For aube-known keys, writes land in~/.config/aube/config.toml(user) or the new<cwd>/.config/aube/config.toml(project). The shared.npmrcis preserved for npm/pnpm/yarn.<cwd>/.config/aube/config.tomlis a new project-scope source. Mirrors the XDG layout used at user-scope. It's an alternative to committing aube-specific settings into a project.npmrcthat other package managers also read.Settings precedence is split by scope. The full default file-source chain, high-to-low:
Two principles: scope locality (project beats user) and aube authority within a scope (aube's config beats
.npmrc).Implementation
ResolveCtxnow exposes{project,user}_{aube_config,npmrc}slices instead of mergednpmrc/aube_configfields.aube_registry::config::load_npmrc_entries_split(cwd)returns user+project halves; reuses the existing tagged loader internally so no duplicate parsing.commands::FileSources::load(cwd)helper consolidates the four-source loading boilerplate that 18 call sites used to inline.precedenceoverrides insettings.tomlkeep working: barenpmrc/aubeConfignames expand to their project+user pair (project first); scope-qualifiedprojectNpmrc/userNpmrc/projectAubeConfig/userAubeConfigare available for fine-grained control.Test plan
cargo buildcargo clippy --all-targets -- -D warningscargo fmt --checkcargo test --workspace— 1507 passed, 0 failedmise run test:bats test/config.bats— 38/38 (4 new tests covering project config.toml + scope locality)mise run test:bats test/minimum_release_age.bats— 5/5 (per-setting precedence override still wired)mise run test:bats test/settings.bats— 18/18values.rs:user_aube_config_wins_over_user_npmrc_by_default,project_npmrc_wins_over_user_aube_config_by_default,project_aube_config_wins_over_project_npmrc_by_defaultconfig set --location project writes aube-owned keys to project config.toml,config set --location project writes unknown keys to ./.npmrc,config get prefers project config.toml over project .npmrc,config get prefers project npmrc over user config.tomlThis PR was generated by Claude.
Note
Medium Risk
Changes settings-resolution precedence across the CLI and redirects
config set/deletewrites for known keys away from.npmrc, which can affect effective configuration in existing projects/users.Overview
Reworks settings resolution to split file-based sources by scope (project vs user) and apply a new default precedence:
project config.toml> project.npmrc> workspace YAML > userconfig.toml> user.npmrc(still undercli > env).Adds project-scope aube config at
<cwd>/.config/aube/config.toml, updates the settings accessor generator to understand scope-qualified precedence names (withnpmrc/aubeConfigaliases expanding to project+user), and introducesload_npmrc_entries_splitplus aFileSourceshelper to wire the newResolveCtxthrough many commands.Updates
aube config get/list/set/deletebehavior: known settings now write/delete inconfig.toml(or workspace YAML for supported keys when no project config exists) and no longer modify.npmrc, with improved errors for stale.npmrcentries; docs and bats/unit tests are updated accordingly.Reviewed by Cursor Bugbot for commit 09b8604. Bugbot is set up for automated code reviews on this repo. Configure here.