← Blog

Dev/Prod Namespace Isolation for Claude Code Plugins

If you develop a Claude Code [1] plugin and your users have it installed from the marketplace, you have a collision problem. Two plugins named tts. Two /say commands. Two MCP [2] servers. Claude Code sees both, and the collision behavior is undefined. That’s not a development workflow.

Here’s the pattern we’ve been using across seven plugins [3].

The -dev Suffix

The working tree uses name: "tts-dev" in plugin.json. The marketplace version uses name: "tts". Launch Claude Code with --plugin-dir . and both load simultaneously — dev commands appear at /tts-dev:say, prod at /tts:say. Every extension point namespaces cleanly: commands, MCP tools, skills, agents, hooks.

This gives you side-by-side testing. You can verify that the dev plugin works against the currently-installed prod version without uninstalling anything.

Launching Dev vs Prod

The --plugin-dir flag tells Claude Code to load a plugin directly from a local directory for the current session. Combined with the -dev naming convention, this gives you three launch modes:

# Both dev and prod — side-by-side testing (from the plugin's repo root)
claude --plugin-dir .

# Prod only — normal user experience
claude

# Dev only — uninstall the marketplace version first
claude plugin uninstall tts
claude --plugin-dir .

With --plugin-dir ., Claude Code loads the local plugin.json (which has the -dev name) alongside any marketplace-installed plugins. Both namespaces coexist: /tts-dev:say runs the working tree code, /tts:say runs the installed version. Without the flag, only marketplace plugins load — your users never see the -dev variants.

Release Workflow

The release workflow swaps the name to prod, tags the release, then restores the dev name:

  1. release-plugin.sh — sets name: "tts" in plugin.json, commits, tags
  2. restore-dev-plugin.sh — sets name: "tts-dev", commits

This produces three sequential commits on main:

[release] → [prepare: name=tts] → [restore: name=tts-dev]
                  ↑ tag v0.4.0         ↑ HEAD

The tag points to the prepare commit with the prod name. HEAD points to the restore commit with the dev name. The marketplace installs from the tag — pin source.ref in marketplace.json to the release tag so users always get the prod name.

Detection

punt audit detects drift automatically:

  • Plugin name in plugin.json must end in -dev
  • Both release-plugin.sh and restore-dev-plugin.sh must exist
  • Every prod command must have a -dev variant

This catches drift after changes. If the dev plugin adds a new command but the prod variant is missing, audit fails.

Limits

The pattern requires maintaining parallel command files — one prod, one dev — which is mechanical but error-prone. punt audit catches drift after the fact. Prevention would be better than detection.

Other ecosystems handle dev/prod differently — npm has --tag, Docker has tag conventions. Claude Code plugins don’t have this yet. If Anthropic adds native dev/prod support, this pattern becomes unnecessary — and that would be a good outcome.

References

  1. Anthropic. “Claude Code.” 2024–present. docs.anthropic.com
  2. Anthropic. “Model Context Protocol.” 2024–present. modelcontextprotocol.io
  3. Punt Labs. “Distribution Standard.” github.com/punt-labs/punt-kit