[BUG] Organization plugin sync strips plugin.json `types`, so function-hooks mods that use $.state fail to load
Preflight Checklist
- [x] I have searched existing issues. #31384 / #27180 / #26555 (closed) were the mirror image, where marketplace-added manifest keys were rejected; #100818 (open) is the same organization sync ignoring
iconandauthor. No report coverstypesbeing stripped. - [x] This is a single bug.
What's Wrong?
When a plugin is distributed through Organization settings > Plugins & skills > Sync from GitHub, the sync validates .claude-plugin/plugin.json against the plugin SDK schema and drops top-level keys it does not know. One of those keys is types, which the function-hooks (Mods) engine uses to find a mod's PluginState contract.
The engine reads that contract from the manifest's top-level types key only (the function-hooks reference names no other location). Without it the hooks-module validator refuses every $.state key the module declares, so the copy the organization sync produces cannot load, while the same plugin installed from the CLI (/plugin install <name> --marketplace <owner>/<repo>) or through managed extraKnownMarketplaces / enabledPlugins works, because those paths copy the manifest whole.
Effect: any mod that uses $.state works for individuals and breaks for exactly the audience an organization marketplace is for.
What Should Happen?
Either of:
- The organization sync passes unknown top-level manifest keys through unchanged (a warning is fine, stripping is not), or
typesis added to the schema the sync validates against, since the function-hooks reference documents it as the location of the state contract.
Error Messages/Logs
Organization sync warning (claude.ai, Plugins & skills, after the repo synced):
Plugin 'pii-guard' has unrecognized key in plugin.json: 'types' (stripped — the SDK ignores unknown top-level fields)
Local reproduction of what the stripped copy does, by removing the key from a checkout and running the bundled validator:
$ claude plugin validate pii-guard
✘ pii-guard.configVersion is not declared: the manifest's types contract must name it ...
✘ pii-guard.paused is not declared: the manifest's types contract must name it ...
✘ pii-guard.queue is not declared: ...
✘ pii-guard.review is not declared: ...
✘ pii-guard.sessionAllows is not declared: ...
✘ pii-guard.settingsOpen is not declared: ...
(claude plugin test still passes on the stripped copy because the test kit answers $.state itself, so the breakage is only visible at validate/load time.)
Steps to Reproduce
- Take a function-hooks plugin whose
plugin.jsonhas"types": "./types/index.d.ts"and whose hooks module declares$.stateatoms. Public example at the exact version: https://github.com/dave-net-positive/Claude_Code_PII_Redactor/tree/v1.4.0 (pii-guard/.claude-plugin/plugin.json,pii-guard/types/index.d.ts,pii-guard/hooks/register.tsx). claude plugin validate pii-guardon the checkout: passes.- Sync the repo as an organization plugin from claude.ai Plugins & skills.
- The sync reports the warning above and the published manifest has no
typeskey. - Remove the key from the local checkout and run
claude plugin validate pii-guardagain: the six errors above.
Workaround used in v1.4.1 of the same repo: keep session state in module variables and redraw with $.ui.invalidate('ui.render'), so the mod no longer needs a types contract at all. That costs state continuity across hot reload and is not available to mods that need $.state semantics.
Claude Model
n/a (plugin loading)
Is this a regression?
Not known to have worked; the organization sync and Mods shipped recently.
Last Working Version
n/a
Claude Code Version
2.1.295 (bundled with the Claude desktop app; the same build's claude plugin validate produced the errors above)
Platform
Claude desktop app (Windows) for the local side; claude.ai organization settings for the sync
Operating System
Windows 11 Pro 10.0.26300
Terminal/Shell
n/a (desktop app); PowerShell 7 for the validator runs
Additional Information
- Sibling report on the same sync ignoring other manifest fields: #100818.
- Mods feedback thread: #91870.
- Both the pre-fix (v1.4.0) and post-fix (v1.4.1) plugin are public in the repo above, so the before/after manifests can be diffed directly.