[FEATURE] Stable path to a plugin's installed version (or @import variable expansion), so orgs can ship versioned CLAUDE.md content in plugins
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
(Filed via gh CLI before noticing this repo disables blank issues — body restructured after the fact to match the feature-request form. Apologies for the missing auto-applied enhancement label.)
Problem Statement
Our engineering org distributes a shared CLAUDE.md (team conventions, guardrail context) through a private plugin marketplace. Each engineer's ~/.claude/CLAUDE.md imports it straight out of the marketplace clone:
@~/.claude/plugins/marketplaces/<marketplace>/CLAUDE.md
That works, but the file is unversioned — it updates on every marketplace refresh, while everything else we ship (hooks, skills, agents) is version-pinned through plugins and gated by a version-bump CI check. We want the shared instruction layer to get the same treatment: ship inside a plugin, so instruction changes are bump-gated, atomic with the plugin behavior they describe, and rollbackable.
Two things block that today:
- Installed plugins land at a version-suffixed path —
~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/— and old versions are retained, so there is no stable on-disk path for "the currently-installed version of this plugin." @importlines in CLAUDE.md get no variable expansion.${CLAUDE_PLUGIN_ROOT}exists only inside hook/command execution contexts, so an import can't reach the current version dynamically.
A static import pinned to .../0.2.4/CLAUDE.md goes silently stale on the next bump, which is worse than what we have.
Proposed Solution
Any one of these solves it (listed cleanest-last):
- A stable
currentsymlink in the plugin cache, maintained by the installer:~/.claude/plugins/cache/<marketplace>/<plugin>/current/→ the installed version. Static imports could then target it. - Variable expansion in
@importpaths, e.g.@${CLAUDE_PLUGIN_ROOT:<plugin>@<marketplace>}/CLAUDE.md. - Native plugin memory: let a plugin bundle a
CLAUDE.mdthat loads with memory authority (and propagates to subagents) when the plugin is enabled. This is the cleanest shape — plugins can already ship skills/commands/agents/hooks/MCP, and instruction content is the one distribution channel missing.
Alternative Solutions
- Current approach: import from the marketplace clone (works, unversioned, updates on every refresh).
- Considered and rejected: a SessionStart hook that maintains the symlink itself. It means instruction delivery depends on hook machinery — a disabled plugin or skipped hook leaves a dangling/stale symlink and the shared layer silently vanishes, the failure mode we adopted the marketplace-clone import to escape.
- Also rejected earlier (spike evidence): injecting the instructions via a SessionStart hook's
additionalContext— injected context carries lower authority than memory and does not propagate to subagents.
Priority
Medium - Would be very helpful
Feature Category
Configuration and settings
Use Case Example
- Platform team ships conventions + guardrail hooks as plugins in a private marketplace; a CI gate requires a version bump on every plugin change.
- A conventions change lands that describes new hook behavior.
- Today: the CLAUDE.md text can reach engineers before the hook version ships (instructions ride the clone, hooks ride the version pin) — we carry a standing rule that shared-layer text must not depend on unreleased plugin behavior.
- With this feature: the instruction text ships inside the same plugin version as the behavior it describes — atomic, rollbackable, and covered by the same CI gate.