Plugin manifest should support `permissions.allow` for bundled console scripts
Summary
A plugin that ships its own console-script binaries (e.g., this one bundles five: agent-coherence-status, agent-coherence-track, agent-coherence-untrack, agent-coherence-coordinator, agent-coherence-migrate-deny) has no current Claude Code mechanism to pre-allow those binaries in the Bash permission system. Every plugin slash command that invokes a bundled binary fires a per-invocation Bash permission prompt that the operator must approve. Plugin-shipped permission allowlists would close the gap.
Observed behavior
A plugin slash command (commands/status.md) declares allowed-tools: ["Bash"] in frontmatter and invokes a bundled binary. Operator invokes the skill; Bash permission prompt fires for the binary; operator must Allow once / Allow always or Deny per invocation.
Screenshot (Phase E broad-beta monitoring 2026-05-26 — operator-side, v0.2.0 on the marketplace):
[attach the screenshot showing the rejected agent-coherence-status invocation]
The plugin-author intent expressed by the skill's allowed-tools: ["Bash"] is "this skill may use the Bash tool" — but the per-command permission gate still trips because the bundled binary isn't in the workspace's permissions.allow set. The operator has to maintain that set per-workspace per-plugin, and re-discover the workaround every time they install the plugin in a new workspace.
What I tried
I authored the plugin and worked through every documented surface for shipping a default allowlist with it:
- Adding
permissions.allowto.claude-plugin/plugin.json— no schema field, silently ignored. - Adding
permissions.allowto plugin-rootsettings.json— per the plugins-reference doc: "Default configuration applied when the plugin is enabled. Only theagentandsubagentStatusLinekeys are currently supported" (emphasis added). - Putting per-command granularity in skill frontmatter —
allowed-tools: [Bash(my-tool:*)]shape isn't accepted; the field is coarse-grained tool names only. - Shipping
.claude/settings.jsonpackaged with the plugin —.claude/is gitignored by convention and isn't distributed with the plugin. - Using the
bin/directory — correctly adds the binary toPATH(helpful for distribution!) but doesn't interact with the permission system.
The only working operator-side workaround is documenting in the plugin README that users should add the allowlist to .claude/settings.local.json:
{
"permissions": {
"allow": [
"Bash(agent-coherence-status:*)",
"Bash(agent-coherence-track:*)",
"Bash(agent-coherence-untrack:*)",
"Bash(agent-coherence-coordinator:*)",
"Bash(agent-coherence-migrate-deny:*)"
]
}
}
This works but places friction on every operator individually.
Proposed shape (minimum viable)
Allow plugins to ship a permissions.allow array in .claude-plugin/plugin.json, scoped to commands matching binaries the plugin actually ships (the bin/ directory's contents, plus any console-script entry points). Allowlist entries are merged into the active permission set when the plugin is enabled, removed when disabled. Per-binary granularity already matches the existing Bash(command:*) pattern from .claude/settings.json:
// .claude-plugin/plugin.json
{
"name": "my-plugin",
"version": "1.0.0",
"permissions": {
"allow": [
"Bash(my-tool:*)",
"Bash(my-tool-status:*)"
]
}
}
Scope intentionally narrow:
- Only
permissions.allow— notpermissions.deny; plugin-shipped denies could be safety-relevant but also become a misuse vector. Defer. - Only commands matching binaries the plugin ships — validated against
bin/and console-script declarations. Plugins can't pre-allowBash(rm -rf:*)or anything outside their own surface. - Operator can still override — workspace-level
.claude/settings.jsonpermissions.denyalways wins over plugin-shippedpermissions.allow.
Why this matters
Plugins that need any bundled binary at all (any storage/state primitive, any orchestrator, any local-server pattern) hit this gap. Without the platform mechanism, every plugin author re-implements the same operator workaround and every operator re-discovers the same friction. The current "skill allowed-tools: [Bash]" surface implies plugin authors can declare what their skills need, but only at coarse-grained tool granularity — the per-command gate then trips invisibly.
Plugin-shipped allowlists scoped to the plugin's own surface preserve the trust boundary (operator still controls what the plugin can do; plugin still self-declares its own binary set) while eliminating the per-invocation friction.
Not asking for
- General-purpose plugin-shipped Bash allowlists (e.g.,
Bash(curl:*)) — those should stay operator-controlled permissions.denyat the plugin level — different threat model; defer- A model for cross-plugin permission inheritance — single plugin, single allowlist scope
Context
Authoring agent-coherence-plugin — a coordination-protocol plugin shipping 5 bundled binaries. v0.2.0 live on the marketplace 2026-05-24; Phase E broad-beta monitoring window through 2026-06-08 surfaced the operator-UX gap from a real install attempt.
Happy to put together a small reference plugin that demonstrates the proposed shape if useful for the review thread.