Skip to content

docs(claude-ops): record the --all + install_new:all mass install - #4182

Open
kyle-sexton wants to merge 2 commits into
mainfrom
docs/plugins-skill-mass-install-gotcha
Open

kyle-sexton wants to merge 2 commits into
mainfrom
docs/plugins-skill-mass-install-gotcha

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

What

Two edits to the claude-ops:plugins skill recording an incident the skill's existing safeguards do not catch.

  • skills/plugins/context/gotchas.md — new section: "--all with install_new: all is a mass install of every catalog, and nothing warns you."
  • skills/plugins/SKILL.md — the marketplace-resolution list now warns that all multiplies the install policy across catalogs; the install_new section requires a counted human confirmation before that combination runs.

Why

On 2026-09-14, /claude-ops:plugins sync --all with the install_new userConfig set to all installed 2,231 plugins (1,953 claude-community, 269 claude-plugins-official, 5 dotnet-agent-skills, 4 skills) between 14:43 and 15:05 — roughly 49 GB of plugin cache.

A logon-triggered session then loaded them and started their MCP servers: 22 third-party processes ran for ~8.5 hours, one binding TCP 8099 on all interfaces, at least 11 running npm install.

The skill did exactly what it was told. Against one curated marketplace, install_new: all means "install the handful I am missing" — a correct policy for a marketplace you maintain. --all silently changes the scope that policy applies over, and neither the downgrade guard nor audit surfaces the resulting count before it runs.

What the gotcha records

  • Why the existing safeguards miss this combination.
  • The claude --bare requirement for the revert. A plain claude plugin uninstall spawns a session that loads every still-enabled plugin and boots its MCP servers — so the first revert attempt was re-executing the bad plugin set on every iteration. --bare was verified over six uninstalls to spawn nothing.
  • The revert recipe, including recovering the id list from the run journal (the only authoritative record of what to remove) and verifying it disjoint from the pre-existing set first.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XD4Hr2S7RA2G8PR2CadLP1

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-15T14:52:00.967568Z 805c753 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@claude

claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 36s —— View job


Code review complete

  • Gather context (PR diff, changed files)
  • Review plugins/claude-ops/skills/plugins/SKILL.md changes
  • Review plugins/claude-ops/skills/plugins/context/gotchas.md changes
  • Verify referenced commands/selectors against actual script behavior
  • Post inline findings
  • Final summary

This is a documentation-only PR (no scripts changed), so I checked every command/selector the new prose introduces against the actual script contracts rather than treating it as prose-only.

1 correctness bug, found in two places (inline comments posted):

  • SKILL.md:281 and context/gotchas.md:368 both instruct running fleet-state.sh --ids install-gap. install-gap is not a valid --ids selector — fleet-state.sh's ids_selector_valid() accepts only installed-user | update-candidates-user | update-candidates-project | downgrade-candidates | current-project | missing-user-install | missing-enabled | user-scope-orphans. The command as written fails with ERROR: unknown --ids selector: install-gap. "install-gap" only exists as a human-readable label inside an error message in sync-run.sh (mp_error "install-gap projection failed..."); the selector sync-run.sh actually passes there is missing-user-install, which is also what context/sync-install-enable.md already uses correctly for the same purpose. Both new call-outs should say --ids missing-user-install.

Verified as correct, not flagged:

  • The paragraph removed from SKILL.md (about scripts/jq-capture.sh being a sourced library) is legitimate doc-drift cleanup, not an unrelated/accidental deletion — that script file was already deleted from main before this branch's tip, so the reference was stale.
  • The audit all (SKILL.md) vs audit --all (gotchas.md) phrasing difference is a pre-existing terminology inconsistency in this skill (bare second-token argument at the slash-command level vs. the internal script's --all flag) — not something this PR introduces, and both readings are internally consistent with their surrounding context, so I did not raise it as a blocking finding.
  • The 2,231-plugin breakdown (1,953 + 269 + 5 + 4) in the incident narrative sums correctly.

No security concerns (docs-only change, no code execution paths added).

@claude

claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 45s —— View job


Security review: no issues found

  • Gather context (PR is a docs-only change to SKILL.md and context/gotchas.md)
  • Run /review:security-review per custom instructions
  • Post final findings

Skip gate hit: the diff has no security-relevant surface. Both changed files are prose additions to skill documentation:

No shell scripts, code, workflow files, or executable logic are touched — only Markdown guidance describing operational policy (requiring a human confirmation count before a mass install). There is no injection surface, no credential/token handling, no authorization logic, and no GitHub Actions change in this diff. Per this lane's skip gate ("change has no security-relevant surface after reading the diff"), no findings to report.

@github-actions

Copy link
Copy Markdown
Contributor

Last security-reviewed head: 805c7537495ed1db377f4e73850e58e1ae69175b. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 805c753749

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +378 to +380
`claude plugin uninstall <id> -s user -y` removes both the `installed_plugins.json` record and the
user-scope `enabledPlugins` entry, but it costs ~6s per plugin, so a four-figure revert runs for
hours. There is no bulk uninstall verb; `marketplace remove` is not one (see its own section above,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add the required verification record for CLI claims

The revert guidance introduces volatile Claude CLI specifics—uninstall side effects, timing, and the absence of a bulk verb—without an external upstream source and a claim-specific basis/as-of/recheck record. The repository requires that record whenever a skill body restates volatile behavior; otherwise this recovery procedure can silently become unsafe as the CLI changes.

AGENTS.md reference: AGENTS.md:L20-L21

Useful? React with 👍 / 👎.

Comment on lines +368 to +369
the per-marketplace install gap first (`fleet-state.sh --ids install-gap` per marketplace, or one
`audit --all`), present the total, and proceed only on a yes. An agent running this unattended

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Correct both commands in the install-gap preflight

When an operator follows this newly required safety check, neither command shown here is valid as written: fleet-state.sh accepts the selector missing-user-install, not install-gap, and the skill's Action Router accepts the marketplace target as the second bare token (audit all), not audit --all. Thus this gotcha's counted-confirmation recipe fails before producing the count it requires; use the documented selector with --marketplace <name> and the skill-level audit all spelling.

Useful? React with 👍 / 👎.

[context/gotchas.md](context/gotchas.md)'s "`--all` with `install_new: all` is a mass install of
every catalog". **When the marketplace target is `all` and the rendered policy is `all`, do not
proceed unattended:** resolve the total install gap first (one `audit all`, or `fleet-state.sh
--ids install-gap` per marketplace), state the number, and get an explicit human yes. Treat the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fleet-state.sh --ids install-gap is not a valid invocation — install-gap isn't one of the accepted --ids selectors. fleet-state.sh's ids_selector_valid() only accepts installed-user | update-candidates-user | update-candidates-project | downgrade-candidates | current-project | missing-user-install | missing-enabled | user-scope-orphans (fleet-state.sh#L458-472). Running the documented command fails with ERROR: unknown --ids selector: install-gap.

"install-gap" only appears as a human-readable label in an error message in sync-run.sh (mp_error "install-gap projection failed...", sync-run.sh#L911); the actual selector it passes is missing-user-install (sync-run.sh#L908), which is also what context/sync-install-enable.md#L36 already uses. This line should say --ids missing-user-install.

Fix this →


**The rule, until the skill enforces a volume gate itself:** treat `--all` combined with a rendered
`install_new` of `all` as requiring an explicit human confirmation that names the number. Resolve
the per-marketplace install gap first (`fleet-state.sh --ids install-gap` per marketplace, or one

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as the parallel text added in SKILL.md: install-gap is not a valid --ids selector — fleet-state.sh's ids_selector_valid() only accepts installed-user | update-candidates-user | update-candidates-project | downgrade-candidates | current-project | missing-user-install | missing-enabled | user-scope-orphans. This command as written errors with unknown --ids selector: install-gap; it should read --ids missing-user-install (the selector sync-run.sh itself actually projects for this purpose, per its project_ids missing-user-install ... call).

@github-actions

Copy link
Copy Markdown
Contributor

Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@github-actions

Copy link
Copy Markdown
Contributor

PR body contract — issue linkage

This PR body does not yet satisfy the issue-linkage contract:

  • Missing a "## Summary" section. Describe what this PR changes and why, in a sentence or two.
  • Missing a "## Fix" section. State the concrete change and how it addresses the problem.
  • Missing a "## Verification" section. Record concrete evidence the change works (commands, gates, output).
  • Missing a "## Related" section. List related PRs, ADRs, or decision-log entries this PR does not close.
  • Missing a native closing keyword (Closes/Fixes/Resolves #N). If this PR references an issue it must not close, put "Refs: #N" (or "Relates to: #N") on its own line. If it relates to no GitHub issue at all, state "No linked issue" (or "No related issue:") in the body instead.

Edit the body and this comment updates itself on the next run.

On 2026-09-14 `/claude-ops:plugins sync --all` run with the `install_new`
userConfig set to `all` installed 2,231 plugins across every known
marketplace in 22 minutes, ~49 GB of cache, and left 22 third-party MCP
servers running for 8.5 hours. Against the one curated marketplace the
policy was written for, `all` means "install the handful I am missing";
`--all` multiplies it across every catalog the machine knows about, and the
wording does not change between the two cases.

gotchas.md: new section recording the incident, why the downgrade guard and
`audit` both miss this combination, the `claude --bare` requirement for the
revert (a plain `plugin uninstall` spawns a session that loads every still-
enabled plugin and boots its MCP servers), and the revert recipe.

SKILL.md: the marketplace-resolution list now warns that `all` multiplies
the install policy across catalogs, and the `install_new` section requires a
counted human confirmation before that combination runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XD4Hr2S7RA2G8PR2CadLP1
@kyle-sexton
kyle-sexton force-pushed the docs/plugins-skill-mass-install-gotcha branch from 805c753 to 1c1f516 Compare September 15, 2026 15:02
check-changelog-parity --check-bump refuses to reuse a published version
when a change set touches shipped plugin files, documentation included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XD4Hr2S7RA2G8PR2CadLP1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant