From 5d744886e424962ed34e9af078b58fd48ad3a520 Mon Sep 17 00:00:00 2001 From: "melodic-automation-lanes[bot]" <337595936+melodic-automation-lanes[bot]@users.noreply.github.com> Date: Wed, 4 Nov 2026 18:59:19 +0000 Subject: [PATCH 1/4] Resolve issue #13191 Lane-Activity: work-resolve-issue/resolve-issue --- ...ssue-issue-13191-41889151702-1-4462e5d9.md | 10 ++++++ ...ssue-issue-13191-41889151702-1-9d2b4dc9.md | 10 ++++++ ...ssue-issue-13191-41889151702-1-5b3e7136.md | 10 ++++++ ...ssue-issue-13191-41889151702-1-e2d96514.md | 10 ++++++ ...ssue-issue-13191-41889151702-1-d3d8b935.md | 9 +++++ ...ssue-issue-13191-41889151702-1-ff586768.md | 10 ++++++ ...ssue-issue-13191-41889151702-1-aeca15ab.md | 11 ++++++ ...ssue-issue-13191-41889151702-1-0a4305b0.md | 11 ++++++ docs/conventions/review-digest.md | 2 +- .../samples/no-shell-write-config.json | 2 +- .../samples/no-write-config.json | 2 +- .../samples/no-shell-write-config.json | 2 +- .../samples/no-write-config.json | 2 +- .../samples/no-shell-write-config.json | 2 +- .../samples/no-write-config.json | 2 +- plugins/attribution/retirements.yaml | 4 +-- .../skills/audit/scripts/check-stamps.sh | 2 +- .../skills/audit/scripts/check-stamps.test.sh | 2 +- .../attribution/skills/audit/scripts/lib.sh | 24 +++++++------ .../skills/audit/scripts/lib.test.sh | 12 +++---- .../skills/audit/scripts/list-corpus.sh | 2 +- .../skills/audit/scripts/list-corpus.test.sh | 8 ++--- .../skills/audit/scripts/score-golden.sh | 2 +- .../skills/audit/scripts/sweep-ledger.test.sh | 3 +- plugins/attribution/skills/setup/SKILL.md | 24 +++++++------ .../attribution/skills/setup/evals/evals.json | 16 ++++----- plugins/bugs/README.md | 8 ++--- plugins/bugs/reference/config.md | 8 ++--- plugins/bugs/scripts/concat-gotchas.sh | 6 ++-- plugins/bugs/scripts/concat-gotchas.test.sh | 8 ++--- plugins/bugs/skills/scan/SKILL.md | 2 +- plugins/bugs/skills/setup/SKILL.md | 10 +++--- plugins/bugs/skills/setup/evals/evals.json | 6 ++-- plugins/bugs/skills/write/SKILL.md | 2 +- plugins/code-metrics/README.md | 2 +- plugins/code-metrics/reference/config.md | 4 +-- .../scripts/fixtures/config/local.yaml | 2 +- .../code-metrics/scripts/resolve-config.py | 30 ++++++++-------- .../skills/audit-coverage/SKILL.md | 2 +- .../skills/audit-duplication/SKILL.md | 2 +- .../skills/audit/actions/complexity.md | 2 +- .../code-metrics/skills/audit/actions/size.md | 2 +- .../skills/audit/actions/type-debt.md | 2 +- .../skills/principles/reference/thresholds.md | 2 +- plugins/code-metrics/skills/setup/SKILL.md | 6 ++-- .../skills/setup/scripts/setup-check.sh | 4 +-- .../skills/setup/scripts/setup-check.test.sh | 4 +-- plugins/codebase-health/README.md | 4 +-- plugins/codebase-health/skills/audit/SKILL.md | 4 +-- .../skills/audit/evals/evals.json | 2 +- .../skills/audit/reference/audit-checklist.md | 2 +- plugins/codebase-health/skills/setup/SKILL.md | 20 +++++------ .../skills/setup/evals/evals.json | 4 +-- .../skills/setup/templates/config-template.md | 4 +-- plugins/discipline/reference/config.md | 2 +- plugins/discipline/skills/setup/SKILL.md | 2 +- plugins/discipline/skills/sweep-all/SKILL.md | 2 +- plugins/improvement/README.md | 2 +- plugins/improvement/reference/config.md | 4 +-- plugins/improvement/skills/find/SKILL.md | 2 +- .../skills/find/context/hotspots.md | 2 +- plugins/improvement/skills/setup/SKILL.md | 20 +++++------ .../improvement/skills/setup/evals/evals.json | 12 +++---- plugins/multi-agent/README.md | 4 +-- plugins/multi-agent/probes/route.json | 2 +- plugins/multi-agent/reference/config.md | 8 ++--- plugins/multi-agent/scripts/resolve-roles.sh | 25 +++++++------- .../multi-agent/scripts/resolve-roles.test.sh | 14 ++++---- plugins/multi-agent/skills/route/SKILL.md | 4 +-- .../multi-agent/skills/route/evals/evals.json | 4 +-- plugins/multi-agent/skills/setup/SKILL.md | 2 +- .../multi-agent/skills/setup/evals/evals.json | 4 +-- .../multi-agent/skills/setup/scripts/setup.sh | 10 +++--- .../skills/setup/scripts/setup.test.sh | 6 ++-- plugins/review/agents/ecosystem-specialist.md | 4 +-- plugins/review/reference/config.md | 2 +- .../explain-change/scripts/digest-policy.mjs | 15 ++++---- plugins/review/skills/setup/SKILL.md | 6 ++-- plugins/review/skills/setup/evals/evals.json | 2 +- plugins/review/tests/explain-change.test.mjs | 34 +++++++++---------- scripts/test_check_vocabulary.py | 1 + scripts/vocabulary-senses.json | 1 + 82 files changed, 317 insertions(+), 227 deletions(-) create mode 100644 .changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md create mode 100644 .changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md create mode 100644 .changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md create mode 100644 .changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md create mode 100644 .changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md create mode 100644 .changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md create mode 100644 .changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md create mode 100644 .changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md diff --git a/.changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md b/.changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md new file mode 100644 index 00000000000..48e2963275c --- /dev/null +++ b/.changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md @@ -0,0 +1,10 @@ +--- +bump: patch +--- + +### Changed + +- The setup skill, its evals, `retirements.yaml` and the audit scripts' comments and test names now + call the config cascade's personal layer, `/attribution.local.yaml`, the personal override + ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). Behavior is + unchanged. diff --git a/.changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md b/.changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md new file mode 100644 index 00000000000..b8178e26528 --- /dev/null +++ b/.changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md @@ -0,0 +1,10 @@ +--- +bump: patch +--- + +### Changed + +- The config reference, README and the `scan`, `write` and `setup` text now call the config + cascade's personal layer, `.claude/bugs.local.md`, the personal override, and the consumer + gotchas block `concat-gotchas.sh` prints heads that layer `#### personal override (...)` + ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). diff --git a/.changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md b/.changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md new file mode 100644 index 00000000000..9de9ac399cf --- /dev/null +++ b/.changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md @@ -0,0 +1,10 @@ +--- +bump: patch +--- + +### Changed + +- The config reference, README, skill text and `setup check` rows now call the config cascade's + personal layer, `.claude/code-metrics.local.yaml`, the personal override + ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). The resolver's + layer label stays `local`, so its output is unchanged. diff --git a/.changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md b/.changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md new file mode 100644 index 00000000000..792ad68ff0a --- /dev/null +++ b/.changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md @@ -0,0 +1,10 @@ +--- +bump: patch +--- + +### Changed + +- The README, the config template and the `audit` and `setup` text and evals now call the config + cascade's personal layer, `.claude/codebase-health.local.md`, the personal override + ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). Behavior is + unchanged. diff --git a/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md b/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md new file mode 100644 index 00000000000..ed20f7bfb26 --- /dev/null +++ b/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md @@ -0,0 +1,9 @@ +--- +bump: patch +--- + +### Changed + +- The config reference and `setup` now call the config cascade's personal layer the personal + override ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). The + `sweep-all` batch overlay, the `batch_*` options, keeps its name. Behavior is unchanged. diff --git a/.changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md b/.changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md new file mode 100644 index 00000000000..37cd6351ae8 --- /dev/null +++ b/.changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md @@ -0,0 +1,10 @@ +--- +bump: patch +--- + +### Changed + +- The config reference, README, `find` and `setup` text and the setup evals now call the config + cascade's personal layer, `.claude/improvement.local.md`, the personal override + ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). Behavior is + unchanged. diff --git a/.changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md b/.changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md new file mode 100644 index 00000000000..728ff4f9afa --- /dev/null +++ b/.changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md @@ -0,0 +1,11 @@ +--- +bump: minor +--- + +### Changed + +- The config cascade's personal layer, `.claude/multi-agent.local.yaml`, is now called the personal + override ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). + `resolve-roles.sh` names it `personal-override` in each role's `source`, in `layers` and in + `notes`, and `/multi-agent:setup check` prints its gitignore row as `personal-override`. A + caller that matched the old label must match the new one. diff --git a/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md b/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md new file mode 100644 index 00000000000..e8998f43e7d --- /dev/null +++ b/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md @@ -0,0 +1,11 @@ +--- +bump: minor +--- + +### Changed + +- The config cascade's personal layer is now called the personal override + ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). + `/review:explain-change`'s digest policy labels a value from `.claude/review-digest.local.json` + `personal override ` in its `source` and warnings, and `setup`, the config reference and + the `ecosystem-specialist` agent use the new name. diff --git a/docs/conventions/review-digest.md b/docs/conventions/review-digest.md index 3b6c2a5c199..8c2d07468e3 100644 --- a/docs/conventions/review-digest.md +++ b/docs/conventions/review-digest.md @@ -58,7 +58,7 @@ an earlier one key by key: 3. personal override `.claude/review-digest.local.json` The result names the layer that supplied each value (`team :`, `user-global `, -`overlay `, or `default`). Quote glob values in the YAML file (`"**/hooks/**"`), since a plain +`personal override `, or `default`). Quote glob values in the YAML file (`"**/hooks/**"`), since a plain `*` opens an alias. The team layer, and the rendered-views team file, are read from the pull request's base commit diff --git a/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-shell-write-config.json b/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-shell-write-config.json index 4e844ae237e..85b92c5424b 100644 --- a/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-shell-write-config.json +++ b/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-shell-write-config.json @@ -100,7 +100,7 @@ } } ], - "why": "tee into the overlay" + "why": "tee into the personal override" }, { "answer": [ diff --git a/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-write-config.json b/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-write-config.json index d6c0495afdb..702a8f34d6f 100644 --- a/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-write-config.json +++ b/plugins/attribution/evals/setup-apply-rejects-misplaced-key/samples/no-write-config.json @@ -40,7 +40,7 @@ } } ], - "why": "overlay" + "why": "personal override" }, { "answer": [ diff --git a/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-shell-write-config.json b/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-shell-write-config.json index 4e844ae237e..85b92c5424b 100644 --- a/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-shell-write-config.json +++ b/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-shell-write-config.json @@ -100,7 +100,7 @@ } } ], - "why": "tee into the overlay" + "why": "tee into the personal override" }, { "answer": [ diff --git a/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-write-config.json b/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-write-config.json index d6c0495afdb..702a8f34d6f 100644 --- a/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-write-config.json +++ b/plugins/attribution/evals/setup-check-reports-retired-config/samples/no-write-config.json @@ -40,7 +40,7 @@ } } ], - "why": "overlay" + "why": "personal override" }, { "answer": [ diff --git a/plugins/attribution/evals/setup-check-writes-nothing/samples/no-shell-write-config.json b/plugins/attribution/evals/setup-check-writes-nothing/samples/no-shell-write-config.json index 4e844ae237e..85b92c5424b 100644 --- a/plugins/attribution/evals/setup-check-writes-nothing/samples/no-shell-write-config.json +++ b/plugins/attribution/evals/setup-check-writes-nothing/samples/no-shell-write-config.json @@ -100,7 +100,7 @@ } } ], - "why": "tee into the overlay" + "why": "tee into the personal override" }, { "answer": [ diff --git a/plugins/attribution/evals/setup-check-writes-nothing/samples/no-write-config.json b/plugins/attribution/evals/setup-check-writes-nothing/samples/no-write-config.json index d6c0495afdb..702a8f34d6f 100644 --- a/plugins/attribution/evals/setup-check-writes-nothing/samples/no-write-config.json +++ b/plugins/attribution/evals/setup-check-writes-nothing/samples/no-write-config.json @@ -40,7 +40,7 @@ } } ], - "why": "overlay" + "why": "personal override" }, { "answer": [ diff --git a/plugins/attribution/retirements.yaml b/plugins/attribution/retirements.yaml index 26f67137b17..7147fa3cf0d 100644 --- a/plugins/attribution/retirements.yaml +++ b/plugins/attribution/retirements.yaml @@ -21,5 +21,5 @@ kind: file path: .claude/provenance.local.json content_match: '"(excluded_paths|budgets|separation|stamp_expiry_days|trigger_less_stamp_check|judge_samples|gates|accuracy)"' action: migrate -successor: "the local overlay is now /attribution.local.yaml (default docs/conventions/attribution.local.yaml) with the same keys: carry every key into it unchanged (when the current overlay, the YAML or else its .claude/ JSON fallback, already sets a key, keep its value, so the current file wins), have the operator confirm the result, then clean" -note: "retired local overlay name; the provenance plugin became attribution and never reads this file" +successor: "the personal override is now /attribution.local.yaml (default docs/conventions/attribution.local.yaml) with the same keys: carry every key into it unchanged (when the current personal override, the YAML or else its .claude/ JSON fallback, already sets a key, keep its value, so the current file wins), have the operator confirm the result, then clean" +note: "retired personal override name; the provenance plugin became attribution and never reads this file" diff --git a/plugins/attribution/skills/audit/scripts/check-stamps.sh b/plugins/attribution/skills/audit/scripts/check-stamps.sh index 7f81e89b437..499d8c4c6bc 100755 --- a/plugins/attribution/skills/audit/scripts/check-stamps.sh +++ b/plugins/attribution/skills/audit/scripts/check-stamps.sh @@ -129,7 +129,7 @@ if [[ -n "$AS_OF" && ! "$AS_OF" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then fi [[ -n "$AS_OF" ]] || AS_OF="$(date +%Y-%m-%d)" -# --- Config cascade (user-global -> team -> overlay; YAML, legacy JSON) ----------- +# --- Config cascade (user-global -> team -> personal override; YAML, legacy JSON) -- REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" CONFIG_ROOT="${CLAUDE_PROJECT_DIR:-$REPO_ROOT}" diff --git a/plugins/attribution/skills/audit/scripts/check-stamps.test.sh b/plugins/attribution/skills/audit/scripts/check-stamps.test.sh index abdf950d576..6f241d21b6d 100755 --- a/plugins/attribution/skills/audit/scripts/check-stamps.test.sh +++ b/plugins/attribution/skills/audit/scripts/check-stamps.test.sh @@ -476,7 +476,7 @@ assert_contains "--show-config attributes a YAML value to its layer" \ "$OUT" "stamp_expiry_days=60 (from $CONV/attribution.yaml)" printf '%s\n' 'trigger_less_stamp_check: true' >"$CONV/attribution.local.yaml" OUT="$(run --show-config 2>&1)" -assert_contains "the YAML overlay refines the YAML team layer" \ +assert_contains "the YAML personal override refines the YAML team layer" \ "$OUT" "trigger_less_stamp_check=true (from $CONV/attribution.local.yaml)" rm -rf "$CLAUDE_PROJECT_DIR/docs" rm -f "$CLAUDE_PROJECT_DIR/.claude/attribution.json" diff --git a/plugins/attribution/skills/audit/scripts/lib.sh b/plugins/attribution/skills/audit/scripts/lib.sh index e14c77515c2..42df81a7d83 100755 --- a/plugins/attribution/skills/audit/scripts/lib.sh +++ b/plugins/attribution/skills/audit/scripts/lib.sh @@ -32,14 +32,16 @@ json_str() { _CFG_LIB="${BASH_SOURCE[0]%/*}/../../../lib" # cfg_layers_init : fill CFG_LAYERS with the config cascade in -# refinement order, user-global then team then overlay, skipping a layer that is -# not present. The team layer is /attribution.yaml and the overlay -# /attribution.local.yaml (ADR 0075), being the bound convention -# home, else docs/conventions. Each falls back to its .claude/attribution.json or -# .claude/attribution.local.json only when the YAML is absent: per file, not per -# key. The config root is a parameter because it is resolved differently per -# script (CLAUDE_PROJECT_DIR over a corpus root that each one finds its own way). -# Config-cascade step 2: a home or non-repo root has no team or overlay layer. +# refinement order, user-global then team then personal override, skipping a +# layer that is not present. The team layer is /attribution.yaml and the +# personal override /attribution.local.yaml (ADR 0075), being the +# bound convention home, else docs/conventions. Each falls back to its +# .claude/attribution.json or .claude/attribution.local.json only when the YAML +# is absent: per file, not per key. The config root is a parameter because it is +# resolved differently per script (CLAUDE_PROJECT_DIR over a corpus root that +# each one finds its own way). +# Config-cascade step 2: a home or non-repo root has no team layer or personal +# override. cfg_layers_init() { local config_root="$1" home="docs/conventions" resolved name layer CFG_LAYERS=() @@ -120,9 +122,9 @@ cfg_scalar() { # cfg_list : the last layer that defines the top-level # replaces the list. Presence, not emptiness, decides: an explicit empty list is -# a value meaning "none", so an overlay can clear an earlier layer's list, while -# a layer that lacks the key leaves it standing. One element per line, internal -# spaces kept. +# a value meaning "none", so a personal override can clear an earlier layer's +# list, while a layer that lacks the key leaves it standing. One element per +# line, internal spaces kept. cfg_list() { local -n _cfg_arr="$1" local _cfg_key="$2" _cfg_layer _cfg_v _cfg_src="" _cfg_bom=$'\xEF\xBB\xBF' diff --git a/plugins/attribution/skills/audit/scripts/lib.test.sh b/plugins/attribution/skills/audit/scripts/lib.test.sh index f324c0d4e0c..60f82566896 100755 --- a/plugins/attribution/skills/audit/scripts/lib.test.sh +++ b/plugins/attribution/skills/audit/scripts/lib.test.sh @@ -94,23 +94,23 @@ cfg_list list excluded_paths assert_eq "a YAML block list is read" "$(printf '%s|' "${list[@]}")" "y/**|" assert_eq "a YAML list names its layer" "$CFG_SOURCE" "$YAML_TEAM" -# --- Overlays, the user-global layer, and per-file fallback per layer ------------ +# --- Personal overrides, the user-global layer, and per-file fallback per layer -- printf '%s\n' '{"stamp_expiry_days": 75}' >"$JSON_LOCAL" cfg_layers_init "$ROOT" -assert_eq "a YAML team layer sits beside a JSON overlay when the YAML overlay is absent" \ +assert_eq "a YAML team layer sits beside a JSON personal override when the YAML personal override is absent" \ "$(layers)" "$YAML_TEAM"$'\n'"$JSON_LOCAL" cfg_scalar v stamp_expiry_days -assert_eq "the JSON overlay refines the YAML team layer" "$v|$CFG_SOURCE" "75|$JSON_LOCAL" +assert_eq "the JSON personal override refines the YAML team layer" "$v|$CFG_SOURCE" "75|$JSON_LOCAL" printf '%s\n' 'stamp_expiry_days: 90' 'excluded_paths: []' >"$YAML_LOCAL" cfg_layers_init "$ROOT" -assert_eq "the YAML overlay replaces the JSON overlay" "$(layers)" "$YAML_TEAM"$'\n'"$YAML_LOCAL" +assert_eq "the YAML personal override replaces the JSON personal override" "$(layers)" "$YAML_TEAM"$'\n'"$YAML_LOCAL" cfg_scalar v stamp_expiry_days -assert_eq "the YAML overlay supplies the value" "$v|$CFG_SOURCE" "90|$YAML_LOCAL" +assert_eq "the YAML personal override supplies the value" "$v|$CFG_SOURCE" "90|$YAML_LOCAL" list=(stale) cfg_list list excluded_paths -assert_eq "an empty YAML overlay list clears the team list" "${#list[@]}|$CFG_SOURCE" "0|$YAML_LOCAL" +assert_eq "an empty YAML personal override list clears the team list" "${#list[@]}|$CFG_SOURCE" "0|$YAML_LOCAL" printf '%s\n' '{"trigger_less_stamp_check": true}' >"$USER_JSON" cfg_layers_init "$ROOT" diff --git a/plugins/attribution/skills/audit/scripts/list-corpus.sh b/plugins/attribution/skills/audit/scripts/list-corpus.sh index cd4124cb4bc..72b982d05cb 100755 --- a/plugins/attribution/skills/audit/scripts/list-corpus.sh +++ b/plugins/attribution/skills/audit/scripts/list-corpus.sh @@ -121,7 +121,7 @@ ROOT="$(git -C "$(anchor_dir)" rev-parse --show-toplevel 2>/dev/null || true)" CONFIG_ROOT="${CLAUDE_PROJECT_DIR:-$ROOT}" -# --- Config cascade (user-global -> team -> overlay; YAML, legacy JSON) ----------- +# --- Config cascade (user-global -> team -> personal override; YAML, legacy JSON) -- cfg_layers_init "$CONFIG_ROOT" diff --git a/plugins/attribution/skills/audit/scripts/list-corpus.test.sh b/plugins/attribution/skills/audit/scripts/list-corpus.test.sh index a600bf1d0bb..6d8de8b83ef 100755 --- a/plugins/attribution/skills/audit/scripts/list-corpus.test.sh +++ b/plugins/attribution/skills/audit/scripts/list-corpus.test.sh @@ -193,16 +193,16 @@ assert_contains "legacy returns once the config no longer excludes it" \ printf '%s\n' '{"excluded_paths":["docs/**"]}' >"$CFG_DIR/attribution.local.json" OVERLAY_OUT="$(cd "$REPO" && CLAUDE_PROJECT_DIR="$REPO" bash "$LIST_CORPUS" 2>/dev/null)" -assert_not_contains "the local overlay's exclusion applies" \ +assert_not_contains "the personal override's exclusion applies" \ "$(echo "$OVERLAY_OUT" | jq -r '.files[]')" "docs/guide.md" -assert_contains "the overlay replaces the team value per key" \ +assert_contains "the personal override replaces the team value per key" \ "$(echo "$OVERLAY_OUT" | jq -r '.files[]')" "evals/fixtures/golden/case-1/case.md" # Per-key override means a later layer REPLACES the value, and an explicit empty # array is a value. printf '%s\n' '{"excluded_paths":["docs/**"]}' >"$CFG_DIR/attribution.json" printf '%s\n' '{"excluded_paths":[]}' >"$CFG_DIR/attribution.local.json" CLEAR_OUT="$(cd "$REPO" && CLAUDE_PROJECT_DIR="$REPO" bash "$LIST_CORPUS" 2>/dev/null)" -assert_contains "an explicit empty overlay clears an inherited exclusion" \ +assert_contains "an explicit empty personal override clears an inherited exclusion" \ "$(echo "$CLEAR_OUT" | jq -r '.files[]')" "docs/guide.md" assert_eq "clearing leaves only the built-in carve-outs declined" \ "$(echo "$CLEAR_OUT" | jq -r '[.declined[] | select(.reason | test("excluded_paths"))] | length')" "0" @@ -226,7 +226,7 @@ assert_not_contains "--show-config does not list the shadowed JSON layer" \ "$YAML_SC" "$CFG_DIR/attribution.json" printf '%s\n' 'excluded_paths: []' >"$CONV/attribution.local.yaml" YAML_CLEAR="$(cd "$REPO" && CLAUDE_PROJECT_DIR="$REPO" bash "$LIST_CORPUS" 2>/dev/null)" -assert_contains "an empty YAML overlay list clears the team exclusion" \ +assert_contains "an empty YAML personal override list clears the team exclusion" \ "$(echo "$YAML_CLEAR" | jq -r '.files[]')" "legacy/old.md" rm -rf "$CONV" rm -f "$CFG_DIR/attribution.json" diff --git a/plugins/attribution/skills/audit/scripts/score-golden.sh b/plugins/attribution/skills/audit/scripts/score-golden.sh index 89ecc13bf71..42ffd6b0945 100755 --- a/plugins/attribution/skills/audit/scripts/score-golden.sh +++ b/plugins/attribution/skills/audit/scripts/score-golden.sh @@ -94,7 +94,7 @@ command -v jq >/dev/null 2>&1 || { exit 4 } -# --- Config cascade (user-global -> team -> overlay; YAML, legacy JSON) ----------- +# --- Config cascade (user-global -> team -> personal override; YAML, legacy JSON) -- REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" CONFIG_ROOT="${CLAUDE_PROJECT_DIR:-$REPO_ROOT}" diff --git a/plugins/attribution/skills/audit/scripts/sweep-ledger.test.sh b/plugins/attribution/skills/audit/scripts/sweep-ledger.test.sh index 29f20a832e4..851cac1337e 100755 --- a/plugins/attribution/skills/audit/scripts/sweep-ledger.test.sh +++ b/plugins/attribution/skills/audit/scripts/sweep-ledger.test.sh @@ -225,7 +225,8 @@ OUT="$(run --topic t1 status)" assert_exit "spend over the ceiling exits 1" "$?" "1" assert_contains "spend over the ceiling is reported as spent" "$OUT" "spend: 34 of 30" -# A team layer's ceiling is refined by the overlay: the later layer wins. +# A team layer's ceiling is refined by the personal override: the later layer +# wins. printf '%s\n' '{"budgets": {"corpus_fetch_ceiling": 500}}' >"$CLAUDE_PROJECT_DIR/.claude/attribution.local.json" OUT="$(run --topic t1 status)" assert_exit "a later layer raising the ceiling clears the stop" "$?" "0" diff --git a/plugins/attribution/skills/setup/SKILL.md b/plugins/attribution/skills/setup/SKILL.md index 48a4139134b..637bfa829fd 100644 --- a/plugins/attribution/skills/setup/SKILL.md +++ b/plugins/attribution/skills/setup/SKILL.md @@ -1,5 +1,5 @@ --- -description: "Set up and maintain this repository's attribution audit configuration: the team file `attribution.yaml` in the convention home and its gitignored local overlay. Run after installing the plugin, or to exclude a path from the audit, change the stamp expiry window, quiet an audit that flags too much, or turn on the trigger-less stamp check." +description: "Set up and maintain this repository's attribution audit configuration: the team file `attribution.yaml` in the convention home and its gitignored personal override. Run after installing the plugin, or to exclude a path from the audit, change the stamp expiry window, quiet an audit that flags too much, or turn on the trigger-less stamp check." argument-hint: "[check|apply]" user-invocable: true disable-model-invocation: true @@ -17,14 +17,15 @@ invocation: both mean `` is `docs/conventions`, where the detectors read; ask nothing. Exit 2 or 3: report its stderr line. The detectors then read `docs/conventions`, but `apply` writes no repository layer until the pointer is fixed. Exit 5: the root is not a repository, so there is - no team layer or overlay. + no team layer or personal override. - Layers in effect, `"${CLAUDE_PLUGIN_ROOT}/skills/audit/scripts/list-corpus.sh" --show-config`. Its `Config layers` list names every layer file the detectors read. A `.claude/` JSON file in that list is a layer still on its fallback. The list does not decide absence: a YAML layer that does not parse is left out of it, named on stderr, and shadows its JSON fallback, which is left - out too. A team layer or overlay is absent only when `test -f "//attribution.yaml"` - (or `attribution.local.yaml`) fails. A YAML layer that exists but is not listed is unparsable: - report it, and never overwrite it or carry its JSON fallback over it without the operator's choice. + out too. A team layer or personal override is absent only when + `test -f "//attribution.yaml"` (or `attribution.local.yaml`) fails. A YAML layer + that exists but is not listed is unparsable: report it, and never overwrite it or carry its JSON + fallback over it without the operator's choice. Substitute the literal root and home the previous calls returned for `` and ``; when the root call failed, there is no team layer to look for. `apply` creates `` when it is @@ -47,7 +48,7 @@ deliberate human choice. | Argument | Action | |---|---| | *(empty)* or `check` | **Read-only.** Report the effective config, which layer supplies each value, and what a proposed change would alter. Writes nothing | -| `apply` | Write the agreed keys to `/attribution.yaml`, the team layer, or to `/attribution.local.yaml` when the user asks for the local overlay | +| `apply` | Write the agreed keys to `/attribution.yaml`, the team layer, or to `/attribution.local.yaml` when the user asks for the personal override | `check` is the default and never writes. `apply` writes only after the user has seen a `check` report naming every key it will change and the layer it will change it in. On a first run in a @@ -93,16 +94,17 @@ an earlier one: |---|---|---|---| | 1 | user-global | `~/.claude/attribution.json` | the operator, across every repo | | 2 | team | `//attribution.yaml` | the repository, tracked | -| 3 | local overlay | `//attribution.local.yaml` | one operator in one repo, gitignored | +| 3 | personal override | `//attribution.local.yaml` | one operator in one repo, gitignored | -`apply` writes only the team layer and the local overlay, never the user-global file. Before it -writes the overlay, `git check-ignore -q "//attribution.local.yaml"` must exit 0; when -it does not, say the file would be tracked and get the operator's choice before writing. +`apply` writes only the team layer and the personal override, never the user-global file. Before +it writes the personal override, `git check-ignore -q "//attribution.local.yaml"` must +exit 0; when it does not, say the file would be tracked and get the operator's choice before +writing. All three absent is a valid state: the bundled defaults apply. Merge is **per-key override**. A later layer replaces a value key by key, and a key absent from a later layer keeps the earlier value. Never write a layer that restates the whole config to change one key; that turns every -key the overlay does not mention into an accidental decision. +key the personal override does not mention into an accidental decision. To report the effective values and their supplying layer, run the detectors' own `--show-config`, which is the authority rather than reading the files by hand: diff --git a/plugins/attribution/skills/setup/evals/evals.json b/plugins/attribution/skills/setup/evals/evals.json index a0b18a69fdd..37356e5db57 100644 --- a/plugins/attribution/skills/setup/evals/evals.json +++ b/plugins/attribution/skills/setup/evals/evals.json @@ -23,7 +23,7 @@ "expectations": [ "Changes only the named key and leaves every other existing key intact", "Does NOT rewrite the file from the full default schema, which would turn unmentioned keys into accidental decisions", - "Writes to the team layer by default, and to the local overlay only when the user asked for it", + "Writes to the team layer by default, and to the personal override only when the user asked for it", "Reports the resulting effective value and the layer it now comes from" ] }, @@ -94,7 +94,7 @@ }, { "id": 8, - "name": "migrates-the-retired-local-overlay", + "name": "migrates-the-retired-personal-override", "prompt": "/attribution:setup apply in a repo with no convention-home pointer where both a gitignored docs/conventions/attribution.local.yaml (judge_samples 5) and the pre-rename .claude/provenance.local.json (judge_samples 3, trigger_less_stamp_check true) exist.", "expected_output": "Detection reports attribution-r002 as FAIL. apply adds only trigger_less_stamp_check to docs/conventions/attribution.local.yaml and keeps its judge_samples 5, because the current file wins where both set a key. It reports that per key, gets the operator's confirmation, then runs --clean attribution-r002 --i-migrated and re-runs detection.", "expectations": [ @@ -119,14 +119,14 @@ }, { "id": 10, - "name": "overlay-write-checks-gitignore", - "prompt": "/attribution:setup apply judge_samples 5 to the local overlay in a repo with no convention-home pointer whose .gitignore does not ignore docs/conventions/attribution.local.yaml.", + "name": "personal-override-write-checks-gitignore", + "prompt": "/attribution:setup apply judge_samples 5 to the personal override in a repo with no convention-home pointer whose .gitignore does not ignore docs/conventions/attribution.local.yaml.", "narration": true, - "expected_output": "Before writing the overlay, git check-ignore -q on docs/conventions/attribution.local.yaml exits non-zero, so the skill says the file would be tracked and asks the operator how to proceed instead of writing it.", + "expected_output": "Before writing the personal override, git check-ignore -q on docs/conventions/attribution.local.yaml exits non-zero, so the skill says the file would be tracked and asks the operator how to proceed instead of writing it.", "expectations": [ - "Runs git check-ignore -q against docs/conventions/attribution.local.yaml before writing the overlay", - "States that the overlay would be tracked when the check fails", - "Does not write the overlay until the operator chooses", + "Runs git check-ignore -q against docs/conventions/attribution.local.yaml before writing the personal override", + "States that the personal override would be tracked when the check fails", + "Does not write the personal override until the operator chooses", "Never writes the user-global ~/.claude/attribution.json" ] } diff --git a/plugins/bugs/README.md b/plugins/bugs/README.md index ea98b28e3a2..4b464e2f087 100644 --- a/plugins/bugs/README.md +++ b/plugins/bugs/README.md @@ -117,20 +117,20 @@ where its value is stored). **Team, the tracked `docs/conventions/bugs.yaml`**, which `/bugs:scan` reads for its lanes (`lanes`) and its filing policy (`filing_posture`), checked against [`schemas/bugs.schema.json`](schemas/bugs.schema.json). A `## Gotchas` section in the prose file -beside it, `docs/conventions/bugs.md` (and in the user-global and local overlay layers), +beside it, `docs/conventions/bugs.md` (and in the user-global and personal override layers), concatenates after the bundled gotchas when `/bugs:scan` or `/bugs:write` loads. Repo-specific lines stay in the layer; a line that is not repo-specific is filed as an issue on this marketplace (`melodic-software/claude-code-plugins`) for curation into the shipped skill. The config is layered per the marketplace's -config-cascade convention, a user-global file, this tracked team file, and a gitignored local -overlay. All layers are optional: with no config at all, `scan` rotates over bundled generic +config-cascade convention, a user-global file, this tracked team file, and a gitignored personal +override. All layers are optional: with no config at all, `scan` rotates over bundled generic default lanes. Keys, defaults, layer order, and per-key merge semantics live in [`reference/config.md`](reference/config.md), their single home. Run `/bugs:setup` to work on either surface. `check` (the default) reports both read-only: the rendered `output_dir` and which layer supplied each lane config value. `apply` writes the tracked file and nothing else. It drafts lane candidates from your repository, confirms them one -at a time, and never touches settings, `pluginConfigs`, the local overlay, or your `.gitignore`. +at a time, and never touches settings, `pluginConfigs`, the personal override, or your `.gitignore`. Project-specific conventions, naming, areas, tracker choice, priority labels, are read from the **consuming project's own `CLAUDE.md` / rules**; the plugin imposes diff --git a/plugins/bugs/reference/config.md b/plugins/bugs/reference/config.md index 2ef6ff63e93..f7700349fe2 100644 --- a/plugins/bugs/reference/config.md +++ b/plugins/bugs/reference/config.md @@ -15,7 +15,7 @@ Three layers, resolved in this order, where a later layer refines an earlier one |---|---|---|---| | 1 | user-global | `~/.claude/bugs.md` | outside the worktree, so no git verdict applies | | 2 | team (tracked) | `${CLAUDE_PROJECT_DIR}/docs/conventions/bugs.yaml` for the keys; `${CLAUDE_PROJECT_DIR}/docs/conventions/bugs.md` for prose and `## Gotchas` | must be tracked, the only layer teammates receive | -| 3 | local overlay | `${CLAUDE_PROJECT_DIR}/.claude/bugs.local.md` | must be gitignored, never staged | +| 3 | personal override | `${CLAUDE_PROJECT_DIR}/.claude/bugs.local.md` | must be gitignored, never staged | The team files sit in `docs/conventions/` whatever convention home the repository binds; a repository that binds another home still keeps them there. @@ -27,7 +27,7 @@ name the layer, resolve as if that layer were absent. Unknown keys are inert. Wh config is surfaced to a human, report which layer supplied each value. `/bugs:scan` and `/bugs:write` also concatenate each layer's `## Gotchas` section (see below) via `scripts/concat-gotchas.sh`, which applies the special-root rule: a root that is home (or an -ancestor of it) or outside a git work tree has no team or overlay layer. +ancestor of it) or outside a git work tree has no team or personal override layer. ## Merge semantics @@ -56,7 +56,7 @@ them. It is therefore not a recognized key, and a layer that sets it is reported ## File format The team keys are plain YAML in `docs/conventions/bugs.yaml`, checked against the schema; the -team prose sits beside it in `docs/conventions/bugs.md`. The user-global and local-overlay layers +team prose sits beside it in `docs/conventions/bugs.md`. The user-global and personal override layers are Markdown with a fenced YAML block holding the same keys; prose outside the block is the consumer's own commentary, except a `## Gotchas` section. @@ -102,7 +102,7 @@ one entry were absent. Do not discard the whole layer. ## Consumer `.gitignore` -One recursive line covers the overlay here and every other cascade surface: +One recursive line covers the personal override here and every other cascade surface: ```gitignore .claude/**/*.local.* diff --git a/plugins/bugs/scripts/concat-gotchas.sh b/plugins/bugs/scripts/concat-gotchas.sh index 1a8779f80e0..ecfb18f970d 100755 --- a/plugins/bugs/scripts/concat-gotchas.sh +++ b/plugins/bugs/scripts/concat-gotchas.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Concatenate ## Gotchas from the bugs config-cascade layers in layer order -# (user-global ~/.claude/bugs.md, team docs/conventions/bugs.md, local overlay +# (user-global ~/.claude/bugs.md, team docs/conventions/bugs.md, personal override # .claude/bugs.local.md). Form 1 (concatenate) per # docs/contracts/config-cascade/consumer-gotchas.md (#3547). # @@ -77,7 +77,7 @@ if [[ -z "$root" ]]; then fi # Config-cascade 1.3 special-root classification: a root that is $HOME or an -# ancestor of it, or is not inside a git working tree, has no team or overlay +# ancestor of it, or is not inside a git working tree, has no team or personal override # layer. Otherwise ~/.claude/bugs.md would be read again as the team layer. if [[ -n "$root" && -n "${HOME:-}" ]]; then # Fold slashes, trailing slash, and case, as config-cascade step 2 and @@ -94,7 +94,7 @@ fi user="${HOME:+$HOME/.claude/bugs.md}" [[ -n "$user" ]] && emit_layer "user-global" "$user" -for pair in "team:docs/conventions/bugs.md" "local overlay:.claude/bugs.local.md"; do +for pair in "team:docs/conventions/bugs.md" "personal override:.claude/bugs.local.md"; do [[ -n "$root" ]] || break file="$root/${pair#*:}" [[ -n "$user" && "$file" -ef "$user" ]] && continue diff --git a/plugins/bugs/scripts/concat-gotchas.test.sh b/plugins/bugs/scripts/concat-gotchas.test.sh index a0e58e1915a..a9a067bacc3 100755 --- a/plugins/bugs/scripts/concat-gotchas.test.sh +++ b/plugins/bugs/scripts/concat-gotchas.test.sh @@ -102,10 +102,10 @@ lanes concatenate. ' layer "$CLAUDE_PROJECT_DIR/.claude/bugs.local.md" '## Gotchas -- Overlay: my fork uses a different tracker. +- Personal override: my fork uses a different tracker. ' # shellcheck disable=SC2016 # backticks are the literal markdown code spans in the expected fixture, not substitution -run_case "three layers concatenate in cascade order" "$(printf '### Consumer gotchas (cascade)\n\n#### user-global (`%s`)\n\n- User: this machine has no GPU.\n\n#### team (`%s`)\n\n- Team: do not file from the sandbox.\n\n#### local overlay (`%s`)\n\n- Overlay: my fork uses a different tracker.\n' "$HOME/.claude/bugs.md" "$CLAUDE_PROJECT_DIR/docs/conventions/bugs.md" "$CLAUDE_PROJECT_DIR/.claude/bugs.local.md")" +run_case "three layers concatenate in cascade order" "$(printf '### Consumer gotchas (cascade)\n\n#### user-global (`%s`)\n\n- User: this machine has no GPU.\n\n#### team (`%s`)\n\n- Team: do not file from the sandbox.\n\n#### personal override (`%s`)\n\n- Personal override: my fork uses a different tracker.\n' "$HOME/.claude/bugs.md" "$CLAUDE_PROJECT_DIR/docs/conventions/bugs.md" "$CLAUDE_PROJECT_DIR/.claude/bugs.local.md")" HOME="${FIXTURES}/home-c" CLAUDE_PROJECT_DIR="${FIXTURES}/repo-c" @@ -191,10 +191,10 @@ layer "$HOME/.claude/bugs.md" '## Gotchas ' layer "$HOME/.claude/bugs.local.md" '## Gotchas -- Overlay under home: not a layer here. +- Personal override under home: not a layer here. ' # shellcheck disable=SC2016 # backticks are literal markdown in the expected output -run_case "home-rooted session reads user-global once, no team or overlay" "$(printf '### Consumer gotchas (cascade)\n\n#### user-global (`%s`)\n\n- User: read once.\n' "$HOME/.claude/bugs.md")" +run_case "home-rooted session reads user-global once, no team or personal override" "$(printf '### Consumer gotchas (cascade)\n\n#### user-global (`%s`)\n\n- User: read once.\n' "$HOME/.claude/bugs.md")" HOME="${FIXTURES}/home-i" CLAUDE_PROJECT_DIR="${FIXTURES}/not-a-repo" diff --git a/plugins/bugs/skills/scan/SKILL.md b/plugins/bugs/skills/scan/SKILL.md index 46371a2a34d..e18e5bdd86f 100644 --- a/plugins/bugs/skills/scan/SKILL.md +++ b/plugins/bugs/skills/scan/SKILL.md @@ -384,7 +384,7 @@ verified, say so and name the lane and rung, so the next run rotates on. - **Never declare `type: review-findings` on a scan report.** That frontmatter alone routes a report into the `/review:fanout` fix relay; a scan report is intake. - **Consumer gotchas extend these.** The pre-computed block holds the `## Gotchas` sections of the - bugs config layers (user-global, team, local overlay) in layer order; apply them to this + bugs config layers (user-global, team, personal override) in layer order; apply them to this invocation. A missing layer is absent, not an error. A generalizable line belongs in this shipped skill via an issue, not in the consumer file. diff --git a/plugins/bugs/skills/setup/SKILL.md b/plugins/bugs/skills/setup/SKILL.md index 39da343cd9c..3a1abc8f5c7 100644 --- a/plugins/bugs/skills/setup/SKILL.md +++ b/plugins/bugs/skills/setup/SKILL.md @@ -87,7 +87,7 @@ merged result: probes per file. `git check-ignore -v docs/conventions/bugs.yaml`: a non-empty result is FAIL, naming the matching pattern. `git ls-files --error-unmatch docs/conventions/bugs.yaml`: a non-zero exit on a present file is FAIL, "present but untracked, commit it so teammates receive - it". Probe `docs/conventions/bugs.md` the same way when present. The `.local.md` overlay must be + it". Probe `docs/conventions/bugs.md` the same way when present. The `.local.md` personal override must be gitignored; staged or unignored is FAIL. The user-global layer sits outside the worktree: say no git verdict applies rather than run a meaningless command. 4. **Unreachable layers.** When a layer cannot be read (often the user-global one), WARN that it was @@ -99,14 +99,14 @@ merged result: Run `check` first, then converge the **team** YAML, the only artifact this action writes. Never touch `settings.json`, `settings.local.json`, managed settings, `pluginConfigs`, `userConfig`, the -user-global layer, the `.local.md` overlay, or the consumer's +user-global layer, the `.local.md` personal override, or the consumer's `.gitignore`. An `output_dir` change requested here routes to the native flow in `check` step A4, never written. -1. **Read the effective config across every layer** and present it. Where a user-global or overlay +1. **Read the effective config across every layer** and present it. Where a user-global or personal override layer changes the team file's effect (adding lanes, replacing one by name, opting out with an empty list, or supplying `filing_posture` nearest-wins), say so: a team-scope edit alone will not - account for it, and re-adding a lane an overlay opts out of will not restore it on this machine. + account for it, and re-adding a lane a personal override opts out of will not restore it on this machine. Prompt the user to update that layer; do not edit it for them. 2. **Draft lanes from the repository** before asking anything: entrypoint and API directories, the highest-churn source areas in `git log`, and any subsystem the repo's own docs treat as critical. @@ -124,7 +124,7 @@ never written. meets the schema, every lane declares `name` and `globs`, the globs match real paths (a lane matching nothing is reported as skipped), and `git check-ignore -v docs/conventions/bugs.yaml` confirms it is not ignored. Report the values observed, never an unobserved change. -6. **Recommend the overlay line; do not write it.** Personal deviations belong in +6. **Recommend the personal override line; do not write it.** Personal deviations belong in `.claude/bugs.local.md`; recommend the recursive `.gitignore` line the reference names if not already covered. 7. **Remind them to stage it.** The team file reaches teammates only once committed. diff --git a/plugins/bugs/skills/setup/evals/evals.json b/plugins/bugs/skills/setup/evals/evals.json index be219773379..ee5526e7ee6 100644 --- a/plugins/bugs/skills/setup/evals/evals.json +++ b/plugins/bugs/skills/setup/evals/evals.json @@ -42,14 +42,14 @@ { "id": 4, "name": "apply-stays-off-user-config-and-gitignore", - "prompt": "/bugs:setup apply\n\nAlso point output_dir at docs/bug-reports/ and add the ignore line for my personal overlay.", - "expected_output": "Writes the lane config only, routes the output_dir change to Claude Code's plugin configuration prompt, and recommends the recursive .claude ignore line for the .local.md overlay without editing .gitignore.", + "prompt": "/bugs:setup apply\n\nAlso point output_dir at docs/bug-reports/ and add the ignore line for my personal override.", + "expected_output": "Writes the lane config only, routes the output_dir change to Claude Code's plugin configuration prompt, and recommends the recursive .claude ignore line for the .local.md personal override without editing .gitignore.", "files": [], "narration": true, "expectations": [ "Does not write settings files, pluginConfigs, or userConfig", "Routes output_dir through Claude Code's native configuration flow", - "Recommends the overlay gitignore line but leaves the edit to the consumer" + "Recommends the personal override gitignore line but leaves the edit to the consumer" ] }, { diff --git a/plugins/bugs/skills/write/SKILL.md b/plugins/bugs/skills/write/SKILL.md index d97f5133c81..48e0908ee2d 100644 --- a/plugins/bugs/skills/write/SKILL.md +++ b/plugins/bugs/skills/write/SKILL.md @@ -237,7 +237,7 @@ present in their host. - **The survey is grounding, not investigation.** A bug that needs real investigation is scoped separately. - **Consumer gotchas extend these.** The pre-computed block holds the `## Gotchas` sections of the - bugs config layers (user-global, team, local overlay) in layer order; apply them to this + bugs config layers (user-global, team, personal override) in layer order; apply them to this invocation. A missing layer is absent, not an error. A generalizable line belongs in this shipped skill via an issue, not in the consumer file. diff --git a/plugins/code-metrics/README.md b/plugins/code-metrics/README.md index 897893914f7..9d98cae1cc0 100644 --- a/plugins/code-metrics/README.md +++ b/plugins/code-metrics/README.md @@ -76,7 +76,7 @@ run continues. This plugin has no `userConfig`. Everything tunable lives in three layers: user-global (`~/.claude/code-metrics.yaml`), team (`docs/conventions/code-metrics.yaml`, tracked, checked by [`schemas/code-metrics.schema.json`](schemas/code-metrics.schema.json); the retired team file -under `.claude/` is not read, and `/code-metrics:setup apply` moves its keys), and local overlay (`.claude/code-metrics.local.yaml`, gitignored; recommended line +under `.claude/` is not read, and `/code-metrics:setup apply` moves its keys), and personal override (`.claude/code-metrics.local.yaml`, gitignored; recommended line `.claude/**/*.local.*`) with per-key override, and every key has a bundled default (`scripts/config-defaults.json`), so the plugin works with no configuration at all; the one opinionated default is `scope.exclude`, which drops `node_modules`, `vendor`, `dist`, and `build` diff --git a/plugins/code-metrics/reference/config.md b/plugins/code-metrics/reference/config.md index 59e0d7914ed..b30203c8dea 100644 --- a/plugins/code-metrics/reference/config.md +++ b/plugins/code-metrics/reference/config.md @@ -15,7 +15,7 @@ resolved in this order over the bundled defaults (`scripts/config-defaults.json` |---|---|---|---| | 1 | user-global | `~/.claude/code-metrics.yaml` | the operator, across repositories | | 2 | team | `/docs/conventions/code-metrics.yaml` | the repository, tracked | -| 3 | local overlay | `/.claude/code-metrics.local.yaml` | one operator in one repository, gitignored | +| 3 | personal override | `/.claude/code-metrics.local.yaml` | one operator in one repository, gitignored | The team layer is `docs/conventions/code-metrics.yaml` alone. The team file earlier releases read from the repository's `.claude/` directory is retired and never read. `/code-metrics:setup check` @@ -35,7 +35,7 @@ holding a newline, carriage return or tab, a `scope.exclude` glob the matcher ca A later layer replaces an earlier layer's value key by key; a key absent from a later layer keeps the earlier value; a list (`scope.exclude`, `lanes..collectors.`) is a closed value and is replaced whole, never concatenated. Unknown keys are inert. All three layers absent is -valid. The recommended consumer `.gitignore` line for the overlay is `.claude/**/*.local.*`; the +valid. The recommended consumer `.gitignore` line for the personal override is `.claude/**/*.local.*`; the plugin never edits your `.gitignore`. The consumer's `.claude/ecosystems/.yaml` files (the ecosystem-commands convention) resolve diff --git a/plugins/code-metrics/scripts/fixtures/config/local.yaml b/plugins/code-metrics/scripts/fixtures/config/local.yaml index 4691bc517ce..bcad770dffe 100644 --- a/plugins/code-metrics/scripts/fixtures/config/local.yaml +++ b/plugins/code-metrics/scripts/fixtures/config/local.yaml @@ -1,4 +1,4 @@ -# Fixture: the local overlay (.claude/code-metrics.local.yaml). One +# Fixture: the personal override (.claude/code-metrics.local.yaml). One # operator's exclusion, additive over the team file. scope: exclude: ["vendor/**"] diff --git a/plugins/code-metrics/scripts/resolve-config.py b/plugins/code-metrics/scripts/resolve-config.py index a8c0ff10b99..0fa123be32d 100755 --- a/plugins/code-metrics/scripts/resolve-config.py +++ b/plugins/code-metrics/scripts/resolve-config.py @@ -9,7 +9,7 @@ 0. bundled defaults scripts/config-defaults.json 1. user-global ~/.claude/code-metrics.yaml 2. team /docs/conventions/code-metrics.yaml - 3. local overlay /.claude/code-metrics.local.yaml + 3. personal override /.claude/code-metrics.local.yaml The team file earlier releases read from the repository's .claude directory is not read; /code-metrics:setup check reports it and apply moves its keys. @@ -198,16 +198,16 @@ def _reset( def merge( - base: Any, overlay: Any, layer: str, prefix: str, layers: dict[str, str] + base: Any, upper: Any, layer: str, prefix: str, layers: dict[str, str] ) -> Any: - if isinstance(base, dict) and isinstance(overlay, dict): + if isinstance(base, dict) and isinstance(upper, dict): result = dict(base) - for key, value in overlay.items(): + for key, value in upper.items(): dotted = f"{prefix}.{key}" if prefix else key result[key] = merge(base.get(key), value, layer, dotted, layers) return result layers[prefix] = layer - return overlay + return upper def _walk(node: Any, prefix: str, out: dict[str, Any]) -> None: @@ -273,15 +273,15 @@ def resolve( for layer, path in layer_files: if not os.path.isfile(path): continue - overlay = _load_layer(path, warnings) - if overlay is None: + values = _load_layer(path, warnings) + if values is None: continue - for key in overlay: + for key in values: if _reserved(key): warnings.append(f"{path}: key {key!r} is reserved and ignored") - overlay = {k: v for k, v in overlay.items() if not _reserved(k)} + values = {k: v for k, v in values.items() if not _reserved(k)} leaves: dict[str, Any] = {} - _walk(overlay, "", leaves) + _walk(values, "", leaves) for key, value in leaves.items(): reason = _invalid(key, value, defaults, threshold_keys) if reason is None: @@ -291,9 +291,9 @@ def resolve( "dropped and the key resolves from a higher layer or the bundled default" ) parts = key.split(".") - _drop(overlay, parts) + _drop(values, parts) _reset(config, defaults, parts, layers) - config = merge(config, overlay, layer, "", layers) + config = merge(config, values, layer, "", layers) files_read.append(path.replace("\\", "/")) if ladder_path: known: set[tuple[str, str, str]] = set() @@ -333,10 +333,10 @@ def resolve( for layer, path in files: if not os.path.isfile(path): continue - overlay = _load_layer(path, warnings) - if overlay is None: + values = _load_layer(path, warnings) + if values is None: continue - eco = merge(eco, overlay, layer, "", eco_layers) + eco = merge(eco, values, layer, "", eco_layers) files_read.append(path.replace("\\", "/")) if not eco: continue diff --git a/plugins/code-metrics/skills/audit-coverage/SKILL.md b/plugins/code-metrics/skills/audit-coverage/SKILL.md index 16d978f36a0..b86c56dbb19 100644 --- a/plugins/code-metrics/skills/audit-coverage/SKILL.md +++ b/plugins/code-metrics/skills/audit-coverage/SKILL.md @@ -156,7 +156,7 @@ configuration. ## Configuration Everything tunable resolves through the code-metrics layers (user-global, team -`docs/conventions/code-metrics.yaml`, local overlay; per-key override; keys in `${CLAUDE_PLUGIN_ROOT}/reference/config.md`): +`docs/conventions/code-metrics.yaml`, personal override; per-key override; keys in `${CLAUDE_PLUGIN_ROOT}/reference/config.md`): | Key | Default | Effect | |---|---|---| diff --git a/plugins/code-metrics/skills/audit-duplication/SKILL.md b/plugins/code-metrics/skills/audit-duplication/SKILL.md index e3de23e56bb..5448c384d77 100644 --- a/plugins/code-metrics/skills/audit-duplication/SKILL.md +++ b/plugins/code-metrics/skills/audit-duplication/SKILL.md @@ -110,7 +110,7 @@ your notes and compare by hand. ## Configuration Everything tunable resolves through the code-metrics layers (user-global, team -`docs/conventions/code-metrics.yaml`, local overlay; per-key override; keys in `${CLAUDE_PLUGIN_ROOT}/reference/config.md`): +`docs/conventions/code-metrics.yaml`, personal override; per-key override; keys in `${CLAUDE_PLUGIN_ROOT}/reference/config.md`): `duplication.min_tokens` (default 50), `duplication.min_lines` (default 5), `duplication.ignore` (globs handed to the detector's own ignore option), `duplication.max_size` (default `1mb`, binary units; a larger file is left out of the scan and reported), `duplication.max_lines` diff --git a/plugins/code-metrics/skills/audit/actions/complexity.md b/plugins/code-metrics/skills/audit/actions/complexity.md index 81db7b2a044..5a15a84b66a 100644 --- a/plugins/code-metrics/skills/audit/actions/complexity.md +++ b/plugins/code-metrics/skills/audit/actions/complexity.md @@ -79,7 +79,7 @@ you, and why no threshold here is a verdict. ## Configuration Everything tunable resolves through the code-metrics layers (user-global, team -`docs/conventions/code-metrics.yaml`, local overlay; per-key override; keys in `/reference/config.md`): the three +`docs/conventions/code-metrics.yaml`, personal override; per-key override; keys in `/reference/config.md`): the three references above, scope exclusions (`scope.exclude`, which by default drops `node_modules`, `vendor`, `dist`, and `build` directories at any depth and reports each pattern's count), sanctioned-replication registries (`scope.registries`), the base ref (`scope.base`), and the diff --git a/plugins/code-metrics/skills/audit/actions/size.md b/plugins/code-metrics/skills/audit/actions/size.md index 77bca1e5e25..d7efb1de649 100644 --- a/plugins/code-metrics/skills/audit/actions/size.md +++ b/plugins/code-metrics/skills/audit/actions/size.md @@ -56,7 +56,7 @@ side as INCONCLUSIVE); otherwise keep the JSON beside your notes and compare by ## Configuration Everything tunable resolves through the code-metrics layers (user-global, team -`docs/conventions/code-metrics.yaml`, local overlay; per-key override; keys in `/reference/config.md`): the reference +`docs/conventions/code-metrics.yaml`, personal override; per-key override; keys in `/reference/config.md`): the reference (`size.file_lines`), the mode (`size.mode`: `file-lines`, or `iso-8.2.115`, which adds a `function_lines` measure comparing each function's non-empty lines against `size.function_lines_pct` of the file's, from a collector that reports function ranges such as diff --git a/plugins/code-metrics/skills/audit/actions/type-debt.md b/plugins/code-metrics/skills/audit/actions/type-debt.md index e5b306eae6c..a7cead47897 100644 --- a/plugins/code-metrics/skills/audit/actions/type-debt.md +++ b/plugins/code-metrics/skills/audit/actions/type-debt.md @@ -66,7 +66,7 @@ your notes and compare by hand. ## Configuration Everything tunable resolves through the code-metrics layers (user-global, team -`docs/conventions/code-metrics.yaml`, local overlay; +`docs/conventions/code-metrics.yaml`, personal override; per-key override; keys in `/reference/config.md`): the reference (`type_debt.reference`, `null` by default), scope exclusions (`scope.exclude`), a per-lane opt-out (`lanes..enabled: false`, which drops that lane even under `--all`), and the per-lane diff --git a/plugins/code-metrics/skills/principles/reference/thresholds.md b/plugins/code-metrics/skills/principles/reference/thresholds.md index 61d9ae12810..a5ae8ad1813 100644 --- a/plugins/code-metrics/skills/principles/reference/thresholds.md +++ b/plugins/code-metrics/skills/principles/reference/thresholds.md @@ -87,7 +87,7 @@ them argue against it directly. ## Setting your own Every reference resolves across three layers, user-global (`~/.claude/code-metrics.yaml`) then -team (`docs/conventions/code-metrics.yaml`) then local overlay, with per-key override: setting one key replaces that value and leaves the +team (`docs/conventions/code-metrics.yaml`) then personal override, with per-key override: setting one key replaces that value and leaves the rest of the defaults intact. The full key list is [`reference/config.md`](../../../reference/config.md), and `/code-metrics:setup` writes the team file and probes the collectors. The report prints the layer that supplied any value a personal layer changed, so a number that differs from a teammate's is diff --git a/plugins/code-metrics/skills/setup/SKILL.md b/plugins/code-metrics/skills/setup/SKILL.md index da3e1f4634f..52b99bcd38e 100644 --- a/plugins/code-metrics/skills/setup/SKILL.md +++ b/plugins/code-metrics/skills/setup/SKILL.md @@ -1,5 +1,5 @@ --- -description: "Verify or configure the code-metrics plugin for this repository: `check` probes the interpreter, every configuration layer (user-global, team, local overlay, and the consumer's ecosystem files) for the YAML subset and the tracked-file guard, prints every reference with the layer that supplied it, and runs each collector adapter's probe and one measure on a bundled fixture (a version and the measure, or missing with its install hint); `apply` writes the tracked `docs/conventions/code-metrics.yaml` team layer per key, carrying every declared key of a retired `.claude/code-metrics.yaml`, idempotently, never installing a tool and never editing `.gitignore`. Use when: 'set up code-metrics', 'configure code metrics', 'is code-metrics configured', 'which collectors are installed', 'set the cyclomatic reference', 'change the file length reference', 'code-metrics setup', or an audit skill reports a configuration layer it could not read." +description: "Verify or configure the code-metrics plugin for this repository: `check` probes the interpreter, every configuration layer (user-global, team, personal override, and the consumer's ecosystem files) for the YAML subset and the tracked-file guard, prints every reference with the layer that supplied it, and runs each collector adapter's probe and one measure on a bundled fixture (a version and the measure, or missing with its install hint); `apply` writes the tracked `docs/conventions/code-metrics.yaml` team layer per key, carrying every declared key of a retired `.claude/code-metrics.yaml`, idempotently, never installing a tool and never editing `.gitignore`. Use when: 'set up code-metrics', 'configure code metrics', 'is code-metrics configured', 'which collectors are installed', 'set the cyclomatic reference', 'change the file length reference', 'code-metrics setup', or an audit skill reports a configuration layer it could not read." argument-hint: "[check|apply] [= ...]" user-invocable: true disable-model-invocation: true @@ -12,7 +12,7 @@ shell: bash Every reference the plugin prints, every lane's collector order, the scope exclusions, and the coverage artifact paths resolve through one consumer surface, layered as user-global (`~/.claude/code-metrics.yaml`), team (`docs/conventions/code-metrics.yaml`, tracked; schema -`${CLAUDE_PLUGIN_ROOT}/schemas/code-metrics.schema.json`), and local overlay +`${CLAUDE_PLUGIN_ROOT}/schemas/code-metrics.schema.json`), and personal override (`.claude/code-metrics.local.yaml`, gitignored) with per-key override. The team file of earlier releases, `.claude/code-metrics.yaml`, is retired and never read; `apply` moves its keys. All three layers absent is a valid state: every key has a bundled default. This skill is the check-centric setup for that @@ -47,7 +47,7 @@ Rows, each PASS, FAIL, WARN, or INFO: 3. **layer team tracked**: `git check-ignore -v` on the team file reports no match (a match is FAIL with the rule: an ignored team layer never reaches the team) and `git ls-files --error-unmatch` sees it (untracked is WARN: written but uncommitted). -4. **layer local ignored**: the overlay is gitignored, else WARN with the recommended consumer +4. **layer local ignored**: the personal override is gitignored, else WARN with the recommended consumer line `.claude/**/*.local.*`. Recommend the line; never edit the consumer's `.gitignore`. 5. **ecosystem `.yaml`**: each consumer ecosystem file parses; its `globs` and `enabled` override lane detection. diff --git a/plugins/code-metrics/skills/setup/scripts/setup-check.sh b/plugins/code-metrics/skills/setup/scripts/setup-check.sh index 362829913bb..2064b25fbdf 100755 --- a/plugins/code-metrics/skills/setup/scripts/setup-check.sh +++ b/plugins/code-metrics/skills/setup/scripts/setup-check.sh @@ -99,9 +99,9 @@ check_layer() { row WARN "layer $name tracked" "written but untracked: commit it to share with the team" fi elif git -C "$REPO_ROOT" check-ignore -q "$rel" 2>/dev/null; then - row PASS "layer $name ignored" "the local overlay is gitignored" + row PASS "layer $name ignored" "the personal override is gitignored" else - row WARN "layer $name ignored" "the local overlay is NOT gitignored; recommended consumer .gitignore line: .claude/**/*.local.* (the plugin never edits your .gitignore)" + row WARN "layer $name ignored" "the personal override is NOT gitignored; recommended consumer .gitignore line: .claude/**/*.local.* (the plugin never edits your .gitignore)" fi } check_layer "user-global" "$HOME_DIR/.claude/code-metrics.yaml" n/a diff --git a/plugins/code-metrics/skills/setup/scripts/setup-check.test.sh b/plugins/code-metrics/skills/setup/scripts/setup-check.test.sh index 1eeb1af9ce6..0b5adff2445 100755 --- a/plugins/code-metrics/skills/setup/scripts/setup-check.test.sh +++ b/plugins/code-metrics/skills/setup/scripts/setup-check.test.sh @@ -101,7 +101,7 @@ else fi # 3. An ignored (and therefore uncommittable) team file is a FAIL and the exit -# code says so; a local overlay that is not ignored warns with the +# code says so; a personal override that is not ignored warns with the # recommended line. git reports an ignore match only for untracked paths, # so the file is untracked first. (cd "$repo" && git rm -q --cached docs/conventions/code-metrics.yaml && git commit -q -m untrack) @@ -112,7 +112,7 @@ out="$(bash "$SCRIPT" --repo-root "$repo" --home "$home")" rc=$? assert_eq "ignored team file exits 1" 1 "$rc" assert_contains "ignored team file fails" "$out" "FAIL layer team tracked" -assert_contains "unignored overlay warns with the gitignore line" "$out" ".claude/**/*.local.*" +assert_contains "unignored personal override warns with the gitignore line" "$out" ".claude/**/*.local.*" rm -f "$repo/.gitignore" # 4. A layer outside the subset is a FAIL naming the construct and line. diff --git a/plugins/codebase-health/README.md b/plugins/codebase-health/README.md index a35e7dc771c..99a10c5c81d 100644 --- a/plugins/codebase-health/README.md +++ b/plugins/codebase-health/README.md @@ -62,7 +62,7 @@ repo's tracked config, resolved additively across three layers: 1. `~/.claude/codebase-health.md`. User-global base (optional) 2. `.claude/codebase-health.md`. Team config (tracked) -3. `.claude/codebase-health.local.md`. Personal overlay (gitignored) +3. `.claude/codebase-health.local.md`. Personal override (gitignored) Each dimension declares `primary-sources` (globs where claims live), `verification-sources` (globs where claims are checked against ground truth), and `example-claims` (concrete `{ claim, verify-via }` @@ -79,7 +79,7 @@ hardcodes a repo's layout. /codebase-health:setup apply # interview + write .claude/codebase-health.md (re-runnable) ``` -Add the recursive `.claude/**/*.local.*` line to your `.gitignore` so personal overlays stay out of version control while +Add the recursive `.claude/**/*.local.*` line to your `.gitignore` so personal overrides stay out of version control while team config stays tracked. ## Consumer conventions diff --git a/plugins/codebase-health/skills/audit/SKILL.md b/plugins/codebase-health/skills/audit/SKILL.md index 057436c1409..0ea9341d30b 100644 --- a/plugins/codebase-health/skills/audit/SKILL.md +++ b/plugins/codebase-health/skills/audit/SKILL.md @@ -113,7 +113,7 @@ pass). Come from the consuming repo's tracked config, resolved additively across 1. `~/.claude/codebase-health.md` (user-global, optional) 2. `.claude/codebase-health.md` (team, tracked) -3. `.claude/codebase-health.local.md` (personal overlay, gitignored) +3. `.claude/codebase-health.local.md` (personal override, gitignored) The four bundled dimensions are `documentation`, `configuration`, `code-quality`, and `architecture`; the config may tune their globs, remove a dimension, or add custom ones. @@ -122,7 +122,7 @@ The four bundled dimensions are `documentation`, `configuration`, `code-quality` later layer's `primary-sources` and `verification-sources` globs UNION with the earlier layer's (not replace), and `example-claims` concatenate with duplicate `claim` text collapsed. A layer removes an inherited dimension by declaring it with empty source lists (an explicit opt-out), never by silent -omission. This keeps a personal overlay purely additive to team config unless it deliberately zeroes a +omission. This keeps a personal override purely additive to team config unless it deliberately zeroes a dimension out. Settle targets by this ladder: diff --git a/plugins/codebase-health/skills/audit/evals/evals.json b/plugins/codebase-health/skills/audit/evals/evals.json index 7a948630d09..877d5f1c7c6 100644 --- a/plugins/codebase-health/skills/audit/evals/evals.json +++ b/plugins/codebase-health/skills/audit/evals/evals.json @@ -45,7 +45,7 @@ "id": 3, "name": "resolve-config-or-infer-and-persist", "prompt": "/codebase-health:audit --docs-only", - "expected_output": "Resolves the tracked audit config (.claude/codebase-health.md and overlays) for the documentation dimension. When it is present, uses its primary/verification sources; when absent, infers targets from the repo layout and offers to persist the inference via /codebase-health:setup rather than hardcoding a layout.", + "expected_output": "Resolves the tracked audit config (.claude/codebase-health.md and its other layers) for the documentation dimension. When it is present, uses its primary/verification sources; when absent, infers targets from the repo layout and offers to persist the inference via /codebase-health:setup rather than hardcoding a layout.", "files": [], "expectations": [ "Attempts to resolve the tracked audit config before enumerating targets, rather than assuming a fixed repo layout", diff --git a/plugins/codebase-health/skills/audit/reference/audit-checklist.md b/plugins/codebase-health/skills/audit/reference/audit-checklist.md index 82a0d1541f8..9f817100b79 100644 --- a/plugins/codebase-health/skills/audit/reference/audit-checklist.md +++ b/plugins/codebase-health/skills/audit/reference/audit-checklist.md @@ -6,7 +6,7 @@ guide helps you recognize claims you might otherwise skip. The four bundled dimensions (documentation / configuration / code-quality / architecture) are universal. Per-dimension `primary-sources`, `verification-sources`, and `example-claims` for THIS -repo come from the resolved audit config (`.claude/codebase-health.md` and its overlays). +repo come from the resolved audit config (`.claude/codebase-health.md` and its other layers). ## Documentation Claims to Verify diff --git a/plugins/codebase-health/skills/setup/SKILL.md b/plugins/codebase-health/skills/setup/SKILL.md index da3e285b2ef..dddd0c3644a 100644 --- a/plugins/codebase-health/skills/setup/SKILL.md +++ b/plugins/codebase-health/skills/setup/SKILL.md @@ -19,11 +19,11 @@ updates rather than overwriting blind. ## The config merge model The audit config resolves as an additive merge of the documented layers. User-global -(`~/.claude/codebase-health.md`) → team (`.claude/codebase-health.md`) → local overlay +(`~/.claude/codebase-health.md`) → team (`.claude/codebase-health.md`) → personal override (`.claude/codebase-health.local.md`), where a later layer's globs union with (not replace) the earlier layer's and example-claims concatenate, **except** that a later layer declaring a dimension with empty source lists is an explicit opt-out that *removes* that inherited dimension. This skill -writes only the **team** file; changes to a higher overlay are the user's to make. +writes only the **team** file; changes to a higher layer are the user's to make. ## `check` (read-only) @@ -38,12 +38,12 @@ FAIL. Modify nothing, and do NOT run an audit. That is `/codebase-health:audit`. than presenting the team file alone as the effective config. 2. **Dimension source lists**. For each dimension present in the team file, its declared source lists parse and name real paths/globs. A dimension whose source list is malformed or fails to parse is - FAIL, naming it. A dimension deliberately zeroed (empty source lists) by an overlay is INFO (an opt-out), + FAIL, naming it. A dimension deliberately zeroed (empty source lists) by a personal override or user-global layer is INFO (an opt-out), reported as removed, not broken. 3. **Tracked, not ignored**, a present team file must be committed to be team-shared: run `git check-ignore -v .claude/codebase-health.md`; a non-empty result is FAIL with the matching - pattern. The `.local.md` overlay is expected to be ignored. INFO, not FAIL. -4. **Overlay divergence**. INFO: when a local or user-global overlay changes the team file's effect + pattern. The `.local.md` personal override is expected to be ignored. INFO, not FAIL. +4. **Personal override divergence**. INFO: when a personal override or user-global layer changes the team file's effect (adds globs, or opts a dimension out with empty source lists), say so explicitly, since `apply` writes only the team file. @@ -53,9 +53,9 @@ Run `check`, then interview and write the config. Proceed non-interactively wher the repo make the values unambiguous; ask only where a dimension's targets genuinely need the user. 1. **Start from the effective config `check` just reported.** This step writes only the *team* file, - so name what a higher overlay contributes. When a local or user-global opt-out zeroes a dimension, - a team-scope re-enable will not restore it on this machine, because the overlay keeps removing it; - prompt the user to remove or update the opt-out in that overlay too. The interview proposes + so name what a higher layer contributes. When a local or user-global opt-out zeroes a dimension, + a team-scope re-enable will not restore it on this machine, because that layer keeps removing it; + prompt the user to remove or update the opt-out in that layer too. The interview proposes changes against that baseline, and nothing is dropped without the user confirming. 2. **Explore the repo to draft defaults.** Before asking anything, infer candidates: - **documentation** primary-sources: doc directories (`docs/`, `README.md`), agent-instruction @@ -85,10 +85,10 @@ the repo make the values unambiguous; ask only where a dimension's targets genui pattern and offer to fix `.gitignore` before reporting success) AND `git ls-files --error-unmatch .claude/codebase-health.md` exits 0 (non-zero means un-ignored but still untracked, the guaranteed state right after a fresh write, so report "written but - untracked: commit it to share with the team", never success). Then **offer the overlay convention**: personal overrides go in + untracked: commit it to share with the team", never success). Then **offer the personal override convention**: personal overrides go in `.claude/codebase-health.local.md`; recommend the consumer add the recursive `.claude/**/*.local.*` line to `.gitignore` if not already covered. A user-global base at `~/.claude/codebase-health.md` is also honored. Layers - resolve user-global → team → local overlay, additively. + resolve user-global → team → personal override, additively. Re-running `apply` after everything passes changes nothing and reports "already configured". diff --git a/plugins/codebase-health/skills/setup/evals/evals.json b/plugins/codebase-health/skills/setup/evals/evals.json index 45a19266dfb..d0c65b97f82 100644 --- a/plugins/codebase-health/skills/setup/evals/evals.json +++ b/plugins/codebase-health/skills/setup/evals/evals.json @@ -29,11 +29,11 @@ "id": 3, "name": "writes-tracked-config-not-plugin-dir", "prompt": "/codebase-health:setup apply\n\nJust write a sensible default config for this repo.", - "expected_output": "Materializes the config at the consumer's tracked .claude/codebase-health.md, confirms it is tracked (not gitignored), and offers the recursive .claude/**/*.local.* overlay/gitignore convention. It never writes configuration into the plugin directory or a plugin data directory.", + "expected_output": "Materializes the config at the consumer's tracked .claude/codebase-health.md, confirms it is tracked (not gitignored), and offers the recursive .claude/**/*.local.* personal override/gitignore convention. It never writes configuration into the plugin directory or a plugin data directory.", "files": [], "expectations": [ "Writes the config to the consumer's tracked .claude/codebase-health.md", - "Offers the recursive .claude/**/*.local.* personal-overlay and gitignore convention", + "Offers the recursive .claude/**/*.local.* personal override and gitignore convention", "Does not write configuration into the plugin directory or plugin data directory" ] } diff --git a/plugins/codebase-health/skills/setup/templates/config-template.md b/plugins/codebase-health/skills/setup/templates/config-template.md index 5ae8bdc5ad9..3056bb27e6e 100644 --- a/plugins/codebase-health/skills/setup/templates/config-template.md +++ b/plugins/codebase-health/skills/setup/templates/config-template.md @@ -3,8 +3,8 @@ Tracked audit-dimension configuration for the codebase-health plugin. Each `##` section below is one audit dimension. The four bundled dimensions (`documentation`, `configuration`, `code-quality`, `architecture`) may be tuned or removed here; new `##` sections add custom dimensions. Personal -overlays go in `.claude/codebase-health.local.md` (gitignored); a user-global base may live at -`~/.claude/codebase-health.md`. Layers resolve user-global → this file → local overlay, additively. +overrides go in `.claude/codebase-health.local.md` (gitignored); a user-global base may live at +`~/.claude/codebase-health.md`. Layers resolve user-global → this file → personal override, additively. Each dimension carries: diff --git a/plugins/discipline/reference/config.md b/plugins/discipline/reference/config.md index 74636545d1d..9241b5a5394 100644 --- a/plugins/discipline/reference/config.md +++ b/plugins/discipline/reference/config.md @@ -17,7 +17,7 @@ Decision 8): | 1 | per user | the plugin's `userConfig` option of the same name | | 2 | repository | `docs/conventions/discipline.yaml` at the repository root, tracked, validated by [`schemas/discipline.schema.json`](../schemas/discipline.schema.json) | -No `~/.claude` file, `.claude/` file or local overlay sets these keys. The reading skill resolves +No `~/.claude` file, `.claude/` file or personal override sets these keys. The reading skill resolves each key in its own text, with no reader script, and reports one line naming the value and the layer that supplied it. `/discipline:setup apply =` writes the repository file after validating it against the schema, and shows the diff and asks before it changes an existing one. diff --git a/plugins/discipline/skills/setup/SKILL.md b/plugins/discipline/skills/setup/SKILL.md index f3106c6ace2..8f72c562600 100644 --- a/plugins/discipline/skills/setup/SKILL.md +++ b/plugins/discipline/skills/setup/SKILL.md @@ -166,7 +166,7 @@ Official contract: /.claude/improvement.md` and silently reports an absent config. Anchor at the root in every self-contained shell call. - **The team file is the only thing `apply` writes.** An effective value contributed by the - overlay or user-global layer cannot be changed here; say which layer owns it instead of + personal override or user-global layer cannot be changed here; say which layer owns it instead of writing a team value that the higher layer will keep overriding. - **No git verdict on the user-global layer.** `git check-ignore` against a path outside the worktree is meaningless (or confidently wrong when the home directory is itself a repo); the tracked/ignored probes apply to the two in-repo layers only. diff --git a/plugins/improvement/skills/setup/evals/evals.json b/plugins/improvement/skills/setup/evals/evals.json index 69925d5f7e9..bf76415c1f2 100644 --- a/plugins/improvement/skills/setup/evals/evals.json +++ b/plugins/improvement/skills/setup/evals/evals.json @@ -5,7 +5,7 @@ "id": 1, "name": "check-reports-effective-config-read-only", "prompt": "/improvement:setup", - "expected_output": "Defaults to the check action: reads every accessible layer of the .claude/improvement.md cascade (user-global, team, local overlay), reports which layers exist and the effective merged configuration (churn window, exclusion patterns, Tier 2 evidence_sources entries) with per-layer provenance, and modifies nothing. All layers absent is reported as INFO (bundled defaults; Tier 2 is an evidence gap), never as a failure. It does not run an improvement scan.", + "expected_output": "Defaults to the check action: reads every accessible layer of the .claude/improvement.md cascade (user-global, team, personal override), reports which layers exist and the effective merged configuration (churn window, exclusion patterns, Tier 2 evidence_sources entries) with per-layer provenance, and modifies nothing. All layers absent is reported as INFO (bundled defaults; Tier 2 is an evidence gap), never as a failure. It does not run an improvement scan.", "files": [], "expectations": [ "No argument routes to the read-only check action — does NOT error or start writing config", @@ -18,26 +18,26 @@ "id": 2, "name": "apply-interviews-and-writes-team-file-only", "prompt": "/improvement:setup apply", - "expected_output": "Runs the check first, presents the effective merged baseline across layers, drafts defaults from the repo (churn exclusions from generated/build trees, evidence-source candidates from configured MCP servers), then interviews the user one decision at a time before writing. Writes only the team .claude/improvement.md in the reference/config.md file format, never a vendor-specific source the user did not declare, and never the user-global layer or the .local.md overlay.", + "expected_output": "Runs the check first, presents the effective merged baseline across layers, drafts defaults from the repo (churn exclusions from generated/build trees, evidence-source candidates from configured MCP servers), then interviews the user one decision at a time before writing. Writes only the team .claude/improvement.md in the reference/config.md file format, never a vendor-specific source the user did not declare, and never the user-global layer or the .local.md personal override.", "files": [], "expectations": [ "Reads the effective config across all layers and presents it before proposing changes", "Drafts churn-exclusion and evidence-source candidates from the repo and configured MCP servers before asking", "Interviews with recommendations rather than writing blind; nothing dropped without confirmation", - "Writes only the team .claude/improvement.md — never the user-global file or the .local.md overlay", + "Writes only the team .claude/improvement.md — never the user-global file or the .local.md personal override", "Does not invent or hardcode a vendor-specific telemetry source the user did not declare" ] }, { "id": 3, - "name": "verifies-tracked-and-offers-overlay-convention", + "name": "verifies-tracked-and-offers-personal-override-convention", "prompt": "/improvement:setup apply\n\nJust write a sensible config for this repo — churn defaults are fine, no telemetry sources yet.", - "expected_output": "Writes the team .claude/improvement.md with only the confirmed churn keys, states that Tier 2 stays a declared evidence gap, re-runs BOTH check probes (git check-ignore for not-ignored AND git ls-files --error-unmatch for tracked — flagging the written-but-untracked state as 'commit it', never success), and offers the recursive .claude/**/*.local.* gitignore line for the personal overlay without editing the consumer's .gitignore itself.", + "expected_output": "Writes the team .claude/improvement.md with only the confirmed churn keys, states that Tier 2 stays a declared evidence gap, re-runs BOTH check probes (git check-ignore for not-ignored AND git ls-files --error-unmatch for tracked — flagging the written-but-untracked state as 'commit it', never success), and offers the recursive .claude/**/*.local.* gitignore line for the personal override without editing the consumer's .gitignore itself.", "files": [], "expectations": [ "Accepts 'no telemetry sources' as a valid outcome — writes churn keys only and says Tier 2 remains an evidence gap", "Verifies the written team file with both probes: not gitignored (git check-ignore) AND actually tracked (git ls-files --error-unmatch), flagging untracked as commit-needed rather than success", - "Recommends the recursive .claude/**/*.local.* gitignore line for the overlay", + "Recommends the recursive .claude/**/*.local.* gitignore line for the personal override", "Does not edit the consumer's .gitignore or write into the plugin/plugin-data directories" ] } diff --git a/plugins/multi-agent/README.md b/plugins/multi-agent/README.md index 72e6138a94f..dcc17c5ded0 100644 --- a/plugins/multi-agent/README.md +++ b/plugins/multi-agent/README.md @@ -12,7 +12,7 @@ answer. | `/multi-agent:assess ` | Returns `workflow`, `subagent` or `single` with a one-line reason. Checks whether workflows are available in this session first; when they are not, `workflow` becomes `subagent`. Writes nothing. | | `/multi-agent:route [code\|research\|mechanical] [session=]` | Resolves the role map through the config cascade and prints it as fenced JSON: per role a `single` and a `fanout` variant, each with model, effort and the layer that supplied them, and each value's basis (upstream statement, judgment, or a config layer). `all` is the map a workflow reads from `args.roles`. | | `/multi-agent:audit-defaults [\|fanout\|repo]` | Fetches each bundled default's pointer and reports which defaults have drifted, whose pointer does not state its value, or whose recheck trigger has fired, with evidence and a proposed diff. `repo` checks the repository's own model, effort, subagent and workflow statements against upstream instead. Runs the `multi-agent:drift-audit` workflow when workflows are available. Never edits a file. | -| `/multi-agent:setup [check\|apply]` | `check` prints the resolved map and whether the personal overlay is gitignored. `apply` previews a change to the user, team or local layer as a diff, writes it on your explicit yes, and shows the map before and after. Run by hand only. | +| `/multi-agent:setup [check\|apply]` | `check` prints the resolved map and whether the personal override is gitignored. `apply` previews a change to the user, team or local layer as a diff, writes it on your explicit yes, and shows the map before and after. Run by hand only. | ## How a workflow uses it @@ -132,7 +132,7 @@ and its evidence: [`reference/routing-rubric.md`](reference/routing-rubric.md). ## Configuration One surface, layered user-global (`~/.claude/multi-agent.yaml`), team -(`docs/conventions/multi-agent.yaml`) and a gitignored overlay +(`docs/conventions/multi-agent.yaml`) and a gitignored personal override (`.claude/multi-agent.local.yaml`), each overriding the bundled defaults per key. `/multi-agent:setup` writes any of the three. Keys, values and layering: [`reference/config.md`](reference/config.md). diff --git a/plugins/multi-agent/probes/route.json b/plugins/multi-agent/probes/route.json index 24c3c1918c2..79b80a4823f 100644 --- a/plugins/multi-agent/probes/route.json +++ b/plugins/multi-agent/probes/route.json @@ -116,7 +116,7 @@ "id": "neg-val-04", "split": "validation", "expect_trigger": false, - "request": "Check whether my personal overlay file is gitignored." + "request": "Check whether my personal override file is gitignored." } ] } diff --git a/plugins/multi-agent/reference/config.md b/plugins/multi-agent/reference/config.md index 749bde42a35..e6d9995b436 100644 --- a/plugins/multi-agent/reference/config.md +++ b/plugins/multi-agent/reference/config.md @@ -13,9 +13,9 @@ this page owns the keys. | Bundled | `${CLAUDE_PLUGIN_ROOT}/reference/defaults.yaml` | | User-global | `~/.claude/multi-agent.yaml` | | Team | `/multi-agent.yaml`, `` being the convention home the repository binds, else `docs/conventions` | -| Personal overlay | `.claude/multi-agent.local.yaml` (gitignored) | +| Personal override | `.claude/multi-agent.local.yaml` (gitignored) | -Later layers win per key. Team and overlay are read only when the root is a +Later layers win per key. Team and personal override are read only when the root is a repository that is neither `$HOME` nor an ancestor of it (`lib/config-root.sh`). The team file is validated by [`schemas/multi-agent.schema.json`](../schemas/multi-agent.schema.json). The @@ -45,7 +45,7 @@ and an explicit yes. Roles are `orchestrator`, `worker`, `verifier` and `retrieval`. A layer naming another role or key is reported and ignored, and so is a workload no layer declares. A declaration in any layer covers values set in every layer, so a -team layer can declare a workload that a personal overlay tunes. A full model id +team layer can declare a workload that a personal override tunes. A full model id (`claude-opus-5-5`) is rejected, so a role map stays portable across providers. Whether a role may name `haiku` is decided in [`routing-rubric.md`](routing-rubric.md); the resolver accepts it and adds a @@ -144,7 +144,7 @@ value or a forced model resolves). Under an Opus session `opus` and `inherit` name the same model, so the guard changes nothing there. Setting `fanout.frontier_guard: false` is an explicit opt-in to frontier -fan-outs. Set it on the layer whose scope you mean: the overlay for one +fan-outs. Set it on the layer whose scope you mean: the personal override for one checkout, the user-global file for every repository on one machine. ## Example team file diff --git a/plugins/multi-agent/scripts/resolve-roles.sh b/plugins/multi-agent/scripts/resolve-roles.sh index 322f997d99f..c056a179791 100755 --- a/plugins/multi-agent/scripts/resolve-roles.sh +++ b/plugins/multi-agent/scripts/resolve-roles.sh @@ -2,13 +2,14 @@ # resolve-roles.sh: resolve the multi-agent role map through the config cascade. # # LAYERS, bottom to top, each overriding per key: -# bundled reference/defaults.yaml -# user-global /.claude/multi-agent.yaml -# team /multi-agent.yaml ( is the convention home the -# repository binds, else docs/conventions) -# overlay /.claude/multi-agent.local.yaml -# Team and overlay apply only when lib/config-root.sh classifies as -# `repo`; a team or overlay path that is the user-global file is read once. +# bundled reference/defaults.yaml +# user-global /.claude/multi-agent.yaml +# team /multi-agent.yaml ( is the convention home +# the repository binds, else docs/conventions) +# personal-override /.claude/multi-agent.local.yaml +# Team and personal override apply only when lib/config-root.sh classifies +# as `repo`; a team or personal override path that is the user-global +# file is read once. # A layer that does not parse, or declares a schema other than 1, is skipped # and named in `notes`. A key with a value outside its allowed set is rejected # and named; the layer below keeps the key. Keys and values: reference/config.md. @@ -300,20 +301,20 @@ if [[ -f "$SCRIPT_DIR/../lib/resolve-convention-home.sh" ]]; then home_out="$(bash "$SCRIPT_DIR/../lib/resolve-convention-home.sh" --root "$ROOT" 2>/dev/null)" && CONVENTION_HOME="$home_out" fi TEAM_CONCERN="$ROOT/$CONVENTION_HOME/multi-agent.yaml" -OVERLAY="$ROOT/.claude/multi-agent.local.yaml" +PERSONAL_OVERRIDE="$ROOT/.claude/multi-agent.local.yaml" if [[ "$ROOT_CLASS" != repo ]]; then layer_state team "$TEAM_CONCERN" "not-applicable ($ROOT_CLASS root)" - layer_state overlay "$OVERLAY" "not-applicable ($ROOT_CLASS root)" + layer_state personal-override "$PERSONAL_OVERRIDE" "not-applicable ($ROOT_CLASS root)" else if [[ -f "$TEAM_CONCERN" ]]; then read_layer team "$TEAM_CONCERN" else layer_state team "$TEAM_CONCERN" absent fi - if [[ -f "$OVERLAY" ]] && ! config_root_paths_same "$OVERLAY" "$USER_LAYER"; then - read_layer overlay "$OVERLAY" + if [[ -f "$PERSONAL_OVERRIDE" ]] && ! config_root_paths_same "$PERSONAL_OVERRIDE" "$USER_LAYER"; then + read_layer personal-override "$PERSONAL_OVERRIDE" else - layer_state overlay "$OVERLAY" absent + layer_state personal-override "$PERSONAL_OVERRIDE" absent fi fi diff --git a/plugins/multi-agent/scripts/resolve-roles.test.sh b/plugins/multi-agent/scripts/resolve-roles.test.sh index ee1238ba456..99285db409e 100755 --- a/plugins/multi-agent/scripts/resolve-roles.test.sh +++ b/plugins/multi-agent/scripts/resolve-roles.test.sh @@ -126,7 +126,7 @@ fixture crosslayer printf 'schema: 1\nworkloads:\n deep: true\n' >"$T/crosslayer/home/.claude/multi-agent.yaml" printf 'schema: 1\nroles:\n verifier:\n workloads:\n deep:\n effort: max\n' >"$T/crosslayer/repo/.claude/multi-agent.local.yaml" out="$(run crosslayer verifier --session-model opus --workload deep)" -assert_contains "user-global declaration, overlay value" "$out" '"single":{"model":"inherit","omit_model":true,"effort":"max"' +assert_contains "user-global declaration, personal override value" "$out" '"single":{"model":"inherit","omit_model":true,"effort":"max"' assert_lacks "declared across layers: no undeclared note" "$out" 'undeclared' # An undeclared workload is reported and ignored, and cannot be resolved. @@ -194,8 +194,8 @@ fixture layered printf 'schema: 1\nroles:\n worker:\n effort: high\n' >"$T/layered/home/.claude/multi-agent.yaml" printf 'schema: 1\nroles:\n worker:\n model: sonnet\n' >"$T/layered/repo/.claude/multi-agent.local.yaml" out="$(run layered worker --session-model opus)" -assert_contains "user-global effort and overlay model merge per key" "$out" '"single":{"model":"sonnet","omit_model":false,"effort":"high"' -assert_contains "source names the layer per value" "$out" '"source":{"model":"overlay","effort":"user-global"}' +assert_contains "user-global effort and personal override model merge per key" "$out" '"single":{"model":"sonnet","omit_model":false,"effort":"high"' +assert_contains "source names the layer per value" "$out" '"source":{"model":"personal-override","effort":"user-global"}' # Turning the guard off is the explicit opt-in to frontier fan-outs. fixture optout @@ -218,7 +218,7 @@ out="$(run malformed worker --session-model opus)" assert_eq "malformed layer still exits 0" 0 "$?" assert_contains "malformed layer is named with its line" "$out" 'team layer skipped:' assert_contains "malformed layer state is skipped" "$out" '"layer":"team"' -assert_contains "the overlay still applies" "$out" '"effort":"low"' +assert_contains "the personal override still applies" "$out" '"effort":"low"' # Wrong schema skips the layer. fixture schema @@ -254,13 +254,13 @@ out="$(run frontiercomma worker --session-model opus)" assert_contains "trailing comma in frontier rejected" "$out" "frontier rejected: 'opus,'" assert_contains "rejected frontier keeps the bundled list" "$out" '"session_frontier":false' -# Team and overlay are not read at a home root. +# Team and personal override are not read at a home root. mkdir -p "$T/homeroot/.claude" git -C "$T/homeroot" init -q printf 'schema: 1\nroles:\n worker:\n effort: low\n' >"$T/homeroot/.claude/multi-agent.local.yaml" out="$("$SUT" --root "$T/homeroot" --home "$T/homeroot" worker 2>/dev/null)" -assert_contains "home root: overlay not applicable" "$out" 'not-applicable (home root)' -assert_contains "home root: overlay value not applied" "$out" '"effort":"medium"' +assert_contains "home root: personal override not applicable" "$out" 'not-applicable (home root)' +assert_contains "home root: personal override value not applied" "$out" '"effort":"medium"' # A role resolving to haiku is not blocked, but gains a note pointing at the rubric. fixture haikurole diff --git a/plugins/multi-agent/skills/route/SKILL.md b/plugins/multi-agent/skills/route/SKILL.md index fd16b81f215..498bc956771 100644 --- a/plugins/multi-agent/skills/route/SKILL.md +++ b/plugins/multi-agent/skills/route/SKILL.md @@ -1,5 +1,5 @@ --- -description: "Model and effort per agent role (orchestrator, worker, verifier, retrieval) for a multi-agent run, resolved through the bundled defaults and the user, team and overlay config layers into fenced JSON with single-agent and fan-out variants and the layer behind each value; fan-out stays off frontier models unless config opts in. Use when asked 'which model for the subagents', 'route the roles', 'what effort should the workers use', 'roles for the workflow args', 'model routing' or 'is fan-out on Fable', or before a skill launches a workflow that takes args.roles." +description: "Model and effort per agent role (orchestrator, worker, verifier, retrieval) for a multi-agent run, resolved through the bundled defaults and the user, team and personal override config layers into fenced JSON with single-agent and fan-out variants and the layer behind each value; fan-out stays off frontier models unless config opts in. Use when asked 'which model for the subagents', 'route the roles', 'what effort should the workers use', 'roles for the workflow args', 'model routing' or 'is fan-out on Fable', or before a skill launches a workflow that takes args.roles." argument-hint: " [workload] [session=]" user-invocable: true disable-model-invocation: false @@ -117,5 +117,5 @@ Rechecks a default that looks wrong for the current models. worker on `sonnet`; `code` keeps the role's model, and any other workload key comes from a config layer. A caller that wants the session model for mechanical work sets `roles.worker.workloads.mechanical.model: inherit`. -- Team and overlay layers resolve against the repository root of the working +- Team and personal override layers resolve against the repository root of the working directory. Inside a second worktree, run from that worktree. diff --git a/plugins/multi-agent/skills/route/evals/evals.json b/plugins/multi-agent/skills/route/evals/evals.json index a7eed384b6c..58f436b36d1 100644 --- a/plugins/multi-agent/skills/route/evals/evals.json +++ b/plugins/multi-agent/skills/route/evals/evals.json @@ -33,9 +33,9 @@ "narration": true, "expected_output": "Runs route.sh worker research with the session alias. The worker resolves to effort medium, its own effort, since no layer sets a research workload; the notes say roles.worker.model was rejected because a full model id is not an alias, and the model comes from the layer below.", "expectations": [ - "The worker's model is reported as supplied by the layer below the overlay, not the overlay", + "The worker's model is reported as supplied by the layer below the personal override, not the personal override", "The rejected key is reported from notes, with the reason that only aliases are accepted", - "The skill does not edit the overlay file" + "The skill does not edit the personal override file" ] }, { diff --git a/plugins/multi-agent/skills/setup/SKILL.md b/plugins/multi-agent/skills/setup/SKILL.md index 2a04fe47004..e5f5d37ea39 100644 --- a/plugins/multi-agent/skills/setup/SKILL.md +++ b/plugins/multi-agent/skills/setup/SKILL.md @@ -37,7 +37,7 @@ Show: 2. the `layers` rows (read, absent, skipped, or not applicable at a home or non-repository root) and every entry of `notes` as written; each note (a skipped layer, a rejected value, an ignored key) is a finding to report; -3. the overlay row: PASS when `.claude/multi-agent.local.yaml` is gitignored, +3. the `personal-override` row: PASS when `.claude/multi-agent.local.yaml` is gitignored, else WARN with the recommended line `.claude/**/*.local.*`. Recommend the line; do not edit `.gitignore`; 4. each `WARN team:` row: a retired team file (the config block in diff --git a/plugins/multi-agent/skills/setup/evals/evals.json b/plugins/multi-agent/skills/setup/evals/evals.json index c1b53a7149e..18d823c8ee8 100644 --- a/plugins/multi-agent/skills/setup/evals/evals.json +++ b/plugins/multi-agent/skills/setup/evals/evals.json @@ -6,11 +6,11 @@ "name": "check-is-read-only", "prompt": "/multi-agent:setup check. This session runs on Opus.", "narration": true, - "expected_output": "Runs scripts/setup.sh check session=opus and shows one line per role with the layer behind each value, the layers rows, every note, and the overlay gitignore row. Recommends the `.claude/**/*.local.*` line when the row is WARN. Writes no file.", + "expected_output": "Runs scripts/setup.sh check session=opus and shows one line per role with the layer behind each value, the layers rows, every note, and the personal override gitignore row. Recommends the `.claude/**/*.local.*` line when the row is WARN. Writes no file.", "expectations": [ "The bundled setup.sh is run with check and session=opus", "Each role line names the single and fan-out model and effort, with inherit written as `inherit: omit the model option`", - "The overlay gitignore row is reported, and .gitignore is not edited", + "The personal override gitignore row is reported, and .gitignore is not edited", "No configuration file is written" ] }, diff --git a/plugins/multi-agent/skills/setup/scripts/setup.sh b/plugins/multi-agent/skills/setup/scripts/setup.sh index 004655aeed8..54db8b5c63b 100755 --- a/plugins/multi-agent/skills/setup/scripts/setup.sh +++ b/plugins/multi-agent/skills/setup/scripts/setup.sh @@ -3,7 +3,7 @@ # # setup.sh check [session=] # The resolved map through the route wrapper (JSON on stdout, notes on -# stderr), then one row on the personal overlay's gitignore state and a +# stderr), then one row on the personal override's gitignore state and a # WARN row for each retired team file still present. # setup.sh apply --layer user|team|local [--write] = ... # Merges the pairs into that layer's existing keys. `=` with no @@ -73,11 +73,11 @@ LOCATE=(--root "$ROOT" --home "$HOME_DIR") check() { "$ROUTE" all "${SESSION[@]+"${SESSION[@]}"}" "${LOCATE[@]}" || return if [[ "$CLASS" != repo ]]; then - printf 'INFO overlay: not applicable at a %s root\n' "$CLASS" + printf 'INFO personal-override: not applicable at a %s root\n' "$CLASS" elif git -C "$ROOT" check-ignore -q .claude/multi-agent.local.yaml; then - printf 'PASS overlay: .claude/multi-agent.local.yaml is gitignored\n' + printf 'PASS personal-override: .claude/multi-agent.local.yaml is gitignored\n' else - printf 'WARN overlay: .claude/multi-agent.local.yaml is not gitignored; the recommended line is .claude/**/*.local.*\n' + printf 'WARN personal-override: .claude/multi-agent.local.yaml is not gitignored; the recommended line is .claude/**/*.local.*\n' fi if [[ "$CLASS" == repo ]]; then retired_rows; fi } @@ -235,7 +235,7 @@ apply() { if ! "$RESOLVER" --root "$tmp/repo" --home "$tmp/home" all >/dev/null 2>"$tmp/notes" || [[ -s "$tmp/notes" ]]; then printf 'setup: the layer would not resolve cleanly; nothing written:\n' >&2 - sed 's/^resolve-roles: overlay/ candidate/; s/^resolve-roles: / /' "$tmp/notes" >&2 + sed 's/^resolve-roles: personal-override/ candidate/; s/^resolve-roles: / /' "$tmp/notes" >&2 exit 1 fi diff --git a/plugins/multi-agent/skills/setup/scripts/setup.test.sh b/plugins/multi-agent/skills/setup/scripts/setup.test.sh index 9d845372b6d..60f4a20fa47 100755 --- a/plugins/multi-agent/skills/setup/scripts/setup.test.sh +++ b/plugins/multi-agent/skills/setup/scripts/setup.test.sh @@ -52,7 +52,7 @@ run() { # run fixture dry out="$(run dry apply --layer local roles.worker.effort=high)" -assert_contains "dry run names the overlay path" "$out" "would write: $T/dry/repo/.claude/multi-agent.local.yaml" +assert_contains "dry run names the personal override path" "$out" "would write: $T/dry/repo/.claude/multi-agent.local.yaml" assert_contains "dry run shows the new key in a diff" "$out" '+ effort: high' state=absent [[ -e "$T/dry/repo/.claude/multi-agent.local.yaml" ]] && state=present @@ -65,9 +65,9 @@ assert_contains "write reads the stored value back" "$out" ' fanout.frontier_gu assert_eq "written file is the rendered subset" "$(cat "$T/local/repo/.claude/multi-agent.local.yaml")" \ $'schema: 1\nfanout:\n frontier_guard: false\nroles:\n worker:\n effort: high' out="$(run local check session=fable)" -assert_contains "check shows the overlay as the source" "$out" '"source":{"model":"bundled","effort":"overlay"}' +assert_contains "check shows the personal override as the source" "$out" '"source":{"model":"bundled","effort":"personal-override"}' assert_contains "check shows the guard off: fan-out inherits under fable" "$out" '"fanout":{"model":"inherit","omit_model":true,"effort":"high","guarded":false}' -assert_contains "check warns when the overlay is not ignored" "$out" 'WARN overlay' +assert_contains "check warns when the personal override is not ignored" "$out" 'WARN personal-override' out="$(run local apply --layer local --write roles.worker.effort=high)" assert_eq "rerun with the same value is unchanged" "unchanged: $T/local/repo/.claude/multi-agent.local.yaml" "$out" run local apply --layer local --write fanout.frontier_guard= >/dev/null diff --git a/plugins/review/agents/ecosystem-specialist.md b/plugins/review/agents/ecosystem-specialist.md index c0f3633feb1..51df70dc116 100644 --- a/plugins/review/agents/ecosystem-specialist.md +++ b/plugins/review/agents/ecosystem-specialist.md @@ -14,14 +14,14 @@ The changed files, build and test scripts, ecosystem configs, and tool output yo ## Before running 1. **Identify the change set**: `git status --porcelain` plus `PR_BASE="$(gh pr list --head "$(git branch --show-current)" --json baseRefName -q '.[0].baseRefName' 2>/dev/null)"; BASE=""; [ -n "$PR_BASE" ] && git fetch origin "$PR_BASE" 2>/dev/null && BASE="$(git rev-parse FETCH_HEAD 2>/dev/null)"; MB="$(git merge-base "${BASE:-origin/${PR_BASE:-HEAD}}" HEAD 2>/dev/null || { D="$(git ls-remote --symref --end-of-options origin HEAD 2>/dev/null | awk '/^ref:/{sub(/refs\/heads\//,"",$2); print $2; exit}')"; [ -n "$D" ] && git fetch origin "$D" 2>/dev/null && git merge-base FETCH_HEAD HEAD 2>/dev/null; } || git merge-base origin/main HEAD 2>/dev/null)"; if [ -n "$MB" ]; then git diff --stat "$MB"; else echo UNRESOLVED-BASE; git diff --stat HEAD; fi`. The PR's real base wins when one exists (fetched first; shallow clones may lack it). `UNRESOLVED-BASE` means no base resolved and only uncommitted changes are listed: say so first, and never report an empty list under it as an empty change set. -2. **Detect affected ecosystems** from changed file paths (e.g. `.cs`/`.csproj` → .NET, `.py`/`pyproject.toml` → Python, `.ts`/`.js`/`package.json` → JS/TS, `.sh` → shell, `.ps1` → PowerShell, `.go` → Go, `.rs` → Rust). Then, for each ecosystem that has a consumer `.claude/ecosystems/.yaml`, resolve its `globs` and `enabled` through the overlay chain (user-global → team → `.local.`, key-by-key) and use the resolved `globs`, which are authoritative over these built-in heuristics, to re-classify the changed files, dropping any ecosystem whose resolved `enabled` is `false` (a deliberately disabled toolchain), even when its globs match. +2. **Detect affected ecosystems** from changed file paths (e.g. `.cs`/`.csproj` → .NET, `.py`/`pyproject.toml` → Python, `.ts`/`.js`/`package.json` → JS/TS, `.sh` → shell, `.ps1` → PowerShell, `.go` → Go, `.rs` → Rust). Then, for each ecosystem that has a consumer `.claude/ecosystems/.yaml`, resolve its `globs` and `enabled` through the config cascade (user-global → team → `.local.`, key-by-key) and use the resolved `globs`, which are authoritative over these built-in heuristics, to re-classify the changed files, dropping any ecosystem whose resolved `enabled` is `false` (a deliberately disabled toolchain), even when its globs match. 3. **Resolve each detected ecosystem's command truth.** Build/test/check commands come from the first source that exists, per "Command-truth resolution" below. Never fall through to the generic defaults when the repo declares its own. ## Command-truth resolution Resolve each ecosystem's build / test / check command from the first source that exists, in order: -1. **`.claude/ecosystems/.yaml` in the consumer repo, when present, is authoritative.** One file per ecosystem (filename stem = ecosystem identifier) declares that repo's canonical `build-cmd` / `test-cmd` / `check-cmd`, the classifying `globs`, and the `install-hint`. Resolution is **per command key**: a present non-null command is authoritative. Use it verbatim, first binding the contract placeholders (``, ``, ``, `$REPO_ROOT`) to this run's values (a command like `shellcheck -x ` must have `` expanded, never handed to the shell literally). A key set to `null` means that phase does not apply, so skip it with no fall-through. An **omitted** key is simply undeclared here, so fall through to rung 2, then rung 3, for that one command. Layer a `~/.claude/ecosystems/.yaml` user-global base and a `.local.` overlay key-by-key when they exist. Governing contract and schema: [`docs/contracts/ecosystem-commands/README.md`](https://raw.githubusercontent.com/melodic-software/claude-code-plugins/main/docs/contracts/ecosystem-commands/README.md). +1. **`.claude/ecosystems/.yaml` in the consumer repo, when present, is authoritative.** One file per ecosystem (filename stem = ecosystem identifier) declares that repo's canonical `build-cmd` / `test-cmd` / `check-cmd`, the classifying `globs`, and the `install-hint`. Resolution is **per command key**: a present non-null command is authoritative. Use it verbatim, first binding the contract placeholders (``, ``, ``, `$REPO_ROOT`) to this run's values (a command like `shellcheck -x ` must have `` expanded, never handed to the shell literally). A key set to `null` means that phase does not apply, so skip it with no fall-through. An **omitted** key is simply undeclared here, so fall through to rung 2, then rung 3, for that one command. Layer a `~/.claude/ecosystems/.yaml` user-global base and a `.local.` personal override key-by-key when they exist. Governing contract and schema: [`docs/contracts/ecosystem-commands/README.md`](https://raw.githubusercontent.com/melodic-software/claude-code-plugins/main/docs/contracts/ecosystem-commands/README.md). 2. **Otherwise, the consuming project's documented conventions.** Read the project rules, contributing docs, `package.json` scripts, `Makefile`/`justfile` targets, and CI workflow files. Projects often encode their canonical build/test/lint commands, with flags and gotchas. Use those verbatim. 3. **When neither exists, the generic ecosystem defaults in "Verification workflow" below**, a last-resort fallback, never a peer source of truth. diff --git a/plugins/review/reference/config.md b/plugins/review/reference/config.md index c37d7a90b84..49772f7d2e4 100644 --- a/plugins/review/reference/config.md +++ b/plugins/review/reference/config.md @@ -4,7 +4,7 @@ The review plugin's keys, one row each, with the skill that reads each one. A ke user through the plugin's `userConfig` option of the same name and per repository in `docs/conventions/review.yaml`, validated by [`schemas/review.schema.json`](../schemas/review.schema.json). No `~/.claude` file, `.claude/` -file or local overlay sets these keys. `/review:setup apply` writes the repository file. +file or personal override sets these keys. `/review:setup apply` writes the repository file. | Key | Values | Default | Reader | |---|---|---|---| diff --git a/plugins/review/skills/explain-change/scripts/digest-policy.mjs b/plugins/review/skills/explain-change/scripts/digest-policy.mjs index 0572aaab271..6d8201af005 100755 --- a/plugins/review/skills/explain-change/scripts/digest-policy.mjs +++ b/plugins/review/skills/explain-change/scripts/digest-policy.mjs @@ -106,19 +106,19 @@ function baseReader(root, baseOid, warnings) { return { ref: baseOid, root, read: (rel) => gitOut(root, ["show", `${baseOid}:${rel}`]) }; } -/** Team and overlay apply only inside a working tree that is not home or above it. */ -function layerPaths(root, userFile, teamFiles, overlayFile) { +/** Team and personal override apply only inside a working tree that is not home or above it. */ +function layerPaths(root, userFile, teamFiles, personalOverrideFile) { const home = real(homedir()); const user = join(home, ".claude", userFile); if (!root || within(home, real(root)) || !git(root, ["rev-parse", "--is-inside-work-tree"])) { - return { user, root: null, team: [], overlay: null }; + return { user, root: null, team: [], personalOverride: null }; } const notUser = (p) => real(p) !== real(user); return { user, root, team: teamFiles.filter((f) => notUser(join(root, f))), - overlay: notUser(join(root, overlayFile)) ? join(root, overlayFile) : null, + personalOverride: notUser(join(root, personalOverrideFile)) ? join(root, personalOverrideFile) : null, }; } @@ -262,9 +262,10 @@ export function resolveDigestConfig(baseOid) { const team = readTeamDigest(base, TEAM_YAML, "docs/conventions/review-digest.md", ".claude/review-digest.json", warnings); if (team) layers.push({ label: "team", path: `${base.ref}:${team.path}`, value: team.value }); } - if (paths.overlay && existsSync(paths.overlay) && personalOverrideApplies(paths.root, paths.overlay, warnings)) { - const value = readJsonLayer(paths.overlay, "overlay", warnings); - if (value) layers.push({ label: "overlay", path: paths.overlay, value }); + const personal = paths.personalOverride; + if (personal && existsSync(personal) && personalOverrideApplies(paths.root, personal, warnings)) { + const value = readJsonLayer(personal, "personal override", warnings); + if (value) layers.push({ label: "personal override", path: personal, value }); } } for (const layer of layers) { diff --git a/plugins/review/skills/setup/SKILL.md b/plugins/review/skills/setup/SKILL.md index 4c7d74219ba..9b4720ca288 100644 --- a/plugins/review/skills/setup/SKILL.md +++ b/plugins/review/skills/setup/SKILL.md @@ -115,7 +115,7 @@ a regular file). `apply` is the fix. 4. **The convention-home offer.** When the repository's `AGENTS.md` or `CLAUDE.md` binds no convention home, the script prints an offer: with the operator's confirmation it adds a convention-home pointer region to that instruction file (creating `AGENTS.md` when neither - exists or `CLAUDE.md` only imports it) and the overlay ignore line + exists or `CLAUDE.md` only imports it) and the personal override ignore line `docs/conventions/**/*.local.*` to `.gitignore`, the only files `apply` writes outside `docs/conventions/`. It prints the offer at the end of an exit 0 run and below the diff of an exit 3 run, so show the operator stdout on exit 0 too. Ask whether to add the region and the @@ -142,7 +142,7 @@ Plugin-side notes on top of the binding's procedure: index rows. Converting it requires the binding's explicit-confirmation gate. 2. **Bootstrap writes** (interactive, user-accepted. No silent writes): the skeleton index with its `standards-contract` frontmatter at the binding's version, and the setup-owned - `/.gitignore` containing `*.local.md` (the personal-overlay ignore). Write + `/.gitignore` containing `*.local.md` (the personal override ignore). Write `.claude/standards.yaml` only when the user relocates the root from the documented default. After a bootstrap write, run the tracked-file pair on each written team file: `git check-ignore -v` reports no match (a match is FAIL with the pattern) AND @@ -157,7 +157,7 @@ Plugin-side notes on top of the binding's procedure: ## Output -A written (or confirmed-healthy) standards index and its overlay `.gitignore`, a one-line summary +A written (or confirmed-healthy) standards index and its `.gitignore` for personal overrides, a one-line summary of the effective standards root, the row-validation result, and how to re-run this setup to reconfigure or migrate. When repository settings were written: the diff shown, the written path, the value `check` reads back, and whether the file is tracked. diff --git a/plugins/review/skills/setup/evals/evals.json b/plugins/review/skills/setup/evals/evals.json index a3e7e9973cc..5123a7b5d68 100644 --- a/plugins/review/skills/setup/evals/evals.json +++ b/plugins/review/skills/setup/evals/evals.json @@ -19,7 +19,7 @@ "id": 2, "name": "second-run-is-a-no-op", "prompt": "/review:setup\n\nThis repo already has docs/standards/README.md with standards-contract frontmatter at the binding's current version, valid row paths, and a docs/standards/.gitignore containing *.local.md from a previous run.", - "expected_output": "Finds a conforming index at the binding's contract version via the presence test, validates the row paths, and short-circuits: reports the index healthy and proposes no changes — a second run produces no diff. No re-interview, no rewrite of the index or the overlay .gitignore, and no migration offer since the versions match.", + "expected_output": "Finds a conforming index at the binding's contract version via the presence test, validates the row paths, and short-circuits: reports the index healthy and proposes no changes — a second run produces no diff. No re-interview, no rewrite of the index or the .gitignore for personal overrides, and no migration offer since the versions match.", "files": [], "expectations": [ "Recognizes the conforming current-version index and proposes no changes (second run yields no diff)", diff --git a/plugins/review/tests/explain-change.test.mjs b/plugins/review/tests/explain-change.test.mjs index 235dd59208d..4528463e094 100644 --- a/plugins/review/tests/explain-change.test.mjs +++ b/plugins/review/tests/explain-change.test.mjs @@ -245,7 +245,7 @@ describe("the team YAML file against the old locations", () => { assert.equal(result.config.digest_policy.source, "default", "the old block's other keys are not mixed in"); assert.deepEqual(result.triggers, ["files"]); }); - test("the YAML file, a user key and the overlay resolve key by key", () => { + test("the YAML file, a user key and the personal override resolve key by key", () => { writeFileSync(join(home, ".claude/review-digest.json"), '{"max_files": 9, "opt_in_label": "mine"}'); const result = run(facts); assert.equal(result.config.max_files.value, 1); @@ -290,7 +290,7 @@ describe("cascade layers resolve through the CLI", () => { assert.equal(result.config.max_files.source, "default"); assert.deepEqual(at(result.medium), DEFAULT_MEDIUM); }); - test("user-global, then the tracked team docs block, then the overlay, key by key", () => { + test("user-global, then the tracked team docs block, then the personal override, key by key", () => { writeFileSync(join(home, ".claude/review-digest.json"), '{"max_files": 1, "opt_in_label": "mine"}'); let result = run(facts); assert.deepEqual(result.triggers, ["files"]); @@ -312,7 +312,7 @@ describe("cascade layers resolve through the CLI", () => { writeFileSync(join(repo, ".claude/review-digest.local.json"), '{"digest_policy": "offer"}'); result = run(facts); assert.equal(result.action, "offer"); - assert.match(result.policy.source, /^overlay /); + assert.match(result.policy.source, /^personal override /); assert.deepEqual(result.warnings, []); }); test("the argument beats every layer", () => { @@ -325,7 +325,7 @@ describe("cascade layers resolve through the CLI", () => { writeFileSync(join(home, ".claude/review-digest.json"), '{"max_files": -1, "palette": "red"}'); const result = run(facts); const warnings = result.warnings.join("\n"); - assert.match(warnings, /overlay .*layer ignored/); + assert.match(warnings, /personal override .*layer ignored/); assert.match(warnings, /invalid max_files/); assert.match(warnings, /unknown key palette is inert/); assert.equal(result.config.max_files.value, 2); @@ -388,7 +388,7 @@ describe("a pull request branch cannot silence its own digest", () => { const run = runPolicy(home, repo); const facts = { ...quiet, files: [{ path: "docs/conventions/review-digest.md" }], baseRefOid: "MAIN" }; - test("team config comes from the base ref, a tracked overlay is ignored, and a config path offers", () => { + test("team config comes from the base ref, a tracked personal override is ignored, and a config path offers", () => { const result = run(facts); assert.deepEqual(result.policy, { value: "offer", source: "default" }); assert.equal(result.action, "offer"); @@ -412,8 +412,8 @@ describe("a pull request branch cannot silence its own digest", () => { }); }); -describe("overlay guards", () => { - const overlay = '{"max_files": 0}'; +describe("personal override guards", () => { + const personalOverride = '{"max_files": 0}'; const setup = (name) => { const home = join(scratch, `home-${name}`); const repo = join(scratch, `repo-${name}`); @@ -423,24 +423,24 @@ describe("overlay guards", () => { }; const facts = { ...quiet, baseRefOid: "MAIN" }; - test("an untracked overlay that is not gitignored applies, with a warning", () => { + test("an untracked personal override that is not gitignored applies, with a warning", () => { const { repo, run } = setup("unignored"); mkdirSync(join(repo, ".claude")); - writeFileSync(join(repo, ".claude/review-digest.local.json"), overlay); + writeFileSync(join(repo, ".claude/review-digest.local.json"), personalOverride); const result = run(facts); - assert.match(result.config.max_files.source, /^overlay /); + assert.match(result.config.max_files.source, /^personal override /); assert.match(result.warnings.join("\n"), /not gitignored, so it can reach team history$/m); }); - test("a symlinked overlay file is refused", () => { + test("a symlinked personal override file is refused", () => { const { repo, run } = setup("linkfile"); mkdirSync(join(repo, ".claude")); - writeFileSync(join(scratch, "outside.json"), overlay); + writeFileSync(join(scratch, "outside.json"), personalOverride); symlinkSync(join(scratch, "outside.json"), join(repo, ".claude/review-digest.local.json")); const result = run(facts); assert.equal(result.config.max_files.source, "default"); assert.match(result.warnings.join("\n"), /symlink.*layer ignored/); }); - test("a .claude submodule holding the overlay is refused and .gitmodules fires risk-path", () => { + test("a .claude submodule holding the personal override is refused and .gitmodules fires risk-path", () => { const { repo, git, commit, run } = setup("submodule"); const sub = join(scratch, "sub"); mkdirSync(sub); @@ -457,11 +457,11 @@ describe("overlay guards", () => { assert.equal(result.action, "offer"); assert.match(result.warnings.join("\n"), /submodule or tracked entry; layer ignored/); }); - test("a tracked symlinked .claude pointing at a dir holding the overlay is refused", () => { + test("a tracked symlinked .claude pointing at a dir holding the personal override is refused", () => { const { repo, git, commit, run } = setup("linkdir"); const evil = join(scratch, "evil"); mkdirSync(evil); - writeFileSync(join(evil, "review-digest.local.json"), overlay); + writeFileSync(join(evil, "review-digest.local.json"), personalOverride); symlinkSync(evil, join(repo, ".claude")); git("add", ".claude"); commit(); @@ -471,7 +471,7 @@ describe("overlay guards", () => { }); }); -describe("a case-variant overlay a pull request tracks is ignored and fires risk-path", () => { +describe("a case-variant personal override a pull request tracks is ignored and fires risk-path", () => { // Simulates a case-insensitive filesystem on any host: the tracked entry differs // only in case from the untracked, gitignored file the script reads. const home = join(scratch, "home-case"); @@ -492,7 +492,7 @@ describe("a case-variant overlay a pull request tracks is ignored and fires risk writeFileSync(join(repo, "docs/conventions/rendered-views.local.yaml"), "medium: hosted\n"); const run = runPolicy(home, repo); - test("the overlay is treated as tracked and a case-variant config path offers", () => { + test("the personal override is treated as tracked and a case-variant config path offers", () => { const result = run({ ...quiet, files: [{ path: "./.claude//Review-Digest.local.json" }], baseRefOid: "MAIN" }); assert.deepEqual(result.policy, { value: "offer", source: "default" }); assert.equal(result.action, "offer"); diff --git a/scripts/test_check_vocabulary.py b/scripts/test_check_vocabulary.py index 94c51ab63aa..215ad8c15af 100755 --- a/scripts/test_check_vocabulary.py +++ b/scripts/test_check_vocabulary.py @@ -137,6 +137,7 @@ def path(sense: str, glob: str, file: str, line: str): path("overlay", "plugins/gaming/**", "plugins/gaming/README.md", OVERLAY_LINE), path("overlay", "plugins/songwriting/skills/**", "plugins/songwriting/skills/x/SKILL.md", OVERLAY_LINE), phrase("overlay", r"\bagentic[- ]overlays?\b", "The agentic overlay layers on the harness."), + phrase("overlay", r"\bbatch[- ]overlays?\b", "The batch overlay layers on the declared tiers."), path("overlay", "plugins/testing/skills/audit/evals/judge-calibration/**", "plugins/testing/skills/audit/evals/judge-calibration/case.md", OVERLAY_LINE), phrase("overlay", r"\b(css|ui|video|image|visual|modal)[- ]overlays?\b", "The modal overlay layers on the page."), phrase("overlay", r"\badr/[0-9]{4}-[a-z0-9-]*overlay[a-z0-9-]*\.md\b", "Read [ADR 0015](../../adr/0015-bind-the-tracker-with-a-personal-overlay.md) on the layer."), diff --git a/scripts/vocabulary-senses.json b/scripts/vocabulary-senses.json index 3d8ca4156b7..afef0332b79 100644 --- a/scripts/vocabulary-senses.json +++ b/scripts/vocabulary-senses.json @@ -68,6 +68,7 @@ {"path": "plugins/gaming/**", "reason": "visual overlays in gaming"}, {"path": "plugins/songwriting/skills/**", "reason": "songwriting's research text uses overlay in its musical sense"}, {"phrase": "\\bagentic[- ]overlays?\\b", "reason": "developer-experience's agentic overlay harness is not the config cascade's personal layer"}, + {"phrase": "\\bbatch[- ]overlays?\\b", "reason": "discipline's batch overlay (the batch_* userConfig options) changes sweep-all's member set, not the config cascade's personal layer"}, {"path": "plugins/testing/skills/audit/evals/judge-calibration/**", "reason": "testing's judge-calibration fixtures are verbatim copies of other plugins' code"}, {"phrase": "\\b(css|ui|video|image|visual|modal)[- ]overlays?\\b", "reason": "a visual overlay, not the config cascade's personal layer"}, {"phrase": "\\badr/[0-9]{4}-[a-z0-9-]*overlay[a-z0-9-]*\\.md\\b", "reason": "a link to an ADR file, whose name is history like the docs/adr/ files this checker excludes"} From 1ba0fa776b89f72bcc48c844f8965dad4e3ffa90 Mon Sep 17 00:00:00 2001 From: "melodic-automation-lanes[bot]" <337595936+melodic-automation-lanes[bot]@users.noreply.github.com> Date: Wed, 4 Nov 2026 20:06:24 +0000 Subject: [PATCH 2/4] Address review feedback on work-resolve-issue/issue-13191-41889151702-1 Lane-Activity: pr-unblock/address-feedback Lane-Thread: PRRT_kwDOTCGFQM6zxtvA Lane-Thread: PRRT_kwDOTCGFQM6zxtvm --- .../work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md | 4 ++-- docs/conventions/review-digest.md | 2 +- scripts/test_check_vocabulary.py | 1 - scripts/vocabulary-senses.json | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md b/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md index ed20f7bfb26..dc387bd16c4 100644 --- a/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md +++ b/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md @@ -5,5 +5,5 @@ bump: patch ### Changed - The config reference and `setup` now call the config cascade's personal layer the personal - override ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). The - `sweep-all` batch overlay, the `batch_*` options, keeps its name. Behavior is unchanged. + override ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). + Behavior is unchanged. diff --git a/docs/conventions/review-digest.md b/docs/conventions/review-digest.md index 8c2d07468e3..c089262aa93 100644 --- a/docs/conventions/review-digest.md +++ b/docs/conventions/review-digest.md @@ -58,7 +58,7 @@ an earlier one key by key: 3. personal override `.claude/review-digest.local.json` The result names the layer that supplied each value (`team :`, `user-global `, -`personal override `, or `default`). Quote glob values in the YAML file (`"**/hooks/**"`), since a plain +`personal-override `, or `default`). Quote glob values in the YAML file (`"**/hooks/**"`), since a plain `*` opens an alias. The team layer, and the rendered-views team file, are read from the pull request's base commit diff --git a/scripts/test_check_vocabulary.py b/scripts/test_check_vocabulary.py index 02bfa095846..502e02e2453 100755 --- a/scripts/test_check_vocabulary.py +++ b/scripts/test_check_vocabulary.py @@ -138,7 +138,6 @@ def path(sense: str, glob: str, file: str, line: str): path("overlay", "plugins/gaming/**", "plugins/gaming/README.md", OVERLAY_LINE), path("overlay", "plugins/songwriting/skills/**", "plugins/songwriting/skills/x/SKILL.md", OVERLAY_LINE), phrase("overlay", r"\bagentic[- ]overlays?\b", "The agentic overlay layers on the harness."), - phrase("overlay", r"\bbatch[- ]overlays?\b", "The batch overlay layers on the declared tiers."), path("overlay", "plugins/testing/skills/audit/evals/judge-calibration/**", "plugins/testing/skills/audit/evals/judge-calibration/case.md", OVERLAY_LINE), phrase("overlay", r"\b(css|ui|video|image|visual|modal)[- ]overlays?\b", "The modal overlay layers on the page."), phrase("overlay", r"\badr/[0-9]{4}-[a-z0-9-]*overlay[a-z0-9-]*\.md\b", "Read [ADR 0015](../../adr/0015-bind-the-tracker-with-a-personal-overlay.md) on the layer."), diff --git a/scripts/vocabulary-senses.json b/scripts/vocabulary-senses.json index 0ab2e060282..4f5bd28ee2e 100644 --- a/scripts/vocabulary-senses.json +++ b/scripts/vocabulary-senses.json @@ -69,7 +69,6 @@ {"path": "plugins/gaming/**", "reason": "visual overlays in gaming"}, {"path": "plugins/songwriting/skills/**", "reason": "songwriting's research text uses overlay in its musical sense"}, {"phrase": "\\bagentic[- ]overlays?\\b", "reason": "developer-experience's agentic overlay harness is not the config cascade's personal layer"}, - {"phrase": "\\bbatch[- ]overlays?\\b", "reason": "discipline's batch overlay (the batch_* userConfig options) changes sweep-all's member set, not the config cascade's personal layer"}, {"path": "plugins/testing/skills/audit/evals/judge-calibration/**", "reason": "testing's judge-calibration fixtures are verbatim copies of other plugins' code"}, {"phrase": "\\b(css|ui|video|image|visual|modal)[- ]overlays?\\b", "reason": "a visual overlay, not the config cascade's personal layer"}, {"phrase": "\\badr/[0-9]{4}-[a-z0-9-]*overlay[a-z0-9-]*\\.md\\b", "reason": "a link to an ADR file, whose name is history like the docs/adr/ files this checker excludes"} From 76520ff79cfd003f9900b37461f2179f03f01eb0 Mon Sep 17 00:00:00 2001 From: "melodic-automation-lanes[bot]" <337595936+melodic-automation-lanes[bot]@users.noreply.github.com> Date: Wed, 4 Nov 2026 20:17:35 +0000 Subject: [PATCH 3/4] Address review feedback on work-resolve-issue/issue-13191-41889151702-1 Lane-Activity: pr-unblock/address-feedback Lane-Thread: VNOTE_2 --- .../work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md b/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md index e8998f43e7d..2f684f469a1 100644 --- a/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md +++ b/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md @@ -7,5 +7,5 @@ bump: minor - The config cascade's personal layer is now called the personal override ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). `/review:explain-change`'s digest policy labels a value from `.claude/review-digest.local.json` - `personal override ` in its `source` and warnings, and `setup`, the config reference and + `personal-override ` in its `source` and warnings, and `setup`, the config reference and the `ecosystem-specialist` agent use the new name. From 26ee192b7266057bd695d0ec63d402ca40100bfc Mon Sep 17 00:00:00 2001 From: "melodic-automation-lanes[bot]" <337595936+melodic-automation-lanes[bot]@users.noreply.github.com> Date: Wed, 4 Nov 2026 20:29:14 +0000 Subject: [PATCH 4/4] Address review feedback on work-resolve-issue/issue-13191-41889151702-1 Lane-Activity: pr-unblock/address-feedback Lane-Thread: VNOTE_1 Lane-Thread: VNOTE_2 Lane-Thread: VNOTE_3 Lane-Thread: VNOTE_4 Lane-Thread: VNOTE_5 --- ...resolve-issue-issue-13191-41889151702-1-4462e5d9.md | 9 ++------- ...resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md | 9 ++------- ...resolve-issue-issue-13191-41889151702-1-5b3e7136.md | 9 ++------- ...resolve-issue-issue-13191-41889151702-1-e2d96514.md | 9 ++------- ...resolve-issue-issue-13191-41889151702-1-d3d8b935.md | 8 ++------ ...resolve-issue-issue-13191-41889151702-1-ff586768.md | 9 ++------- ...resolve-issue-issue-13191-41889151702-1-aeca15ab.md | 10 ++-------- ...resolve-issue-issue-13191-41889151702-1-0a4305b0.md | 10 ++-------- 8 files changed, 16 insertions(+), 57 deletions(-) diff --git a/.changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md b/.changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md index 48e2963275c..f5bcf97567e 100644 --- a/.changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md +++ b/.changes/attribution/work-resolve-issue-issue-13191-41889151702-1-4462e5d9.md @@ -1,10 +1,5 @@ --- -bump: patch +bump: none --- -### Changed - -- The setup skill, its evals, `retirements.yaml` and the audit scripts' comments and test names now - call the config cascade's personal layer, `/attribution.local.yaml`, the personal override - ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). Behavior is - unchanged. +No release needed: this pull request changes no attribution file. The personal override rename (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment. diff --git a/.changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md b/.changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md index b8178e26528..7269865be00 100644 --- a/.changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md +++ b/.changes/bugs/work-resolve-issue-issue-13191-41889151702-1-9d2b4dc9.md @@ -1,10 +1,5 @@ --- -bump: patch +bump: none --- -### Changed - -- The config reference, README and the `scan`, `write` and `setup` text now call the config - cascade's personal layer, `.claude/bugs.local.md`, the personal override, and the consumer - gotchas block `concat-gotchas.sh` prints heads that layer `#### personal override (...)` - ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). +No release needed: this pull request changes no bugs file. The personal override rename (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment. diff --git a/.changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md b/.changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md index 9de9ac399cf..dc8152f362d 100644 --- a/.changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md +++ b/.changes/code-metrics/work-resolve-issue-issue-13191-41889151702-1-5b3e7136.md @@ -1,10 +1,5 @@ --- -bump: patch +bump: none --- -### Changed - -- The config reference, README, skill text and `setup check` rows now call the config cascade's - personal layer, `.claude/code-metrics.local.yaml`, the personal override - ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). The resolver's - layer label stays `local`, so its output is unchanged. +No release needed: this pull request changes no code-metrics file. The personal override rename (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment. diff --git a/.changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md b/.changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md index 792ad68ff0a..f84241aea6d 100644 --- a/.changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md +++ b/.changes/codebase-health/work-resolve-issue-issue-13191-41889151702-1-e2d96514.md @@ -1,10 +1,5 @@ --- -bump: patch +bump: none --- -### Changed - -- The README, the config template and the `audit` and `setup` text and evals now call the config - cascade's personal layer, `.claude/codebase-health.local.md`, the personal override - ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). Behavior is - unchanged. +No release needed: this pull request changes no codebase-health file. The personal override rename (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment. diff --git a/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md b/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md index dc387bd16c4..4d0cebc90f4 100644 --- a/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md +++ b/.changes/discipline/work-resolve-issue-issue-13191-41889151702-1-d3d8b935.md @@ -1,9 +1,5 @@ --- -bump: patch +bump: none --- -### Changed - -- The config reference and `setup` now call the config cascade's personal layer the personal - override ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). - Behavior is unchanged. +No release needed: this pull request changes no discipline file. The personal override rename (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment. diff --git a/.changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md b/.changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md index 37cd6351ae8..44f1ed5690c 100644 --- a/.changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md +++ b/.changes/improvement/work-resolve-issue-issue-13191-41889151702-1-ff586768.md @@ -1,10 +1,5 @@ --- -bump: patch +bump: none --- -### Changed - -- The config reference, README, `find` and `setup` text and the setup evals now call the config - cascade's personal layer, `.claude/improvement.local.md`, the personal override - ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). Behavior is - unchanged. +No release needed: this pull request changes no improvement file. The personal override rename (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment. diff --git a/.changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md b/.changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md index 728ff4f9afa..bc63d49387c 100644 --- a/.changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md +++ b/.changes/multi-agent/work-resolve-issue-issue-13191-41889151702-1-aeca15ab.md @@ -1,11 +1,5 @@ --- -bump: minor +bump: none --- -### Changed - -- The config cascade's personal layer, `.claude/multi-agent.local.yaml`, is now called the personal - override ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). - `resolve-roles.sh` names it `personal-override` in each role's `source`, in `layers` and in - `notes`, and `/multi-agent:setup check` prints its gitignore row as `personal-override`. A - caller that matched the old label must match the new one. +No release needed: this pull request changes no multi-agent file. The `personal-override` label in resolve-roles.sh and setup.sh (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment. diff --git a/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md b/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md index 2f684f469a1..c9523f31141 100644 --- a/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md +++ b/.changes/review/work-resolve-issue-issue-13191-41889151702-1-0a4305b0.md @@ -1,11 +1,5 @@ --- -bump: minor +bump: none --- -### Changed - -- The config cascade's personal layer is now called the personal override - ([#13191](https://github.com/melodic-software/claude-code-plugins/issues/13191)). - `/review:explain-change`'s digest policy labels a value from `.claude/review-digest.local.json` - `personal-override ` in its `source` and warnings, and `setup`, the config reference and - the `ecosystem-specialist` agent use the new name. +No release needed: this pull request changes no review plugin file. The `personal-override ` source label in digest-policy.mjs (#13191) is already on the base and recorded by its chore-13191-personal-override-eight fragment.