Blog · Developer Tools

Claude Code Plugin Binaries

By Fabio Douek

Overview

Claude Code v2.1.91, released April 2, 2026, quietly shipped one of the more consequential plugin system changes since the plugin system launched: plugins can now include native executables in a bin/ directory, and those executables are automatically added to the Bash tool’s PATH.

The changelog entry is a single line:

Plugins can now ship executables under bin/ and invoke them as bare commands from the Bash tool.

That undersells it. Until now, the plugin system was built primarily around interpreted content: Markdown skills, JSON configurations, shell scripts referenced by full path. MCP servers could already ship compiled binaries as their server process, but those were opaque to the Bash tool and required MCP protocol wrappers. Adding first-class bin/ support changes the trust model, unlocks new categories of plugins, and brings Claude Code closer to how mature plugin ecosystems like VS Code extensions handle native tooling.

This post digs into how it works under the hood, what the binary introspection of v2.1.91 reveals about the implementation, and what this means for plugin authors and users. This analysis is based on the official documentation, changelog, and binary inspection of v2.1.91, not hands-on testing with a plugin.

Setup

The surface-level usage is dead simple. The plugins reference has been updated to show bin/ as a first-class directory in the plugin layout:

my-plugin/
├── .claude-plugin/
│   └── plugin.json
├── commands/
├── agents/
├── skills/
├── hooks/
├── bin/                      # Plugin executables added to PATH
│   └── my-tool               # Invokable as bare command in Bash tool
├── scripts/
├── .mcp.json
└── README.md

Drop an executable in bin/, install the plugin, and Claude can invoke my-tool directly in any Bash tool call. No full paths, no ${CLAUDE_PLUGIN_ROOT}/bin/my-tool gymnastics. It’s just on PATH.

This is distinct from the existing scripts/ directory, which requires explicit path references via ${CLAUDE_PLUGIN_ROOT}/scripts/process.sh and is primarily used by hooks and skills.

How It Works

How Binaries Get on PATH

When a plugin with a bin/ directory is enabled, Claude Code adds that directory to the Bash tool’s PATH. The mechanism is tied to the plugin lifecycle: enabling the plugin makes bin/ executables available, disabling it removes them. This is scoped to Claude’s Bash tool, not your system shell.

One practical note: executables in bin/ must have the executable bit set (chmod +x). This is the same requirement as hook scripts, but easy to forget when committing binaries to a Git repo, since Git only tracks the executable bit on Unix-like systems.

Security Considerations

The bin/ convention has no built-in integrity checking. If you install a plugin from a Git-based marketplace, you’re trusting the repo’s integrity. The official Anthropic marketplace is vetted, but community marketplaces offer no equivalent verification for binary content.

A few other things I noticed are missing or undocumented:

  • No architecture targeting: There’s no arm64 vs x64 distinction. On Apple Silicon Macs, plugin authors would need to ship universal binaries or detect architecture themselves.
  • No runtime sandboxing: Binary executables run with the same permissions as Claude Code itself. There’s no seccomp, sandbox-exec, or capability restriction beyond what the user’s permission mode provides.
  • No hash verification: There’s no checksum or signature validation for executables in the bin/ directory. If a plugin ships a binary, you’re trusting the source.

Mitigations: disableSkillShellExecution and Friends

Shipping bin/ support in the same release as new security controls was not a coincidence. v2.1.91 also introduced the disableSkillShellExecution setting, which disables inline shell execution in skills, custom slash commands, and plugin commands.

Skills support two syntaxes for running shell commands during prompt preprocessing: fenced blocks (```!) and inline commands (!`command`). These execute before the prompt reaches Claude, injecting live output into the skill’s context. When disableSkillShellExecution is true, both syntaxes are replaced with [shell command execution disabled by policy] instead of being executed.

To be clear: this setting does not block bin/ executables. Those run through the Bash tool at Claude’s discretion, not through skill preprocessing. What it does is prevent a plugin’s skill files from silently running shell commands as a side effect of being loaded. For organizations evaluating plugins that ship binaries, this is the difference between “this plugin provides tools Claude can invoke with your approval” and “this plugin runs code the moment its skill activates.”

Configuration is a one-liner in any settings.json scope:

{
  "disableSkillShellExecution": true
}

Enterprise admins can enforce it via managed policy settings, where it takes precedence over user settings.

This is part of a broader set of enterprise controls shipped alongside bin/:

SettingWhat it controls
disableSkillShellExecutionBlocks inline shell in skills/commands
disableAllHooksDisables all hooks and statusLine execution
allowManagedHooksOnlyOnly admin-deployed hooks run
strictPluginOnlyCustomizationBlocks non-plugin skills, hooks, MCP, or agents
allowManagedMcpServersOnlyOnly admin-approved MCP servers

The combination of disableSkillShellExecution and strictPluginOnlyCustomization gives enterprises a tight perimeter: only vetted plugin skills load, and none of them can execute shell commands during preprocessing. Binary executables in bin/ still require explicit Bash tool invocation, which is governed by the user’s permission mode.

Backwards Compatibility

This is fully backwards compatible. Plugins without a bin/ directory work exactly as before. The plugin.json manifest schema has no new required fields. The bin/ directory is auto-discovered by convention, similar to how commands/, agents/, and skills/ directories work when no explicit paths are set in the manifest.

Existing plugins that ship executables under scripts/ and reference them via ${CLAUDE_PLUGIN_ROOT}/scripts/... continue to work. The bin/ directory is an addition, not a replacement.

Comparison to VS Code Extensions

VS Code has supported native binaries for years through platform-specific extension packages. The comparison is instructive:

AspectVS CodeClaude Code
Platform targeting--target flag with specific platform-arch combos (win32-x64, darwin-arm64, linux-x64)No built-in platform targeting
DistributionVSIX packages via marketplaceGit repos or local directories
SigningPublisher verification via marketplaceNo binary signing (marketplace vetting only)
Binary discoveryExtension API, explicit pathsAuto-added to PATH
Build integrationNative Node modules must compile against Electron’s Node versionNo build constraints

Claude Code’s approach is significantly simpler: drop a binary in bin/ and it works. VS Code’s is more mature but carries years of complexity around native Node module compilation, Electron version pinning, and platform matrix builds.

Verdict

The bin/ feature solves a real limitation. Before v2.1.91, plugins that needed compiled tools had awkward workarounds: shell scripts that downloaded binaries at runtime, MCP servers wrapping CLI tools assumed to be pre-installed, or instructions telling users to brew install dependencies manually. Now a plugin can just ship the tool.

Who Benefits

Plugin authors building developer tooling get the most value. Think linters, formatters, code generators, and language-specific analysis tools that are written in Go, Rust, or C++ and don’t fit neatly into Node or Python MCP server wrappers. A plugin could ship a single compiled binary alongside skills that use it, making the plugin fully self-contained. No pip install dependencies, no node_modules, just a binary that works.

The security-conscious should pay attention. Plain-text plugins have the advantage of being auditable. Now that bin/ is a first-class feature, the ecosystem needs to evolve its trust model. There’s currently no binary signing or hash verification for the bin/ convention, so you’re relying on marketplace vetting and Git repo integrity.

What I’d Like to See Next

Architecture-aware platform targeting (arm64 vs x64) would close the gap with VS Code. Some form of binary attestation, whether checksums, signatures, or both, would strengthen the trust model for community marketplaces. And documentation is still catching up: GitHub issue #42872 identifies several undocumented areas around bin/ behavior, packaging requirements, and Bash tool integration.

This is a v1 of binary support, and it shipped as a one-liner in a changelog with 12 items. But it’s the kind of infrastructure change that compounds. For my own use, I’m already looking at shipping single Go binaries instead of Python scripts with fragile dependency chains. I expect others will find similar reasons to reach for bin/.

Comments