Skip to content

fix(plugin-dev): align userConfig docs and hook validator with v2.1.207 shell-injection fix - #76576

Open
1837620622 wants to merge 1 commit into
anthropics:mainfrom
1837620622:fix/plugin-dev-user-config-shell-form
Open

fix(plugin-dev): align userConfig docs and hook validator with v2.1.207 shell-injection fix#76576
1837620622 wants to merge 1 commit into
anthropics:mainfrom
1837620622:fix/plugin-dev-user-config-shell-form

Conversation

@1837620622

@1837620622 1837620622 commented Jul 11, 2026

Copy link
Copy Markdown

Summary

Claude Code v2.1.207 rejected ${user_config.*} in shell-form plugin hook / monitor / MCP headersHelper commands (shell-injection fix) and stopped reading pluginConfigs from project-level .claude/settings.json. The hosted plugins reference still shows the old unsafe monitor example (see #76567 / #76568).

This PR updates the in-repo plugin author toolkit (plugin-dev) that Claude and authors actually use when scaffolding plugins—so generated plugins do not ship configs that fail after upgrade.

What was wrong in this repo

  1. userConfig was undocumented in plugin-structure / manifest-reference, so authors had no safe pattern for enable-time options.
  2. validate-hook-schema.sh rejected real bundled plugins:
    • Real hooks/hooks.json files use {"description", "hooks": {...}}; the validator treated hooks / description as unknown events.
    • matcher is optional (official hooks docs + every bundled plugin omit it in places); the validator required it.
  3. The validator never flagged shell-form ${user_config.*}, so authors could not catch a v2.1.207 break before shipping.
  4. Arithmetic counters used ((error_count++)) under set -e, which aborts on the first error (post-increment of 0 is falsy).

Changes

Area Change
manifest-reference.md Full userConfig schema, storage scopes (user / --settings / managed only), safe vs rejected substitution rules
plugin-structure/SKILL.md Short userConfig section with v2.1.207 caveats
hook-development/SKILL.md Exec form preference, $CLAUDE_PLUGIN_OPTION_<KEY>, shell-form ban table
mcp-integration/.../authentication.md headersHelper migration: pass options via env, not the helper command string
validate-hook-schema.sh Unwrap plugin wrapper; optional matcher; error on shell-form ${user_config.*}; safe counters
plugin-validator.md Security checks for shell-form options + project-scope note
scripts README Documents the new checks

Evidence

Aligned with CHANGELOG.md 2.1.207:

Plugin hooks/monitors/MCP headersHelper: ${user_config.*} in shell-form commands is now rejected (shell-injection fix). Hooks: use exec form (args array) or $CLAUDE_PLUGIN_OPTION_<KEY>; monitors and headersHelper: read the value inside the script (config file or the server's env block).

Plugin option values (pluginConfigs) are no longer read from project-level .claude/settings.json; only user, --settings, and managed settings are honored.

Hosted docs still show the unsafe monitor example (poll-deploy.sh ${user_config.api_endpoint}) on https://code.claude.com/docs/en/plugins-reference — this PR does not modify that site (not present in this repository). Updating the author toolkit closes the gap for plugin authors using plugin-dev today.

Verification

# All five bundled plugins that ship hooks/hooks.json — now pass
bash plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh \
  plugins/explanatory-output-style/hooks/hooks.json   # exit 0
bash plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh \
  plugins/hookify/hooks/hooks.json                    # exit 0
bash plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh \
  plugins/learning-output-style/hooks/hooks.json      # exit 0
bash plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh \
  plugins/ralph-wiggum/hooks/hooks.json               # exit 0
bash plugins/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh \
  plugins/security-guidance/hooks/hooks.json          # exit 0

# Shell-form user_config — fails with clear migration guidance
# Exec-form / direct settings map — still pass

Related issues

Note: The Mintlify/site pages named in those issues live outside this public tree. This PR lands the same corrections in the shipped plugin-dev skills and validator so authors are not taught the unsafe pattern while generating plugins in-product.

Test plan

  • Validator passes on all five bundled plugins that ship hooks/hooks.json
  • Shell-form ${user_config.*} returns exit 1 with fix instructions
  • Exec-form and direct event-map fixtures still pass
  • Docs cite v2.1.207 changelog behavior and safe migrations only

….1.207

Claude Code v2.1.207 rejects ${user_config.*} in shell-form plugin hook,
monitor, and MCP headersHelper commands (shell-injection fix), and no
longer reads pluginConfigs from project settings. The plugin-dev toolkit
did not document userConfig at all and the hook schema validator treated
real plugin hooks.json files (wrapper format, optional matcher) as
invalid.

- Document userConfig schema, storage scopes, and safe migration paths
- Teach exec-form / CLAUDE_PLUGIN_OPTION_* patterns for hooks and headersHelper
- Fix validate-hook-schema.sh: unwrap plugin format, optional matcher,
  flag shell-form ${user_config.*}, fix set -e counter arithmetic
- Align plugin-validator security checks with the same rules

Addresses anthropics#76567 and anthropics#76568 for the in-repo author toolkit.
@1837620622

Copy link
Copy Markdown
Author

Ready for review

This aligns the in-repo plugin author toolkit with Claude Code v2.1.207 shell-injection hardening:

Minimal & correct: docs + validator only — no runtime product binary changes.

Happy to iterate on wording or test fixtures.

— 传康Kk (@1837620622)

@1837620622

Copy link
Copy Markdown
Author

Second-pass validation (maintainer-ready)

Post-landing checklist re-run on 8894c49 so reviewers do not have to rediscover scope:

Check Result
validate-hook-schema.sh on all 5 plugins/*/hooks/hooks.json exit 0 each (explanatory-output-style, hookify, learning-output-style, ralph-wiggum, security-guidance)
Shell-form ${user_config.*} fixture exit 1 + migration hint
Exec-form args + direct event-map fixtures exit 0
Hosted site pages from #76567 / #76568 Not in this tree (public repo = plugins / examples / CHANGELOG). PR intentionally targets the in-repo plugin-dev toolkit only
Diff size 7 files, +284 / −30 — single theme (userConfig safety + validator truthfulness). Not a candidate for split without losing the docs↔validator coupling

Factual alignment for the new userConfig section is against CHANGELOG.md 2.1.207 (shell-form reject + project pluginConfigs ignored) and the current hosted schema fields for option types. No further code changes pending from this pass.

Happy to take wording nits on the migration table if a docs owner wants different emphasis between exec-form args and pure $CLAUDE_PLUGIN_OPTION_*.

— 传康Kk (@1837620622)

@1837620622

Copy link
Copy Markdown
Author

Friendly review ping 🙏

Aligns the in-repo plugin-dev toolkit with Claude Code v2.1.207 shell-injection rules (user_config / exec-form / validator). Happy to address feedback.

@1837620622

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant