From 2c3711cfd4ec6e7630010848032f958c588f4304 Mon Sep 17 00:00:00 2001 From: bob Date: Sat, 23 May 2026 17:56:53 -0400 Subject: [PATCH] chore(compat): ship 8 schema-validated opt-ins + fix latent // strip; bump tested_up_to to 2.1.150 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SchemaStore PR #5706 merged 2026-05-23 (sync to CC v2.1.143), unblocking nine settings.json keys + five env vars held in the configurator backlog. This PR ships all of them as commented opt-ins (the PRs #17/#18 pattern) and bumps tested_up_to 2.1.132 → 2.1.150 after the 2.1.147-2.1.150 resurvey found only one new key (allowAllClaudeAiMcps, 2.1.149 — Enterprise managed, outside configurator territory). Latent-bug fix: configure.py was stripping ALL top-level //-prefixed keys when merging settingsPatch files, including the opt-in stubs (// sandbox, // prUrlTemplate) PRs #17 and #18 promised would surface in users' generated .claude/settings.json. New _is_doc_label helper keeps stub keys, drops only label keys (//, //N). Two source patches also corrected (slop-scan, microbit-enforcer) — their top-level documentation keys would otherwise leak under the new filter. Settings-key opt-ins shipped (commented; user uncomments to activate): - skillOverrides → token-efficiency tier-pro patch - worktree.baseRef + worktree.bgIsolation → new multi-agent patch - autoMode.hard_deny + sandbox.failIfUnavailable → safety patch - subagentStatusLine + statusLine.hideVimModeIndicator → ui extraSettings - Hook args/continueOnBlock → doc note in safety + git-workflow patches - CLAUDE_CODE_STOP_HOOK_BLOCK_CAP → safety patch // env block Still held for a future schemastore sync: terminalSequence hook output (2.1.147), Stop/SubagentStop input background_tasks/session_crons (2.1.149). Both verified absent from #5706. Closes #53. Co-Authored-By: Claude Opus 4.7 --- CHANGELOG.md | 21 +++++++ config_schema.py | 57 +++++++++++-------- configure.py | 14 ++++- .../microbit-enforcer/settings-patch.json | 2 +- templates/git-workflow/settings-patch.json | 3 +- templates/multi-agent/settings-patch.json | 10 ++++ templates/safety/settings-patch.json | 18 +++++- .../safety/settings-patch.slop-scan.json | 2 +- .../settings-patch.tier-pro.json | 2 + 9 files changed, 99 insertions(+), 30 deletions(-) create mode 100644 templates/multi-agent/settings-patch.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fec8e3..f6afe34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ All notable changes to this project. Format: [Keep a Changelog](https://keepacha ## Unreleased +### chore(compat): bump tested_up_to to 2.1.150 + ship eight schema-validated opt-ins after SchemaStore PR #5706 merge + +[SchemaStore PR #5706](https://github.com/SchemaStore/schemastore/pull/5706) merged 2026-05-23, syncing `claude-code-settings.json` to Claude Code v2.1.143 and unblocking nine settings keys (+ five env vars) that had been held in the configurator's backlog through three prior CHANGELOG resurveys. This PR ships all of them as commented-out opt-ins so users can uncomment to activate, matching the established pattern from PRs #17 (`prUrlTemplate`) and #18 (`sandbox.network.deniedDomains`). Bumps `tested_up_to` 2.1.132 → 2.1.150 (covers the 18 CC releases since the last bump, including the 2.1.147–2.1.150 resurvey that found only one new configurator-adjacent key — `allowAllClaudeAiMcps`, 2.1.149 — Enterprise managed setting, outside configurator territory). Closes tracking issue #53. + +**Latent bug fix:** discovered while wiring the new opt-ins that `configure.py`'s `settingsPatch` merger was stripping ALL top-level `//`-prefixed keys, including the opt-in stubs (`// sandbox`, `// prUrlTemplate`) that PRs #17 and #18 promised would surface in users' generated `.claude/settings.json`. The filter intended to drop documentation labels (`//`, `//2`, `//9`) but was too aggressive. New `_is_doc_label(k)` helper distinguishes label keys (pure-digit suffix or empty) from stub keys (`// foo`). The existing `// sandbox` + `// prUrlTemplate` opt-ins now actually appear in scaffolded settings.json for the first time — users who `cc-configure --retrofit` will see them on the next run. No persona snapshot drift (snapshots compare file trees, not contents); all 50+ shell fixtures still pass. Two source patch files also corrected (`safety/settings-patch.slop-scan.json`, `commands/microbit-enforcer/settings-patch.json`) — their top-level `"// settings-patch.slop-scan.json": "..."` / `"// microbit-enforcer.json": "..."` keys were maintainer-facing docs that would otherwise leak into user settings under the new filter; rewritten as plain `"//"` labels. + +**Settings keys shipped as opt-ins:** + +- **`skillOverrides`** (CC 2.1.129+) → `templates/token-efficiency/settings-patch.tier-pro.json`, behind the existing `tier=pro` flag. Default value in the commented stub is `"name-only"` (most conservative). Values: `off` (hides from model AND `/`-menu), `user-invocable-only` (hides from model only), `name-only` (collapses description to just the skill name). Directly reduces the context metric `/check-context` flags. +- **`worktree.baseRef` + `worktree.bgIsolation`** (CC 2.1.133+ / 2.1.143+) → new `templates/multi-agent/settings-patch.json` (added `settingsPatch` reference to `multi-agent` module — module previously shipped no settings). Pair naturally with `/merge-worktrees`. `baseRef=head` preserves unpushed local commits in new worktrees; `bgIsolation=none` lets background sessions edit the live working copy directly when a worktree is impractical. +- **`autoMode.hard_deny`** (CC 2.1.136+) → `templates/safety/settings-patch.json`. Auto-mode classifier rules that block unconditionally regardless of user intent or allow exceptions. Example values seeded: `"Running executable files"`, `"Writing to system directories"`. Only meaningful under `claude --auto-mode`. +- **`sandbox.failIfUnavailable`** (CC 2.1.143+) → nested inside the existing `// sandbox` block in `templates/safety/settings-patch.json`. Set to `true` for fail-closed sandbox posture (hard failure when required deps missing, instead of falling back to non-sandboxed execution). +- **`subagentStatusLine` + `statusLine.hideVimModeIndicator`** (CC 2.1.143+) → `extraSettings` in `ui` module (`config_schema.py`). `subagentStatusLine` lets subagent runs render a distinct status line for visual separation from the parent session; `hideVimModeIndicator` suppresses CC's built-in vim mode display when the user's statusline script renders its own. +- **Hook `args: string[]` exec form + `continueOnBlock: boolean`** (CC 2.1.139+) → doc comment in `templates/safety/settings-patch.json` and `templates/git-workflow/settings-patch.json` annotating that the new syntax is now schema-valid for custom hooks users add. No active hook configs use them yet — pure forward-looking enablement. + +**Env vars (mention-only, in `safety/settings-patch.json` comment block):** `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` (override 8-block consecutive-Stop cap; seeded value `"16"` inside the commented `// env` block). The other four (`ANTHROPIC_WORKSPACE_ID`, `CLAUDE_CODE_OPUS_4_6_FAST_MODE_OVERRIDE`, `CLAUDE_CODE_PLUGIN_PREFER_HTTPS`, `CLAUDE_CODE_POWERSHELL_RESPECT_EXECUTION_POLICY`) are platform-/workspace-specific and don't warrant configurator-shipped defaults; captured in the `CLAUDE_CODE_COMPAT` rationale comment for future-self. + +**Still held for a future schemastore sync PR:** hook output `terminalSequence` field (CC 2.1.147); Stop/SubagentStop hook input `background_tasks` + `session_crons` fields (CC 2.1.149). Both were verified absent from #5706's head-branch schema and remain in `docs/07-backlog.md`. + +`CLAUDE_CODE_COMPAT.tested_up_to` bumped 2.1.132 → 2.1.150; rationale comment rewritten to a clean summary. Local SessionStart watcher (`.claude/hooks/check-schemastore-pr.sh`, gitignored) retired after PR #5706 merged. + ## [2.5.0] — 2026-05-21 Bundle release: the drift-monitor family — PR #51 introduced the pattern (`.claude/.cc-manifest.json` baseline + SessionStart hook + `/verify-setup` narrative for MCP servers), and PR #54 completed it with two more dimensions (stack manifests + check-command alignment). Plus PR #49 cleaning up legacy `/brainstorm` references after the superpowers v5.1.0 churn, and PR #52 tracking SchemaStore PR #5706 (no template changes; `tested_up_to` bump deferred to the unblock batch). `CC_VERSION` bumped to 2.5.0. diff --git a/config_schema.py b/config_schema.py index 9d49cd8..6c77751 100644 --- a/config_schema.py +++ b/config_schema.py @@ -182,6 +182,7 @@ "commands/merge-worktrees/SKILL.md", "commands/infinite/SKILL.md", ], + "settingsPatch": "multi-agent/settings-patch.json", }, { "id": "github-actions", @@ -242,7 +243,14 @@ "statusLine": { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/statusline.sh", - } + "//": "Optional: hideVimModeIndicator (CC 2.1.143+, schemastore-validated 2026-05-23). When the statusline script renders its own vim mode display, set to true to suppress Claude Code's built-in one. Uncomment the next key by removing the leading '// ' (and drop this '//' explainer).", + "// hideVimModeIndicator": True, + }, + "//": "Optional: subagentStatusLine (CC 2.1.143+, schemastore-validated 2026-05-23). Distinct statusline for subagent runs so they're visually separable from the parent session. Uncomment the next block by removing the leading '// ' from the key.", + "// subagentStatusLine": { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/statusline.sh --subagent", + }, }, }, ] @@ -347,28 +355,31 @@ # configurator against. Newer is likely fine but unverified. CLAUDE_CODE_COMPAT = { "min_version": "2.1.116", # agent mcpServers http (2.1.116/117) - "tested_up_to": "2.1.132", # alwaysLoad MCP, updatedToolOutput PostToolUse, - # ultrareview non-interactive, prUrlTemplate + - # sandbox.network.deniedDomains schema-validated. - # 2.1.122-128: bug fixes + MCP "workspace" reserved - # + managed-settings channelsEnabled (enterprise). - # 2.1.129-132: skillOverrides settings.json key now - # works (held — not yet in schemastore 2026-05-06); - # plugin manifests gain experimental: wrapper for - # themes/monitors; CLAUDE_CODE_SESSION_ID exposed in - # Bash subprocess env; no other configurator- - # territory schema additions. - # 2026-05-21 resurvey of 2.1.133-2.1.146: eleven - # configurator-territory keys + five env vars held - # in SchemaStore PR #5706 (sync to v2.1.143; - # supersedes the closed #5665). Bump deferred until - # #5706 merges and the unblock batch ships per the - # "no lone tracking bumps" rule. Two further items - # (terminalSequence hook output from 2.1.141; - # background_tasks/session_crons hook input from - # 2.1.145) need a future sync PR. No live breakage: - # /simplify → /code-review rename in 2.1.146 does - # not collide with the configurator's /review. + "tested_up_to": "2.1.150", # SchemaStore PR #5706 merged 2026-05-23 (sync to + # v2.1.143), unblocking nine settings.json keys for + # opt-in templating: skillOverrides (token- + # efficiency-pro tier-pro patch), worktree.baseRef + # + worktree.bgIsolation (multi-agent patch), + # autoMode.hard_deny + sandbox.failIfUnavailable + # (safety patch), subagentStatusLine + + # statusLine.hideVimModeIndicator (ui extraSettings), + # and the hook `args: string[]` + `continueOnBlock` + # forms (doc-only in safety/git-workflow patches). + # Five new env vars also schema-validated and + # mention-only in module docs: ANTHROPIC_WORKSPACE_ID, + # CLAUDE_CODE_OPUS_4_6_FAST_MODE_OVERRIDE, + # CLAUDE_CODE_PLUGIN_PREFER_HTTPS, + # CLAUDE_CODE_POWERSHELL_RESPECT_EXECUTION_POLICY, + # CLAUDE_CODE_STOP_HOOK_BLOCK_CAP (safety patch). + # 2.1.147-150 resurvey (2026-05-23): only one new + # configurator-adjacent key (allowAllClaudeAiMcps, + # 2.1.149) — Enterprise managed setting, outside + # configurator territory. /simplify → /code-review + # rename (2.1.146) does not collide with /review. + # Still held for a future schemastore sync PR: + # hook output `terminalSequence` (2.1.147); Stop / + # SubagentStop hook input `background_tasks` + + # `session_crons` fields (2.1.149). } diff --git a/configure.py b/configure.py index d1fbaf8..ec5dc99 100755 --- a/configure.py +++ b/configure.py @@ -435,6 +435,16 @@ def repl(m): return re.sub(r"\{\{(\w+)\}\}", repl, text) +def _is_doc_label(k: str) -> bool: + # Source patch files use two `//` conventions: numbered doc labels + # ("//", "//2", "//9") that explain the patch to humans reading the + # source and must NOT propagate to the user's generated settings.json, + # and stub keys ("// sandbox", "// prUrlTemplate") that DO propagate so + # the user can uncomment them. Distinguish by the bit after `//`: pure + # digits (or empty) = doc label. + return k == "//" or (k.startswith("//") and k[2:].isdigit()) + + def deep_merge(a, b): if isinstance(a, list) and isinstance(b, list): return a + b @@ -460,7 +470,7 @@ def compute_merged_settings(form_values: dict, selected: set, module_flags: dict if m.get("settingsPatch"): patch_path = TEMPLATE_DIR / m["settingsPatch"] patch = json.loads(patch_path.read_text(encoding="utf-8")) - patch = {k: v for k, v in patch.items() if not k.startswith("//")} + patch = {k: v for k, v in patch.items() if not _is_doc_label(k)} settings = deep_merge(settings, patch) if m.get("extraSettingsHook"): settings["hooks"] = deep_merge(settings.get("hooks", {}), m["extraSettingsHook"]) @@ -475,7 +485,7 @@ def compute_merged_settings(form_values: dict, selected: set, module_flags: dict extra = extra.get(selected_value) if extra: extra_patch = json.loads((TEMPLATE_DIR / extra).read_text(encoding="utf-8")) - extra_patch = {k: v for k, v in extra_patch.items() if not k.startswith("//")} + extra_patch = {k: v for k, v in extra_patch.items() if not _is_doc_label(k)} settings = deep_merge(settings, extra_patch) # extraSettingsEnv: merge env vars driven by the flag's value. # Boolean false ⇒ skip. Otherwise emit each {key: value} pair into diff --git a/templates/commands/microbit-enforcer/settings-patch.json b/templates/commands/microbit-enforcer/settings-patch.json index 9a29a4b..c325b48 100644 --- a/templates/commands/microbit-enforcer/settings-patch.json +++ b/templates/commands/microbit-enforcer/settings-patch.json @@ -1,5 +1,5 @@ { - "// microbit-enforcer.json": "Auto-installed alongside the freeze/unfreeze/guard/careful microbits when commands.subset is 'full' or 'rigorous'. PreToolUse rejects Write/Edit/NotebookEdit when a marker is present; SessionStart clears markers (session-scoped lifecycle).", + "//": "Auto-installed alongside the freeze/unfreeze/guard/careful microbits when commands.subset is 'full' or 'rigorous'. PreToolUse rejects Write/Edit/NotebookEdit when a marker is present; SessionStart clears markers (session-scoped lifecycle).", "hooks": { "PreToolUse": [ { diff --git a/templates/git-workflow/settings-patch.json b/templates/git-workflow/settings-patch.json index 317898c..607fc63 100644 --- a/templates/git-workflow/settings-patch.json +++ b/templates/git-workflow/settings-patch.json @@ -6,7 +6,8 @@ "//5": "GitLab: https://gitlab.com/{owner}/{repo}/-/merge_requests/{number}", "//6": "Bitbucket: https://bitbucket.org/{owner}/{repo}/pull-requests/{number}", "//7": "GHE: https://gh.example.com/{owner}/{repo}/pull/{number}", - "//8": "Uncomment by removing the leading '// ' on the next line, then set the template, then drop these //N keys.", + "//8": "Hook authoring note (CC 2.1.139+, schemastore-validated 2026-05-23): hookCommand entries now accept 'args: string[]' for direct-exec form (no shell wrapping, no quote-escaping pain) and 'continueOnBlock: boolean' for prompt hooks (default false; when true, ok:false feeds reason back to Claude and continues the turn instead of stopping). Useable on the hooks below if you customize them.", + "//9": "Uncomment prUrlTemplate by removing the leading '// ' on the next line, then set the template, then drop these //N keys.", "// prUrlTemplate": "https://gitlab.com/{owner}/{repo}/-/merge_requests/{number}", "hooks": { "PostToolUse": [ diff --git a/templates/multi-agent/settings-patch.json b/templates/multi-agent/settings-patch.json new file mode 100644 index 0000000..a320247 --- /dev/null +++ b/templates/multi-agent/settings-patch.json @@ -0,0 +1,10 @@ +{ + "//": "Merged into .claude/settings.json. Multi-agent module ships no active settings by default — the commented opt-ins below are for users running parallel sessions or worktrees and pair naturally with /merge-worktrees.", + "//2": "Optional: worktree.baseRef (CC 2.1.133+, schemastore-validated 2026-05-23). Values: 'fresh' (default; creates new worktrees from origin/HEAD) or 'head' (preserves unpushed local commits in the new worktree). Pick 'head' if you frequently spin up worktrees from in-progress work.", + "//3": "Optional: worktree.bgIsolation (CC 2.1.143+, schemastore-validated 2026-05-23). Values: 'worktree' (default; background sessions get their own worktree) or 'none' (background sessions edit the live working copy directly, skipping EnterWorktree). 'none' is useful for repos where worktrees are impractical (build artifacts outside the tree, hardcoded paths).", + "//4": "Uncomment by removing the leading '// ' on the next key + tuning the values, then drop these //N keys.", + "// worktree": { + "baseRef": "head", + "bgIsolation": "worktree" + } +} diff --git a/templates/safety/settings-patch.json b/templates/safety/settings-patch.json index 6db55bc..fc0c6a0 100644 --- a/templates/safety/settings-patch.json +++ b/templates/safety/settings-patch.json @@ -4,7 +4,11 @@ "//3": "Optional opt-in: sandbox.network.deniedDomains (CC 2.1.113+, schemastore-validated 2026-04-28).", "//4": "Only takes effect when the sandbox is otherwise active for the command (see sandboxing docs).", "//5": "Supports wildcards (*.example.com). Below is a small data-exfiltration-resistant baseline; tune for your threat model.", - "//6": "Uncomment by removing the leading '// ' on the next key, then drop these //N keys.", + "//6": "Inside the // sandbox block: failIfUnavailable (CC 2.1.143+, schemastore-validated 2026-05-23) makes sandbox startup a hard failure when required dependencies are missing, instead of falling back to non-sandboxed execution. Fail-closed posture for safety-sensitive projects — uncomment the inner '// failIfUnavailable: true' line after uncommenting the outer block.", + "//7": "Optional: autoMode.hard_deny (CC 2.1.136+, schemastore-validated 2026-05-23). Classifier rules that block unconditionally regardless of user intent or allow exceptions — final guardrail when running with auto mode. Edit the strings to match the action categories you want to hard-block. Only meaningful if you run `claude --auto-mode`.", + "//8": "Optional: env CLAUDE_CODE_STOP_HOOK_BLOCK_CAP (CC 2.1.143+) overrides the default 8-block cap for consecutive Stop hook blocks. Raise this only if a safety Stop hook intentionally blocks repeatedly and you want to tolerate it without the cap kicking in.", + "//9": "Hook authoring note (CC 2.1.139+, schemastore-validated 2026-05-23): hookCommand entries now accept 'args: string[]' for direct-exec form (no shell, no quote-escaping pain) and 'continueOnBlock: boolean' for prompt hooks (default false; when true, ok:false feeds the reason back to Claude and the turn continues instead of stopping). Use these on custom hooks you add below.", + "//10": "Uncomment any opt-in by removing the leading '// ' on its key, then drop the explainer //N keys.", "// sandbox": { "network": { "deniedDomains": [ @@ -19,7 +23,17 @@ "anonfiles.com", "uguu.se" ] - } + }, + "// failIfUnavailable": true + }, + "// autoMode": { + "hard_deny": [ + "Running executable files", + "Writing to system directories" + ] + }, + "// env": { + "CLAUDE_CODE_STOP_HOOK_BLOCK_CAP": "16" }, "hooks": { "PreToolUse": [ diff --git a/templates/safety/settings-patch.slop-scan.json b/templates/safety/settings-patch.slop-scan.json index 8562dfb..fdfce31 100644 --- a/templates/safety/settings-patch.slop-scan.json +++ b/templates/safety/settings-patch.slop-scan.json @@ -1,5 +1,5 @@ { - "// settings-patch.slop-scan.json": "Registers the slop-scan PostToolUse hook. Applied via safety.flags.slop_scan when set to true. Only the hook registration lives here; the action mode + opt-in flags are exported via extraSettingsEnv (see config_schema.py).", + "//": "Registers the slop-scan PostToolUse hook. Applied via safety.flags.slop_scan when set to true. Only the hook registration lives here; the action mode + opt-in flags are exported via extraSettingsEnv (see config_schema.py).", "hooks": { "PostToolUse": [ { diff --git a/templates/token-efficiency/settings-patch.tier-pro.json b/templates/token-efficiency/settings-patch.tier-pro.json index fe3c135..4c45b0b 100644 --- a/templates/token-efficiency/settings-patch.tier-pro.json +++ b/templates/token-efficiency/settings-patch.tier-pro.json @@ -1,4 +1,6 @@ { + "//": "Optional: skillOverrides (CC 2.1.129+, schemastore-validated 2026-05-23). Suppresses skill visibility/descriptions to reduce context overhead — the metric /check-context flags. Values: 'off' (hides from model AND /-menu), 'user-invocable-only' (hides from model, /-menu still works), 'name-only' (collapses description to just the skill name). 'name-only' is the conservative default; pick 'user-invocable-only' if you only ever invoke skills explicitly. Uncomment the next line by removing the leading '// '.", + "// skillOverrides": "name-only", "env": { "CLAUDE_BASH_MAX_LINES": "80" },