Deferred from #2526 / #2527, which documented the exposure but left the remediation unscheduled.
The invariant
skills/plugins/SKILL.md states it directly:
Never silently fixes drift it finds. sync mutates only via the documented CLI actions below;
converge is the one action that can touch a committed .claude/settings.json, and only after an
explicit per-plugin confirm.
The violation
sync.md Step 5 issues claude plugin enable <id> -s <that scope> for every completeness gap in a
verifiable scope, which includes project when currentProject: true. Verified on Claude Code
2.1.228 (#2526): enable -s project writes the project's committed .claude/settings.json, adding
enabledPlugins[<id>] = true and re-serializing the file in Claude Code's key order.
So sync — the default action — silently writes a team-shared tracked file. 0.31.8 documented this
as a "known exposure" and told the step to name it in the report. That is a mitigation, not a fix.
Why confirming is not the fix
converge.md opens with an autonomous-session abort because it can touch committed settings:
CLAUDE_CODE_REMOTE set, or invocation via /loop or /schedule, aborts immediately, because no
human is present to answer a confirm.
sync has no such abort and is not meant to: it is the on-demand/headless maintenance action, and
/claude-ops:lanes runs it from scheduled background sessions. A code path that writes team-shared
state cannot be made safe by confirming when there may be nobody to confirm. The write must not
happen at all.
Proposed fix
Step 5 restricts its automatic enable to scopes that are not team-shared state:
This restores the invariant: after the change, no sync code path writes a committed settings file.
It trades a small amount of automatic completeness for the guarantee the skill already advertises,
and the report still tells the user exactly what to run.
converge is unaffected — it keeps its confirm gate and its autonomous abort, and its V1 scope
already excludes enable-state, so a project-scope enable gap is not something it can absorb.
Expected
sync.md Step 5: the scope rule above, replacing the 0.31.8 "known exposure" paragraph.
SKILL.md Report: an "Action needed" row for project-scope enable gaps carrying the exact command.
scope-semantics.md: the sync consequence bullet updated — no longer an exposure, now a
documented restriction.
Deferred from #2526 / #2527, which documented the exposure but left the remediation unscheduled.
The invariant
skills/plugins/SKILL.mdstates it directly:The violation
sync.mdStep 5 issuesclaude plugin enable <id> -s <that scope>for every completeness gap in averifiable scope, which includes
projectwhencurrentProject: true. Verified on Claude Code2.1.228 (#2526):
enable -s projectwrites the project's committed.claude/settings.json, addingenabledPlugins[<id>] = trueand re-serializing the file in Claude Code's key order.So
sync— the default action — silently writes a team-shared tracked file. 0.31.8 documented thisas a "known exposure" and told the step to name it in the report. That is a mitigation, not a fix.
Why confirming is not the fix
converge.mdopens with an autonomous-session abort because it can touch committed settings:CLAUDE_CODE_REMOTEset, or invocation via/loopor/schedule, aborts immediately, because nohuman is present to answer a confirm.
synchas no such abort and is not meant to: it is the on-demand/headless maintenance action, and/claude-ops:lanesruns it from scheduled background sessions. A code path that writes team-sharedstate cannot be made safe by confirming when there may be nobody to confirm. The write must not
happen at all.
Proposed fix
Step 5 restricts its automatic
enableto scopes that are not team-shared state:user— machine-scope,~/.claude/settings.json. Unchanged.local— writes the gitignored.claude/settings.local.json(verified, claude-ops plugins skill: enable -s project writes committed settings, and a subdirectory install is invisible to currentProject #2526). Unchanged.project— no longer enabled automatically. Reported under "Action needed" with the exactcommand the user can run, in the
cd-into-its-own-projectPathformconverge.mdmandates andwith the fully-qualified id
gotchas.mdrequires.This restores the invariant: after the change, no
synccode path writes a committed settings file.It trades a small amount of automatic completeness for the guarantee the skill already advertises,
and the report still tells the user exactly what to run.
convergeis unaffected — it keeps its confirm gate and its autonomous abort, and its V1 scopealready excludes enable-state, so a project-scope enable gap is not something it can absorb.
Expected
sync.mdStep 5: the scope rule above, replacing the 0.31.8 "known exposure" paragraph.SKILL.mdReport: an "Action needed" row for project-scope enable gaps carrying the exact command.scope-semantics.md: thesyncconsequence bullet updated — no longer an exposure, now adocumented restriction.