diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index fe43f86..d5ca000 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "config-audit", "description": "Multi-agent workflow for analyzing, reporting, and optimizing Claude Code configuration across your entire machine", - "version": "5.2.0", + "version": "5.3.0", "author": { "name": "Kjell Tore Guttormsen" }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cd7576..3c0b822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,77 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.3.0] - 2026-06-19 + +### Summary +Permission-rule & plugin-hygiene hardening. Five additive scanner findings extend the existing +DIS, CML, PLH, and feature-gap scanners — no new scanner file, so the scanner count stays **13**. +DIS gains forbidden-parameter and ineffective-allow-wildcard detection; CML mirrors Claude Code's +own 40.0k-char "large CLAUDE.md" startup warning, context-window scaled; PLH flags two plugins +that declare the same name; and feature-gap recommends `disableBundledSkills` under skill-listing +pressure. The cross-plugin command-name finding is reframed from a HIGH conflict to a LOW +ambiguity. Scanner internals only — no command, agent, or output-format changes; `--json` and +`--raw` remain byte-stable. + +### Added +- **DIS forbidden-param rules** — flags `Tool(param:value)` whose key is the tool's own + canonicalizing field (`command`/`file_path`/`path`/`notebook_path`/`url`); Claude Code ignores + these and emits a startup warning. Severity by intent: **deny/ask = false security (medium)**, + **allow = dead config (low)**. Valid forms (`Bash(npm:*)`, `WebFetch(domain:host)`, + `Agent(model:opus)`) are never flagged. Predicate `forbiddenParamRule` in `permission-rules.mjs`. +- **DIS ineffective allow-wildcards + `Tool(*)` deny-all** — flags unanchored tool-name globs in + `permissions.allow` (`*`, `B*`, `mcp__*`) that CC silently skips (low); treats `Tool(*)` as + deny-all (`Bash(*)` ≡ `Bash`) so a bare allow killed by it is reported as dead config. Valid + `mcp____*` is never flagged. +- **CML context-window-scaled char budget** — new `CA-CML` finding mirroring CC's startup warning + *"Large CLAUDE.md will impact performance (X chars > 40.0k)"*. Anchors on the conservative 200k + window; discloses the relaxed ~200,000-char figure at 1M context. Severity **medium** (token + cost). Char-keyed, complementary to the 200/500-line checks. Window constants live in the shared + `scanners/lib/context-window.mjs`. +- **PLH plugin namespace collision** — flags 2+ discovered plugins declaring the same `name` in + `plugin.json`. Namespaces collapse; CC picks an undocumented winner; the loser's + commands/skills/agents go silently unreachable. Severity **medium** (dead config), + `category: 'plugin-hygiene'`, COL-shaped `details.namespaces`. Keys on the declared `name`, not + `basename(dir)`; name-less plugins are excluded. +- **feature-gap `disableBundledSkills` lever** — conditional recommendation to set + `disableBundledSkills` when the active skill listing is over budget; remediation companion to + SKL `CA-SKL-002`. + +### Changed +- **PLH cross-plugin command-name overlap: HIGH → LOW** — reframed from "conflict" to "ambiguity". + Commands are namespaced (`/name:command`) so both stay reachable; only a same-`name` plugin + collision loses components (covered by the new namespace-collision finding). Now group-first + (one finding per command name listing every namespace), COL-shaped `details.namespaces`. The old + HIGH `Cross-plugin command name conflict` finding and its humanizer entry are removed. Scoring + impact: configs with cross-plugin command overlap score slightly higher. Not a `--json`-shape + break — no test or consumer asserted the old HIGH. + +### Fixed +- **README scanner table** — added the missing SKL row (12 → 13 rows); the prose table lagged the + badge/self-audit count (the `--check-readme` gate is number-only and didn't catch it). + +### Internal +- **Extract skill-listing budget to shared lib** — `scanners/lib/context-window.mjs` as the single + source of truth for the 200k/1M context-window constants, re-exported by + `skill-listing-budget.mjs` and consumed by the new CML char-budget finding. + +### Knowledge +- Three backing entries added: `disableBundledSkills` as a token-efficiency lever + (`prompt-cache-patterns.md`); the 40.0k-char "large CLAUDE.md" startup warning + CC 2.1.169 + context-window scaling (`claude-code-capabilities.md`); and `Tool(param:value)` permission + semantics — deny/ask-only matching plus the canonicalizing-field rules CC ignores + (`claude-code-capabilities.md`). + +### Test count +- 936 tests across 56 test files (unchanged — this release covers already-tested work on `main`). + +### Verification +- 936/936 tests pass (`node --test 'tests/**/*.test.mjs'`). +- `node scanners/self-audit.mjs --json --check-readme` → `configGrade: A`, `pluginGrade: A`, + `readmeCheck.passed: true`. +- README version badge updated: `version-5.2.0` → `version-5.3.0`. Scanner count stays 13; tests + badge already `936+`. + ## [5.2.0] - 2026-06-18 ### Summary diff --git a/README.md b/README.md index e80cfe3..b47291e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ *AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)* -![Version](https://img.shields.io/badge/version-5.2.0-blue) +![Version](https://img.shields.io/badge/version-5.3.0-blue) ![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple) ![Scanners](https://img.shields.io/badge/scanners-13-cyan) ![Commands](https://img.shields.io/badge/commands-18-green) @@ -21,7 +21,7 @@ A Claude Code plugin that checks configuration health, suggests context-aware im ## Table of Contents -- [What's New in v5.2.0](#whats-new-in-v520) +- [What's New in v5.3.0](#whats-new-in-v530) - [What Is This?](#what-is-this) - [The Configuration Problem](#the-configuration-problem) - [Quick Start](#quick-start) @@ -45,16 +45,31 @@ A Claude Code plugin that checks configuration health, suggests context-aware im --- -## What's New in v5.2.0 +## What's New in v5.3.0 -**Claude Code 2.1.114→181 compatibility + skill-listing budget.** A new orchestrated -scanner, **SKL**, checks the model's skill-listing token budget: `CA-SKL-001` flags any -active skill description over the 1,536-char listing cap (silently truncated by CC 2.1.105), -and `CA-SKL-002` flags when the summed descriptions exceed the listing budget (~2% of context). -Five validators were refreshed for the settings and hook surface that shipped across -CC 2.1.114–181 (new settings keys, `xhigh` effort, `MessageDisplay` + post-session hook -events), and an adversarial gap-review eliminated a batch of false positives in the MCP and -permissions scanners. → **13 orchestrated deterministic scanners** (+ standalone plugin-health). +**Permission-rule & plugin-hygiene hardening.** Five additive scanner findings extend the +permission, CLAUDE.md, and plugin surfaces — no new scanner, so the count stays **13**: + +- **DIS forbidden-param rules** — flags `Tool(param:value)` whose key is the tool's own + canonicalizing field (`command`/`file_path`/`path`/`notebook_path`/`url`), which Claude Code + silently ignores with a startup warning. Severity by intent: deny/ask = false security + (medium), allow = dead config (low). Valid forms (`Bash(npm:*)`, `WebFetch(domain:host)`, + `Agent(model:opus)`) are never flagged. +- **DIS ineffective allow-wildcards** — unanchored tool-name globs in `permissions.allow` + (`*`, `B*`, `mcp__*`) that CC silently skips, plus `Tool(*)` treated as deny-all + (`Bash(*)` ≡ `Bash`) so a bare allow killed by it is reported as dead config. +- **CML context-window-scaled char budget** — mirrors CC's own *"Large CLAUDE.md will impact + performance (X chars > 40.0k)"* startup warning; anchors on the conservative 200k window and + discloses the relaxed ~200,000-char figure at 1M context. Char-keyed, complementary to the + existing line checks. +- **PLH plugin namespace collision** — flags two or more plugins declaring the same `name` in + `plugin.json`; their namespaces collapse and Claude Code silently drops the loser's components. +- **feature-gap `disableBundledSkills` lever** — recommends disabling bundled skills when the + active skill listing is over budget (remediation companion to `CA-SKL-002`). + +The cross-plugin command-name finding is reframed from a HIGH conflict to a **LOW ambiguity** to +match Claude Code's namespacing (`/name:command` keeps both commands reachable). `--json` and +`--raw` output remain byte-stable. --- @@ -603,6 +618,7 @@ This plugin is cautious by design — configuration files are important, and a b | Version | Date | Highlights | |---------|------|-----------| +| **5.3.0** | 2026-06-19 | Permission-rule & plugin-hygiene hardening. Five additive scanner findings extend existing scanners (count stays **13**): DIS forbidden-param rules (`Tool(param:value)` on a canonicalizing field — deny/ask = false security, allow = dead config) and ineffective allow-wildcards + `Tool(*)` deny-all; CML context-window-scaled 40.0k-char CLAUDE.md budget mirroring CC's startup warning; PLH plugin namespace collision (two plugins declaring the same `name`); feature-gap `disableBundledSkills` lever under skill-listing pressure. PLH cross-plugin command-name overlap reframed HIGH → LOW (namespacing keeps both reachable). `--json`/`--raw` byte-stable. 936 tests | | **5.2.0** | 2026-06-18 | CC 2.1.114→181 compatibility + skill-listing budget. New orchestrated scanner **SKL** (`CA-SKL-001` 1,536-char listing cap, `CA-SKL-002` listing-budget sum) → 13 orchestrated scanners. Five validators refreshed for CC 2.1.114–181 settings/hook surface (`xhigh` effort, `MessageDisplay` + post-session events, 28 hook events). False positives eliminated in MCP (auto-injected/POSIX env vars, invented `trust` field) and permissions (param-aware DIS/CNF). Hermetic HOME isolation across all CLI-spawning tests. 875 tests | | **5.1.0** | 2026-05-01 | Plain-language UX humanizer. Default output of all 18 commands now leads with prose; findings grouped by user-impact category (Configuration mistake, Conflict, Wasted tokens, Missed opportunity, Dead config) and led by urgency phrase (Fix this now → FYI). New `--raw` flag preserves v5.0.0 verbatim output for tooling that scrapes stderr; `--json` is unchanged and byte-stable. New scanner-lib modules: `humanizer.mjs`, `humanizer-data.mjs` with TRANSLATIONS for 13 scanner prefixes. Self-audit terminal output also humanized. 792 tests (+157 humanizer-tester) | | **5.0.0** | 2026-05-01 | Reality-based token-optimization. 3 new scanners (CPS cache-prefix, DIS dead tools, COL plugin collisions) → 12 deterministic scanners. New `/config-audit manifest` and `--accurate-tokens` API calibration. Severity-weighted scoring (`scoringVersion: 'v5'`). MCP token estimates 15 → 500+. Plugin Hygiene as 10th quality area. Knowledge: cache-stability replaces 200-line rule, cache-telemetry recipe. **Breaking:** F2 token magnitude jump, F3 severity weighting, F5 Pattern D removed, N1 `CA-TOK-*` glob now matches CA-TOK-005. 635 tests | diff --git a/knowledge/claude-code-capabilities.md b/knowledge/claude-code-capabilities.md index 28cbe04..1fa2f78 100644 --- a/knowledge/claude-code-capabilities.md +++ b/knowledge/claude-code-capabilities.md @@ -31,6 +31,13 @@ | `/code-review` bundled review skill | v2.1.147 | Renamed from the former cleanup skill; reports correctness bugs at a chosen effort (`/code-review high`), `--comment` posts inline PR comments. | | `/config key=value` | v2.1.181 | Apply any setting from the prompt (e.g. `/config thinking=false`) — interactive, `-p`, and Remote Control. Lets `/config-audit` settings recommendations be applied without hand-editing settings.json. | +## v5.3.0 scanner-backing facts (verified 2026-06-19) + +| Fact | Source | Backs | +|------|--------|-------| +| **"Large CLAUDE.md will impact performance (X chars > 40.0k)"** — Claude Code emits this startup warning when a CLAUDE.md exceeds ~40,000 chars. CC 2.1.169 scales the threshold with the model's context window: ~40.0k at a 200k-context model, relaxing to ~200,000 chars at 1M context. The figure is a **char** count, not a line count — complementary to the 200/500-line adherence guidance (a file can be long by lines yet under budget, or short by lines yet over it). | CC changelog 2.1.169 + live startup-warning text | CML `CA-CML` char-budget finding — anchors on the conservative 200k window (fires earliest, since the user's window is unobservable) and discloses the relaxed 1M figure. Window constants in `scanners/lib/context-window.mjs`. Severity medium (token cost, not an adherence cliff). | +| **`Tool(param:value)` permission matching is deny/ask-only.** The `param:value` form is honored only in `permissions.deny` and `permissions.ask`; in `permissions.allow` it matches nothing (dead config). Separately, a rule whose key is the tool's own *canonicalizing field* — `command` (Bash/PowerShell), `file_path` (Read/Edit/Write), `path` (Grep/Glob), `notebook_path` (NotebookEdit), `url` (WebFetch) — is **ignored** by CC, which emits a startup warning. Valid parameter forms (`Bash(npm:*)`, `WebFetch(domain:host)`, `Agent(model:opus)`) are honored. | code.claude.com/docs/en/permissions | DIS forbidden-param finding (`forbiddenParamRule` in `permission-rules.mjs`): deny/ask = false security (medium, the block never applies), allow = dead config (low). | + ## Official Configuration Guidance (Anthropic) These principles are backed by official docs and verified community reports. Use them to ground recommendations. diff --git a/knowledge/prompt-cache-patterns.md b/knowledge/prompt-cache-patterns.md index 5e4d3c4..c986e06 100644 --- a/knowledge/prompt-cache-patterns.md +++ b/knowledge/prompt-cache-patterns.md @@ -56,3 +56,14 @@ uncertainty band. | medium | Materially inflates token cost per turn (cache miss, schema bloat) | | low | Detectable inefficiency that compounds across long sessions | | info | Informational signal — no action required, may indicate room for optimisation | + +## Skill-listing budget lever: disableBundledSkills + +When the active skill listing exceeds its token budget (SKL `CA-SKL-002`), the +`disableBundledSkills` setting is a direct token-efficiency lever: it removes the descriptions +of plugin-bundled skills from the skill listing injected into the system prompt, shrinking the +per-turn baseline. Unlike trimming individual descriptions (`CA-SKL-001`), it is a single switch +that drops the entire bundled-skill surface at once — appropriate when the bundled skills are not +in active use. feature-gap surfaces it as a conditional recommendation, the remediation companion +to `CA-SKL-002`. Sibling levers: `skillOverrides` (selectively re-enable specific skills) and +per-skill description trimming.