Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/claude-config/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "claude-config",
"version": "0.35.3",
"version": "0.35.4",
"description": "Eight 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 (which settings scopes exist and what rules each one holds — managed policy, user-global, project, local, and the pre-v2.1.211 start-directory copy), audit-instructions (locally-owned instruction surfaces vs current model capability — proposes removals/rewrites of instructions the model no longer needs, and detects 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",
Expand Down
29 changes: 29 additions & 0 deletions plugins/claude-config/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,35 @@
All notable changes to the `claude-config` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.35.4]

### Fixed

- **`audit-pass` no longer asks the model to evaluate a placeholder it never sees.** Its default
`target` read "`${CLAUDE_PROJECT_DIR}` when set, else `git rev-parse --show-toplevel`". That
placeholder is substituted inline in skill content before the file reaches the model, so the literal
token is never visible and "when set" is a test about a value that has already been resolved. The
default is now stated in prose — the project root Claude Code resolved for this session, else
`git rev-parse --show-toplevel` — with the prohibition itself written out so the shape does not come
back. **This was a contradiction inside one plugin**: #2250 landed exactly this prohibition in
`audit-prompting-postures` while `audit-pass` kept the shape, so two sibling skills disagreed about
the same placeholder.
- **Both instances, not just the filed one.** The report named `SKILL.md:42-43`; the same unevaluable
condition also sat in the non-git refusal ("with no explicit `target` and no
`${CLAUDE_PROJECT_DIR}`"), where it governs the diagnostic path that refusal exists to produce.
Fixing only the cited line would have left the contradiction half-standing while reading as closed.
- **The `{id}` derivation is stated, so a report cannot be written where the next run will not look.**
The skill said `${CLAUDE_PLUGIN_DATA}` resolves to `~/.claude/plugins/data/{id}/` and never said how
`{id}` is formed. Now quoted: the plugin identifier with characters outside `a-z`, `A-Z`, `0-9`, `_`
and `-` replaced by `-`, with the plugins reference's own worked example
(`formatter@my-marketplace` → `formatter-my-marketplace`). A wrong derivation is also how `--resume`
loses a partial.
- **`${CLAUDE_PLUGIN_DATA}` is recorded as absent from the Bash tool's environment.** The export is
documented for "hook processes and … MCP and LSP server subprocesses"; the Bash tool is none of
those, so `echo "$CLAUDE_PLUGIN_DATA"` in a Bash call returns an empty string even though the token
substitutes correctly in skill content. Nothing in the skill said so, which invites exactly that
shell expansion.

## [0.35.3]

### Fixed
Expand Down
16 changes: 12 additions & 4 deletions plugins/claude-config/skills/audit-pass/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,17 @@ Bare invocation reads and reports. `--fix` is the only mutation path, and it is

Parse `$ARGUMENTS`:

- **`target`** — the git repository to audit. Default: `${CLAUDE_PROJECT_DIR}` when set, else
`git rev-parse --show-toplevel`. Never the working directory — a run launched from a subdirectory
must key and scan identically to one launched from the root.
- **`target`** — the git repository to audit. Default: the project root Claude Code resolved for this
session; where no such root is available, `git rev-parse --show-toplevel`. Never the working
directory — a run launched from a subdirectory must key and scan identically to one launched from
the root.

**Do not express this as a condition over `${CLAUDE_PROJECT_DIR}` "when set".** That placeholder is
substituted inline in skill content before this file reaches you, so the literal token is never
visible and the test is not yours to make — you would be deciding "is it set?" about a value that
has already been resolved. Work from what you can observe: the resolved path, or a command you run.
The sibling `audit-prompting-postures` states this same rule where it derives its report path, and
the two skills contradicted each other on it until this was fixed.

**`target` must resolve to the active project root, and a path that does not is refused.** The
delegated interfaces accept no target: `audit-instructions` takes a surface scope and inventories
Expand All @@ -63,7 +71,7 @@ Parse `$ARGUMENTS`:
before Phase 0 does any work, naming the path and the reason, writing nothing.

**Name the directory, not an empty string.** In the case this refusal is *for*, the default
resolution above produces nothing: with no explicit `target` and no `${CLAUDE_PROJECT_DIR}`,
resolution above produces nothing: with no explicit `target` and no session-resolved project root,
`git rev-parse --show-toplevel` fails outside a repository and there is no resolved root to report.
So for the diagnostic only, fall back to the current directory and name **that** — a refusal that
cannot say which path it refused is barely better than a silent one. The fallback is for the message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,24 @@ held.
- The report goes under `${CLAUDE_PLUGIN_DATA}` at `runs/<state-key>/<run-id>/findings.json`, which
survives plugin updates. **State its location precisely, because a whole target class turns on it:**
that directory resolves to `~/.claude/plugins/data/{id}/`
([plugins reference](https://code.claude.com/docs/en/plugins-reference), verified 2026-08-11), and no
documented setting relocates it. It is therefore **outside** a target below `~` and **inside** any
([plugins reference](https://code.claude.com/docs/en/plugins-reference), verified 2026-08-12), and no
documented setting relocates it.

**`{id}` is derived, and deriving it wrong loses the report.** Same page, verbatim: `{id}` is *"the
plugin identifier with characters outside `a-z`, `A-Z`, `0-9`, `_`, and `-` replaced by `-`"*, with
the worked example that a plugin installed as `formatter@my-marketplace` lands in
`~/.claude/plugins/data/formatter-my-marketplace/` — the `@` becomes `-`. A wrong derivation writes
the report where the next run will not look for it, which is also how `--resume` loses a partial.

**`${CLAUDE_PLUGIN_DATA}` is not in the Bash tool's environment — do not try to expand it from a
shell.** The same page scopes the export precisely: *"All three are exported as environment variables
to hook processes and to MCP and LSP server subprocesses."* The Bash tool is none of those. The token
does substitute in **skill content**, which is how a resolved path reaches you in this file, but
`echo "$CLAUDE_PLUGIN_DATA"` inside a Bash call yields an empty string. Use the path already
substituted into the text you are reading, or rebuild it from `~/.claude/plugins/data/` plus the
Comment thread
kyle-sexton marked this conversation as resolved.
mangled identifier above.

It is therefore **outside** a target below `~` and **inside** any
target at or above it. The default path is *usually* outside the scan set and is **not
unconditionally** outside it — a dotfiles repository, or `~` itself, is a target where containment
holds by construction, and the older unconditional claim was false there.
Expand Down
Loading