|
| 1 | +# Stop committing machine-local capability into `.claude/compound-v.json` (design, v2.6.2) |
| 2 | + |
| 3 | +**Status:** approved for build (2026-07-06). Triggered by a real downstream-repo PR review comment |
| 4 | +(a teammate flagged `.claude/compound-v.json` — 109 new lines — as "should be in exclusions"). |
| 5 | + |
| 6 | +## 1. What it is |
| 7 | +`.claude/compound-v.json` (written by `/v:init` Step 4a, refreshed by `/v:models` Step 3) currently |
| 8 | +mixes two unrelated kinds of data in one **committed** file: genuine team/project **policy** |
| 9 | +(`stance`, `models`, `memory`, `epic`, `review`, `workflows_accelerator`) and a **machine-local |
| 10 | +capability snapshot** (`backends`, `checked_at` — "which CLI/MCP tools were detected on the machine |
| 11 | +that last ran `/v:init`"). The fix: **stop writing `backends`/`checked_at` into the committed |
| 12 | +file.** No new file is needed — a correct, already-uncommitted home for exactly this data already |
| 13 | +exists: `~/.claude/compound-v-capabilities.json` (`/v:init` Step 4b, user-home-scoped, "reused |
| 14 | +across repos"). `backends` was pure redundancy with it. |
| 15 | + |
| 16 | +## 2. Why |
| 17 | +`backends` is written as *"add `codex` if Codex is usable... add `cursor` if `cursor-agent` is |
| 18 | +installed **and authenticated**"* — a fact about **the machine that ran `/v:init`**, not a team |
| 19 | +decision. Committing it means every other developer's checkout claims their teammate's local tool |
| 20 | +availability as if it were their own — wrong the moment a second developer (with a different local |
| 21 | +setup) opens the file. This is precisely what the reviewer flagged. |
| 22 | + |
| 23 | +**It is also not load-bearing today** — audited via full-repo grep before writing this spec: |
| 24 | +`compound-v-resolve-model.py`'s `load_config_models()` reads only the `models` key; no script or |
| 25 | +skill prose reads `backends`/`checked_at` back out of `.claude/compound-v.json` programmatically. |
| 26 | +Actual backend availability is already re-probed live at dispatch/orchestrate time (the "env-aware" |
| 27 | +codex→claude fallback in `routing-policy.md`, invoked "at runtime, not only at `/v:init`") and by |
| 28 | +the Step 4b capability cache. So this is a hygiene/trust fix (stop the file lying to teammates), not |
| 29 | +a routing-behavior fix — nothing about actual dispatch logic changes. |
| 30 | + |
| 31 | +## 3. The split (final — after the audit, simpler than a new file) |
| 32 | + |
| 33 | +| Field | Home | Committed? | |
| 34 | +|---|---|---| |
| 35 | +| `stance`, `models`, `memory`, `epic`, `review`, `workflows_accelerator` | `.claude/compound-v.json` (unchanged) | ✅ yes — team policy | |
| 36 | +| Backend/tool availability (`codex`, `antigravity`, `cursor`, `context7`, `workflows`) | `~/.claude/compound-v-capabilities.json` (**already exists**, Step 4b, user-home) | ❌ no — already outside any repo | |
| 37 | +| ~~`backends`~~, ~~`checked_at`~~ | **removed** from `.claude/compound-v.json` | — | |
| 38 | + |
| 39 | +No new file, no new read path, no resolver/dispatcher/memory code changes — the two fields being |
| 40 | +removed have zero programmatic readers today (confirmed by audit). This is a **documentation + |
| 41 | +write-path** change only. |
| 42 | + |
| 43 | +## 4. Components |
| 44 | + |
| 45 | +### 4.1 `commands/v-init.md` Step 4a |
| 46 | +Drop `backends` and `checked_at` from the written JSON example and the field-by-field write |
| 47 | +instructions. Add one clarifying sentence: this file is committed team **policy** only; machine |
| 48 | +capability already lives in the Step 4b user-level cache and must never be duplicated here. |
| 49 | + |
| 50 | +### 4.2 `commands/v-models.md` Step 3 |
| 51 | +Drop `backends`/`checked_at` from the "preserve every other key" list (nothing seeds or reads them |
| 52 | +going forward). **Backward-compat:** if an existing project's file already has these keys (written |
| 53 | +by a pre-2.6.2 `/v:init`), `/v:models` does not need to actively strip them — they're inert. No |
| 54 | +migration tooling; a user who wants a clean file re-runs `/v:init`, or edits the two keys out by |
| 55 | +hand. (No over-engineering: don't build a migration script for two dead JSON keys.) |
| 56 | + |
| 57 | +### 4.3 Every other doc showing the full example JSON |
| 58 | +`skills/compound-v/routing-policy.md`, `skills/compound-v/execution-manifest.md`, and any other |
| 59 | +doc that reproduces the `.claude/compound-v.json` example shape gets the same trim, so there is |
| 60 | +exactly one place a reader learns the shape and it's consistent everywhere. |
| 61 | + |
| 62 | +### 4.4 Explicit "why" note, once, at the canonical source |
| 63 | +`v-init.md` Step 4a (the canonical place the file is first written) states the committed/uncommitted |
| 64 | +split explicitly and *why* — this is the paragraph a future contributor (or a `git blame`-curious |
| 65 | +teammate) reads to understand the reasoning, so it doesn't need re-litigating per downstream repo. |
| 66 | + |
| 67 | +## 5. Invariants |
| 68 | +1. **`.claude/compound-v.json` (committed) never records what's true only of one machine.** |
| 69 | +2. **No duplication** — machine capability has exactly one home (`~/.claude/compound-v-capabilities.json`). |
| 70 | +3. **No functional/runtime behavior changes** — `models` resolution, `memory`/`epic`/`review` reads, |
| 71 | + and the live env-aware backend fallback are all unaffected (none of them read `backends`/`checked_at`). |
| 72 | +4. **Backward-compatible** — an existing committed file with the old fields still works (they're |
| 73 | + simply ignored by everything, as they are today); no migration required to upgrade. |
| 74 | + |
| 75 | +## 6. Verification |
| 76 | +- Grep-based check: after the doc edits, no doc's *written* example (the JSON blocks presented as |
| 77 | + "what `/v:init`/`/v:models` writes") contains `backends`/`checked_at` inside `.claude/compound-v.json`'s |
| 78 | + shape. |
| 79 | +- Re-confirm the audit finding holds after edits: `load_config_models()` and every other reader are |
| 80 | + unaffected (they were never touched). |
| 81 | +- Codex cross-model verification: does the doc consistently point machine-capability data at the |
| 82 | + Step 4b cache everywhere, with no leftover reference implying `backends` is still needed/read? |
| 83 | +- Full existing regression (`compound-v-resolve-model.py --selftest`, `compound-v-memory.py --selftest`, |
| 84 | + frontmatter lint, CI version lockstep) stays green — expected, since no code changed. |
| 85 | + |
| 86 | +## 7. Out of scope |
| 87 | +- An automated migration/cleanup tool for existing committed files with the old fields. |
| 88 | +- Any change to the Step 4b capability-cache format (it's already correct). |
| 89 | +- Any change to live routing/fallback behavior (unaffected by this fix). |
| 90 | + |
| 91 | +## 8. Version |
| 92 | +**v2.6.2** (patch — docs/write-path only; `plugin.json` + `marketplace.json` in lockstep). |
0 commit comments