--dangerously-load-development-channels does not register a channel; only allowedChannelPlugins works
--dangerously-load-development-channels does not register a channel; only allowedChannelPlugins works
Summary
Per the channels reference, a channel plugin under development should be loadable with:
claude --dangerously-load-development-channels plugin:yourplugin@yourmarketplace
On 2.1.220 this flag has no observable effect. The channel is never registered, no error surfaces, and the documented confirmation dialog never appears. The only way we could get a non-allowlisted channel to register was an admin allowedChannelPlugins entry in /etc/claude-code/managed-settings.json — which the docs present as an enterprise alternative, not a prerequisite for local development.
Net effect: there appears to be no working path for developing a channel plugin without root access to the machine.
Environment
- Claude Code 2.1.220 (native installer)
- Linux (kernel 6.8), bash
- Plugin installed from a local directory marketplace,
--scope local, confirmed enabled - MCP server declares
capabilities.experimental['claude/channel']and connects successfully
Reproduction
Uses only first-party code, so no third-party plugin is needed. The point is to give fakechat a non-allowlisted identity.
- Copy
external_plugins/fakechatfromanthropics/claude-plugins-officialinto a scratch marketplace, renaming both the plugin and the marketplace so it is no longer on the approved allowlist:
````
ctl-mp/
.claude-plugin/marketplace.json → { "name": "probe-mp", "plugins": [{ "name": "notchat", "source": "./plugins/notchat" }] }
plugins/notchat/ → verbatim fakechat, with plugin.json name → "notchat"
and .mcp.json server key → "notchat"
- Install it and launch with the documented development flag:
``bash``
claude plugin marketplace add ./ctl-mp
claude plugin install notchat@probe-mp --scope local
claude --debug --dangerously-load-development-channels plugin:notchat@probe-mp
- Read
~/.claude/debug/<session-id>.txt.
Expected
The channel registers. Per the docs, a full-screen warning dialog appears first ("I am using this for local development"), then a startup notice reading messages from plugin:notchat@probe-mp inject directly in this session.
Actual
The MCP server starts and connects normally (fakechat: http://localhost:8799 on stderr, tools discovered), but:
MCP server "plugin:notchat:notchat": Channel notifications skipped:
server plugin:notchat:notchat not in --channels list for this session
No warning dialog appears. No startup notice appears. Nothing is written to the session or to stderr — the failure is only visible under --debug.
What we tried
All on 2.1.220, against both the fakechat clone above and a separate third-party channel plugin, across entry forms server:x, plugin:x:x, and plugin:x@marketplace, in default and bypassPermissions permission modes:
| Launch | Debug-log verdict |
|---|---|
| --dangerously-load-development-channels plugin:x@mp | not in --channels list for this session |
| --channels plugin:x@mp + --dangerously-load-development-channels plugin:x@mp | is not on the approved channels allowlist (use --dangerously-load-development-channels for local dev) |
| --channels plugin:x@mp, with allowedChannelPlugins set | Channel notifications registered ✅ |
| --dangerously-load-development-channels plugin:x@mp, with allowedChannelPlugins set | not in --channels list for this session |
Two things stand out:
- The second row is self-contradicting. Claude Code advises using
--dangerously-load-development-channelsin the same message produced by a session that was passed exactly that flag with exactly that value. - The flag never enters its entry into the channels list. Row 1 fails with "not in
--channelslist", so the flag does not imply enablement. But rows 2 and 4 show it does not bypass the allowlist either — so it does not appear to do anything at all. Removing theallowedChannelPluginsentry breaks registration again even with the flag present.
Workaround
Add the plugin to /etc/claude-code/managed-settings.json and use --channels alone:
{"channelsEnabled":true,
"allowedChannelPlugins":[{"marketplace":"your-marketplace","plugin":"yourplugin"}]}
This requires root and, since the list replaces the default Anthropic allowlist rather than extending it, every channel plugin already in use must be re-listed or it silently stops working.
Secondary: a manually-configured MCP server silently shadows a plugin's channel
Related, and it cost us several hours before we found it. If an .mcp.json or --mcp-config entry happens to use the same server name as a plugin's own server, the plugin's server is suppressed:
Suppressing plugin MCP server "plugin:msteams:msteams": duplicates manually-configured "msteams"
The surviving server is then server:msteams, so a --channels plugin:msteams@marketplace entry can never match it, and the channel silently fails to register. Both lines are [DEBUG]-level, so with no --debug the symptom is simply that inbound events vanish.
Two smaller notes in the same area:
- The
Channels (experimental)startup banner prints even when registration was skipped, so it is not a usable signal that a channel is live. --plugin-diryields the server idplugin:<name>:<name>with no marketplace component, so aplugin:<name>@<marketplace>entry can never match a plugin loaded that way. Worth documenting, since--plugin-diris otherwise the natural choice while developing.
Suggested fixes
- Make
--dangerously-load-development-channelsactually register its entries, or emit a real error when it declines to. - Never advise a flag in a message produced by a session that was already given that flag.
- Promote the "channel skipped" lines from
[DEBUG]to a visible warning — a silently dead channel is very expensive to diagnose. - Document that
allowedChannelPluginsreplaces rather than extends the default allowlist.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗