From 93131988ed8d22c1678c543d86bc8414abd10509 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Tue, 29 Sep 2026 18:14:36 -0400 Subject: [PATCH 1/6] docs(claude-config): route audit --fix through update-config and document auto-mode refusals Refs #5376 Co-Authored-By: Claude Opus 5.5 --- plugins/claude-config/skills/audit/SKILL.md | 18 +++++++++++++++++- .../skills/audit/context/procedures.md | 9 +++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/plugins/claude-config/skills/audit/SKILL.md b/plugins/claude-config/skills/audit/SKILL.md index 4ee492c3f7..4779b0dea0 100644 --- a/plugins/claude-config/skills/audit/SKILL.md +++ b/plugins/claude-config/skills/audit/SKILL.md @@ -319,7 +319,10 @@ environment. For each user-approved fix: -1. Make the edit. Done when the target file carries the change and nothing else in it moved. +1. Make the edit. Route each approved edit to `settings.json`, `settings.local.json`, or `.mcp.json` + through the built-in `update-config` skill, not a direct write. In auto mode a settings edit needs + the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that + fix is the consent. Done when the target file carries the change and nothing else in it moved. 2. Validate with `jq . >/dev/null` after each edit. Done when jq exits 0; on a parse error, revert that edit before touching the next one. 3. Report what changed, as the file, the key, and the before and after values. Done when every @@ -331,6 +334,19 @@ After all fixes: server counts) - Verify all config files are still valid JSON +### Refusals in auto mode + +Two operations are refused in auto mode. Writing the team-layer suppression record +`.claude/audit-pass.md` is refused as `[Instruction Poisoning]`. Re-running `scripts/audit-engine.sh` +for the after-fix summary is refused as `[Self-Modification]`. Never retry around a refusal. Hand the +operator the fallback: they apply the `.claude/audit-pass.md` edit themselves, or run the engine +re-run and paste its output back. Report the before/after comparison from what they return. + +Claim: auto mode refuses those two operations under those two category names. Basis: a +`claude-config:audit@0.48.2` `--fix` run in melodic-software/.github PR #153, Claude Code 2.1.283, +auto mode. As of 2026-09-27. Recheck when a Claude Code release changes auto-mode classifier +categories, or a run where either refusal no longer fires. + ### Fixes the skill can apply Auto-fixable (add `$schema`, **move** deny rules from local to project, plugin orphan-`false` diff --git a/plugins/claude-config/skills/audit/context/procedures.md b/plugins/claude-config/skills/audit/context/procedures.md index d730575320..c8e7e5a508 100644 --- a/plugins/claude-config/skills/audit/context/procedures.md +++ b/plugins/claude-config/skills/audit/context/procedures.md @@ -57,6 +57,15 @@ cat .claude/settings.local.json | tr -d '\r' | jq '.permissions.deny // empty' | Remove orphan plugins (`true`) | No | Yes (user enabled a now-removed plugin, so investigate intent) | | Rename plugins (heuristic match) | No | Yes (verify upstream rename, update key, preserve `enabled` value) | +Each approved edit to `settings.json`, `settings.local.json`, or `.mcp.json` goes through the +built-in `update-config` skill. In auto mode it needs the `[Self-Modification]` handshake: the +classifier asks, and the user's explicit approval of that fix is the consent. Two operations are +refused in auto mode: writing `.claude/audit-pass.md` (`[Instruction Poisoning]`) and re-running +`scripts/audit-engine.sh` for the after-fix summary (`[Self-Modification]`). The fallback for each is +the operator applying the edit or running the re-run and pasting the output back; never retry around +the refusal. The verification record for the category names is in +[SKILL.md](../SKILL.md) "Refusals in auto mode". + **The judgment on a baseline deny addition, stated.** Two things have to be checked before the rule is added, and neither is mechanical: From b8b89b431bafdef6f0c3c9338f3fbc392ed768d2 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Tue, 29 Sep 2026 18:21:24 -0400 Subject: [PATCH 2/6] docs(claude-config): bump to 0.52.2 with changelog for audit --fix routing Co-Authored-By: Claude Opus 5.5 --- plugins/claude-config/.claude-plugin/plugin.json | 2 +- plugins/claude-config/CHANGELOG.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/plugins/claude-config/.claude-plugin/plugin.json b/plugins/claude-config/.claude-plugin/plugin.json index ed64cb65cc..c86285f0db 100644 --- a/plugins/claude-config/.claude-plugin/plugin.json +++ b/plugins/claude-config/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "claude-config", - "version": "0.52.1", + "version": "0.52.2", "description": "Nine configuration-health skills (plus setup) for a repo's Claude Code configuration: audit (settings.json / .mcp.json / hooks / plugins / permissions drift), audit-automation-gaps (evidence-gated verdicts on automation gaps), audit-permission-grants (allow-rule / allowed-tools grants for auto-mode durability and portability), audit-permission-state (the permission rules actually in effect: every settings scope merged with per-rule provenance, what auto mode drops on entry, config written where nothing reads it, and which managed intents are enforced versus loosenable), draft-auto-mode-rules (interview and draft a paste-ready autoMode classifier block; prints only, never writes), audit-instructions (locally-owned instruction surfaces vs current model capability, proposing removals/rewrites of instructions the model no longer needs, and detecting cross-surface instruction conflicts), audit-prompting-postures (the additive lane: posture guidance the prompting guide says a component's purpose needs but the component does not carry), audit-pass (one coordinated, ordered, resumable pass over a named target: three-scope inventory, run-time-derived exclusion set, stable finding identity, suppression memory, resume, one human gate, delegating every check to the plugin that owns it), and unhobble (the empirical bare-baseline experiment: reversibly strip a repo's standing instructions, log real stumbles against the current model, re-add only what evidence earns).", "author": { "name": "Melodic Software", diff --git a/plugins/claude-config/CHANGELOG.md b/plugins/claude-config/CHANGELOG.md index ce70af2645..1cd19c729a 100644 --- a/plugins/claude-config/CHANGELOG.md +++ b/plugins/claude-config/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to the `claude-config` plugin are documented here. Format fo Versions 0.51.8 to 0.51.9 and 0.51.11 to 0.51.14 were reserved by parallel branches and never released. +## [0.52.2] - 2026-09-29 + +### Changed + +- **`audit` / Phase 5:** route approved settings and `.mcp.json` edits through `update-config` with + the `[Self-Modification]` handshake, and document the two auto-mode refusals + (`.claude/audit-pass.md` as `[Instruction Poisoning]`, the `audit-engine.sh` re-run as + `[Self-Modification]`) with the operator fallback + ([#5376](https://github.com/melodic-software/claude-code-plugins/issues/5376)). + ## [0.52.1] - 2026-09-29 ### Changed From d1f2558266791eb8f756c938570c4c94817de8a6 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Tue, 29 Sep 2026 18:40:23 -0400 Subject: [PATCH 3/6] docs(claude-config): keep orphan-false removal on the guarded script and link the refusal basis Co-Authored-By: Claude Opus 5.5 --- plugins/claude-config/skills/audit/SKILL.md | 10 ++++++---- .../claude-config/skills/audit/context/procedures.md | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/claude-config/skills/audit/SKILL.md b/plugins/claude-config/skills/audit/SKILL.md index d47b5c492d..38411982ab 100644 --- a/plugins/claude-config/skills/audit/SKILL.md +++ b/plugins/claude-config/skills/audit/SKILL.md @@ -327,7 +327,9 @@ environment. For each user-approved fix: 1. Make the edit. Route each approved edit to `settings.json`, `settings.local.json`, or `.mcp.json` - through the built-in `update-config` skill, not a direct write. In auto mode a settings edit needs + through the built-in `update-config` skill, not a direct write; the one exception is orphan-`false` + plugin removal, which goes through `scripts/fix-plugin-drift.sh --yes` so its lower-precedence-scope + check still runs. In auto mode a settings edit needs the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that fix is the consent. Done when the target file carries the change and nothing else in it moved. 2. Validate with `jq . >/dev/null` after each edit. Done when jq exits 0; on a parse error, @@ -349,9 +351,9 @@ for the after-fix summary is refused as `[Self-Modification]`. Never retry aroun operator the fallback: they apply the `.claude/audit-pass.md` edit themselves, or run the engine re-run and paste its output back. Report the before/after comparison from what they return. -Claim: auto mode refuses those two operations under those two category names. Basis: a -`claude-config:audit@0.48.2` `--fix` run in melodic-software/.github PR #153, Claude Code 2.1.283, -auto mode. As of 2026-09-27. Recheck when a Claude Code release changes auto-mode classifier +Claim: auto mode refuses those two operations under those two category names. Basis: an empirical +`claude-config:audit@0.48.2` `--fix` run in auto mode on Claude Code 2.1.283, recorded in +[melodic-software/.github PR #153](https://github.com/melodic-software/.github/pull/153). As of 2026-09-27. Recheck when a Claude Code release changes auto-mode classifier categories, or a run where either refusal no longer fires. ### Fixes the skill can apply diff --git a/plugins/claude-config/skills/audit/context/procedures.md b/plugins/claude-config/skills/audit/context/procedures.md index c8e7e5a508..2167c97b0c 100644 --- a/plugins/claude-config/skills/audit/context/procedures.md +++ b/plugins/claude-config/skills/audit/context/procedures.md @@ -58,7 +58,8 @@ cat .claude/settings.local.json | tr -d '\r' | jq '.permissions.deny // empty' | Rename plugins (heuristic match) | No | Yes (verify upstream rename, update key, preserve `enabled` value) | Each approved edit to `settings.json`, `settings.local.json`, or `.mcp.json` goes through the -built-in `update-config` skill. In auto mode it needs the `[Self-Modification]` handshake: the +built-in `update-config` skill, except orphan-`false` plugin removal, which stays on +`scripts/fix-plugin-drift.sh --yes` for its lower-precedence-scope check. In auto mode it needs the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that fix is the consent. Two operations are refused in auto mode: writing `.claude/audit-pass.md` (`[Instruction Poisoning]`) and re-running `scripts/audit-engine.sh` for the after-fix summary (`[Self-Modification]`). The fallback for each is From 5d026c764c0fa06559d499c3e7c38a65f3a6408a Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Wed, 30 Sep 2026 10:18:30 -0400 Subject: [PATCH 4/6] docs(claude-config): keep .mcp.json edits direct in audit Phase 5 update-config covers settings.json and settings.local.json only, so the Phase 5 routing no longer names .mcp.json. Co-Authored-By: Claude Opus 5.5 --- plugins/claude-config/CHANGELOG.md | 2 +- plugins/claude-config/skills/audit/SKILL.md | 4 ++-- plugins/claude-config/skills/audit/context/procedures.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/claude-config/CHANGELOG.md b/plugins/claude-config/CHANGELOG.md index 46777d55a0..93df2ac628 100644 --- a/plugins/claude-config/CHANGELOG.md +++ b/plugins/claude-config/CHANGELOG.md @@ -9,7 +9,7 @@ Versions 0.51.8 to 0.51.9 and 0.51.11 to 0.51.14 were reserved by parallel branc ### Changed -- **`audit` / Phase 5:** route approved settings and `.mcp.json` edits through `update-config` with +- **`audit` / Phase 5:** route approved `settings.json` and `settings.local.json` edits through `update-config` with the `[Self-Modification]` handshake, and document the two auto-mode refusals (`.claude/audit-pass.md` as `[Instruction Poisoning]`, the `audit-engine.sh` re-run as `[Self-Modification]`) with the operator fallback diff --git a/plugins/claude-config/skills/audit/SKILL.md b/plugins/claude-config/skills/audit/SKILL.md index b83b5b8efb..9f7df56e39 100644 --- a/plugins/claude-config/skills/audit/SKILL.md +++ b/plugins/claude-config/skills/audit/SKILL.md @@ -326,8 +326,8 @@ environment. For each user-approved fix: -1. Make the edit. Route each approved edit to `settings.json`, `settings.local.json`, or `.mcp.json` - through the built-in `update-config` skill, not a direct write; the one exception is orphan-`false` +1. Make the edit. Route each approved edit to `settings.json` or `settings.local.json` + through the built-in `update-config` skill, not a direct write (`.mcp.json` is outside its scope; edit it directly); the one exception is orphan-`false` plugin removal, which goes through `scripts/fix-plugin-drift.sh --yes` so its lower-precedence-scope check still runs. In auto mode a settings edit needs the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that fix is the consent. Done when the diff --git a/plugins/claude-config/skills/audit/context/procedures.md b/plugins/claude-config/skills/audit/context/procedures.md index 0244cd480e..710cc17a9d 100644 --- a/plugins/claude-config/skills/audit/context/procedures.md +++ b/plugins/claude-config/skills/audit/context/procedures.md @@ -57,8 +57,8 @@ cat .claude/settings.local.json | tr -d '\r' | jq '.permissions.deny // empty' | Remove orphan plugins (`true`) | No | Yes (user enabled a now-removed plugin, so investigate intent) | | Rename plugins (heuristic match) | No | Yes (verify upstream rename, update key, preserve `enabled` value) | -Each approved edit to `settings.json`, `settings.local.json`, or `.mcp.json` goes through the -built-in `update-config` skill, except orphan-`false` plugin removal, which stays on +Each approved edit to `settings.json` or `settings.local.json` goes through the +built-in `update-config` skill (`.mcp.json` is edited directly), except orphan-`false` plugin removal, which stays on `scripts/fix-plugin-drift.sh --yes` for its lower-precedence-scope check. In auto mode it needs the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that fix is the consent. Two operations are refused in auto mode: writing `.claude/audit-pass.md` From b71b4d3d0d5edd6f1c2f9c997a7a16dddc07b115 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Wed, 30 Sep 2026 10:43:28 -0400 Subject: [PATCH 5/6] docs(claude-config): wrap Phase 5 routing line Co-Authored-By: Claude Opus 5.5 --- plugins/claude-config/skills/audit/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/claude-config/skills/audit/SKILL.md b/plugins/claude-config/skills/audit/SKILL.md index 9f7df56e39..6735ff0f55 100644 --- a/plugins/claude-config/skills/audit/SKILL.md +++ b/plugins/claude-config/skills/audit/SKILL.md @@ -327,8 +327,8 @@ environment. For each user-approved fix: 1. Make the edit. Route each approved edit to `settings.json` or `settings.local.json` - through the built-in `update-config` skill, not a direct write (`.mcp.json` is outside its scope; edit it directly); the one exception is orphan-`false` - plugin removal, which goes through `scripts/fix-plugin-drift.sh --yes` so its lower-precedence-scope + through the built-in `update-config` skill, not a direct write (`.mcp.json` is outside its + scope; edit it directly); the one exception is orphan-`false` plugin removal, which goes through `scripts/fix-plugin-drift.sh --yes` so its lower-precedence-scope check still runs. In auto mode a settings edit needs the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that fix is the consent. Done when the target file carries the change and nothing else in it moved. From 2d98e821bbd9ccb44021fdb3310741b2311a1bcf Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Wed, 30 Sep 2026 11:06:36 -0400 Subject: [PATCH 6/6] docs(claude-config): reconcile Phase 5 routing with the mutation gate Phase 5 routes settings edits through update-config when it resolves and writes directly otherwise; the mutation gate and reference now agree. Co-Authored-By: Claude Opus 5.5 --- plugins/claude-config/skills/audit/SKILL.md | 8 ++++---- plugins/claude-config/skills/audit/context/procedures.md | 3 ++- .../skills/audit/reference/native-update-config.md | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/plugins/claude-config/skills/audit/SKILL.md b/plugins/claude-config/skills/audit/SKILL.md index 6735ff0f55..67dff28234 100644 --- a/plugins/claude-config/skills/audit/SKILL.md +++ b/plugins/claude-config/skills/audit/SKILL.md @@ -327,8 +327,8 @@ environment. For each user-approved fix: 1. Make the edit. Route each approved edit to `settings.json` or `settings.local.json` - through the built-in `update-config` skill, not a direct write (`.mcp.json` is outside its - scope; edit it directly); the one exception is orphan-`false` plugin removal, which goes through `scripts/fix-plugin-drift.sh --yes` so its lower-precedence-scope + through the built-in `update-config` skill when it resolves in this session, and write directly + when it does not (`.mcp.json` is outside its scope; edit it directly); the one exception is orphan-`false` plugin removal, which goes through `scripts/fix-plugin-drift.sh --yes` so its lower-precedence-scope check still runs. In auto mode a settings edit needs the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that fix is the consent. Done when the target file carries the change and nothing else in it moved. @@ -411,8 +411,8 @@ request such as "allow npm commands" or "add a hook that runs when Claude stops" an audit. **Mutation gate.** `update-config` writes settings files as its job. This skill writes only in -Phase 5, under `--fix`, one confirmed fix at a time, and never chains into `update-config` on its -own behalf. +Phase 5, under `--fix`, one confirmed fix at a time; Phase 5 routes each such settings edit through +`update-config`, and outside `--fix` this skill never chains into it on its own behalf. **Availability is never assumed.** Bundled skills are gated by settings such as `disableBundledSkills` and vary by version and host; this section states what to do when the diff --git a/plugins/claude-config/skills/audit/context/procedures.md b/plugins/claude-config/skills/audit/context/procedures.md index 710cc17a9d..933c76f86a 100644 --- a/plugins/claude-config/skills/audit/context/procedures.md +++ b/plugins/claude-config/skills/audit/context/procedures.md @@ -58,7 +58,8 @@ cat .claude/settings.local.json | tr -d '\r' | jq '.permissions.deny // empty' | Rename plugins (heuristic match) | No | Yes (verify upstream rename, update key, preserve `enabled` value) | Each approved edit to `settings.json` or `settings.local.json` goes through the -built-in `update-config` skill (`.mcp.json` is edited directly), except orphan-`false` plugin removal, which stays on +built-in `update-config` skill when it resolves in this session, and directly when it does not +(`.mcp.json` is always edited directly), except orphan-`false` plugin removal, which stays on `scripts/fix-plugin-drift.sh --yes` for its lower-precedence-scope check. In auto mode it needs the `[Self-Modification]` handshake: the classifier asks, and the user's explicit approval of that fix is the consent. Two operations are refused in auto mode: writing `.claude/audit-pass.md` diff --git a/plugins/claude-config/skills/audit/reference/native-update-config.md b/plugins/claude-config/skills/audit/reference/native-update-config.md index a8666d9c36..9224cf535c 100644 --- a/plugins/claude-config/skills/audit/reference/native-update-config.md +++ b/plugins/claude-config/skills/audit/reference/native-update-config.md @@ -15,10 +15,10 @@ in any session. `update-config` makes a change the person asks for. This skill checks what is already configured against current docs and the project's conventions and reports findings; its `--fix` phase applies -only findings it produced, each behind a confirmation. One writes on request, the other judges the -result, so an audit finding the person wants fixed in a way `--fix` does not cover is a natural -request to hand to `update-config`, which the person or the model makes as a new request, not a -chain from this skill. +only findings it produced, each behind a confirmation, and routes those settings edits through +`update-config` when it resolves. One writes on request, the other judges the result, so an audit +finding the person wants fixed in a way `--fix` does not cover is a natural request to hand to +`update-config`, which the person or the model makes as a new request, not a chain from this skill. ## Presence