Skip to content

claude-ops: install_new userConfig has no default, leaves literal placeholder unrendered #786

Description

@kyle-sexton

Bug

claude-ops's plugins skill (SKILL.md) references ${user_config.install_new} expecting Claude Code to substitute the configured value (or fall back to "ask") before the model sees the rendered skill. When the option is unset, the literal string ${user_config.install_new} leaks through unrendered instead.

Root cause

In plugin.json, the install_new userConfig entry has no "default" key:

"install_new": {
  "type": "string",
  "title": "New-plugin install policy for the plugins skill's sync action",
  "description": "Controls what `sync` does with catalog plugins that aren't installed yet. Valid values: \"ask\" (default — offer them in one batched multi-select prompt), \"all\" (install every one automatically), \"none\" (report only, never install). The manifest schema has no enum type, so this validates in prose, not JSON Schema; any other value is treated as \"ask\"."
}

Compare to the boolean options in the same manifest (e.g. api_error_audit_enabled), which all declare "default": true. Those presumably substitute correctly when unset; install_new has no such declared default, so there's nothing for Claude Code to substitute when the user hasn't configured it, and the raw template placeholder passes through into the skill body.

Impact

plugins sync's Step 4 (install new catalog plugins) cannot reliably branch on the configured policy — the skill has to detect the unrendered placeholder itself and fall back to ask, rather than the substitution mechanism doing it. SKILL.md's own text ("Any other value is invalid; treat it as ask") assumes a rendered but wrong value, not a never-rendered one — this is a distinct failure mode.

Suggested fix

Add "default": "ask" to the install_new userConfig entry in plugin.json, matching the documented default and the pattern used by every other option in the manifest.

Repro

  1. Do not set install_new in any settings scope.
  2. Invoke /claude-ops:plugins sync.
  3. Observe the skill's "Configured value: ${user_config.install_new}" line render with the literal placeholder instead of a substituted value.

Metadata

Metadata

Assignees

Labels

priority: mediumReal value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions