[BUG] `--plugin-dir` silently drops all but the last directory when specified multiple times
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
When loading multiple plugins via --plugin-dir, only the last directory takes effect — all earlier directories are silently discarded. This happens with both the repeated-flag form (--plugin-dir A --plugin-dir B) and the variadic form (--plugin-dir A B).
The CLI help explicitly advertises multi-directory support:
--plugin-dir <paths...> Load plugins from directories for this session only (repeatable)
Single plugin works correctly; multiple plugins fail silently.
What Should Happen?
All specified plugin directories should be loaded. claude --plugin-dir ./pluginA --plugin-dir ./pluginB should load both pluginA and pluginB.
Error Messages/Logs
No errors or warnings are emitted. The earlier --plugin-dir values are silently discarded.
Steps to Reproduce
A full reproduction repository is available at:
https://github.com/pers0n4/claude-code/tree/fix/plugin-dir-multi-load-repro/repro/plugin-dir-multi-load
1. Create two minimal test plugins
Each plugin has a single SessionStart hook that writes a unique marker file to /tmp/.
plugin-alpha/ plugin-beta/
├── .claude-plugin/ ├── .claude-plugin/
│ └── plugin.json │ └── plugin.json
└── hooks/ └── hooks/
├── hooks.json ├── hooks.json
└── session-start.mjs └── session-start.mjs
↓ writes alpha-loaded.txt ↓ writes beta-loaded.txt
<details>
<summary>plugin-alpha source (click to expand)</summary>
.claude-plugin/plugin.json:
{
"name": "plugin-alpha",
"version": "0.0.1",
"description": "Minimal test plugin A for --plugin-dir verification"
}
hooks/hooks.json:
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs\"",
"timeout": 5
}
]
}
]
}
}
hooks/session-start.mjs:
import { writeFileSync, mkdirSync } from "node:fs";
const dir = "/tmp/plugin-dir-repro-results";
mkdirSync(dir, { recursive: true });
writeFileSync(
`${dir}/alpha-loaded.txt`,
`alpha loaded at ${new Date().toISOString()}\n`,
{ flag: "a" },
);
console.log(JSON.stringify({ continue: true }));
</details>
plugin-beta is identical except it writes beta-loaded.txt.
2. Run the tests
# Clone the repro and cd into it
git clone -b fix/plugin-dir-multi-load-repro https://github.com/pers0n4/claude-code.git /tmp/repro
cd /tmp/repro/repro/plugin-dir-multi-load
# Or run the automated test script:
bash run-test.sh
Manual steps:
ALPHA=/tmp/repro/repro/plugin-dir-multi-load/plugin-alpha
BETA=/tmp/repro/repro/plugin-dir-multi-load/plugin-beta
RESULTS=/tmp/plugin-dir-repro-results
# Single directory — works correctly
rm -rf $RESULTS
claude --plugin-dir $ALPHA -p "say hi"
ls $RESULTS/ # → alpha-loaded.txt ✅
rm -rf $RESULTS
claude --plugin-dir $BETA -p "say hi"
ls $RESULTS/ # → beta-loaded.txt ✅
# Multiple directories — only last one loads (BUG)
rm -rf $RESULTS
claude --plugin-dir $ALPHA --plugin-dir $BETA -p "say hi"
ls $RESULTS/ # → beta-loaded.txt only ❌ (alpha missing)
rm -rf $RESULTS
claude --plugin-dir $BETA --plugin-dir $ALPHA -p "say hi"
ls $RESULTS/ # → alpha-loaded.txt only ❌ (beta missing)
# Variadic syntax — same bug
rm -rf $RESULTS
claude --plugin-dir $ALPHA $BETA -p "say hi"
ls $RESULTS/ # → beta-loaded.txt only ❌ (alpha missing)
3. Result matrix
| Command | alpha-loaded.txt | beta-loaded.txt | Status |
|---------|:---:|:---:|:---:|
| --plugin-dir alpha | Yes | — | Pass |
| --plugin-dir beta | — | Yes | Pass |
| --plugin-dir alpha --plugin-dir beta | No | Yes | Fail |
| --plugin-dir beta --plugin-dir alpha | Yes | No | Fail |
| --plugin-dir alpha beta (variadic) | No | Yes | Fail |
Result: In every multi-directory case, only the last directory's plugin is loaded.
Claude Code Version
2.1.45 (Claude Code)
Operating System
macOS 26.3
Terminal/Shell
Ghostty/zsh
Additional Information
Root cause hypothesis:
The CLI help defines --plugin-dir as <paths...> (variadic) with (repeatable), which suggests the argument parser collects multiple values into an array. However, the downstream plugin loading code appears to only consume the last element of that array — either by treating it as a scalar string or by iterating but overwriting state on each pass.
Workaround:
Install one plugin permanently via claude plugin add, then use --plugin-dir for the remaining plugin that needs local testing.
Reproduction repository:
https://github.com/pers0n4/claude-code/tree/fix/plugin-dir-multi-load-repro/repro/plugin-dir-multi-load
Includes:
- Two minimal test plugins (plugin-alpha, plugin-beta)
- Automated test script (
run-test.sh) - README with expected vs actual results
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗