The Plugin Was Ready. The Cloud Session Wasn't.

4 min read
Claude CodePluginsToolingCI/CD

After building a Claude Code plugin and testing it locally, I moved to a cloud session — and everything disappeared. No error, no warning. Here's what's actually happening and how to fix it.

I built content-stack (opens in a new tab) — a Claude Code plugin marketplace with two plugins I use on my own projects. It worked well locally. The setup felt clean: register the marketplace in .claude/settings.json, list the plugins under enabledPlugins, commit it, done.

Then I tried it in a cloud session — Claude Desktop running in a remote, headless environment.

The plugins weren't there. No error in the terminal. No warning in the session. Just nothing.

What the configuration looks like

The setup that should work:

{
  "extraKnownMarketplaces": {
    "content-stack": {
      "source": {
        "source": "github",
        "repo": "pcamarajr/content-stack"
      }
    }
  },
  "enabledPlugins": {
    "content-ops@content-stack": true,
    "cost-tracker@content-stack": true
  }
}

This is exactly what the docs describe. The marketplace is registered, the plugins are enabled. Locally, it works. In a cloud or headless session, the plugins silently don't install.

What's actually happening

The root cause isn't a bug — it's an architectural constraint. Claude Code's plugin auto-installation is tied to the interactive trust dialog. When you open a project interactively, Claude Code prompts you to trust the folder. That trust event is what triggers marketplace registration and plugin installation.

In cloud sessions — claude.ai, headless CI, Docker containers — the trust dialog is skipped entirely. No dialog means no trust event. No trust event means plugins never install. The enabledPlugins setting is just ignored, silently.

It's one of those failures that's particularly hard to debug because there's no feedback. You're not doing anything wrong. The setting is correct. Claude Code just has no hook to act on it.

The fix: a bootstrap script

In Claude Desktop, environments (opens in a new tab) define where and how a cloud session runs. Each environment has a Setup script field — a Bash script that runs automatically when a new session starts, before Claude Code launches. That's exactly the hook we need.

To set it up: open the environment dropdown in Claude Desktop, create a new environment (or edit an existing one), and paste the script into the Setup script field.

#!/bin/bash
# bootstrap-plugins.sh

set -e

claude plugin marketplace list | grep -q "content-stack" || \
  claude plugin marketplace add pcamarajr/content-stack

claude plugin list --installed | grep -q "content-ops" || \
  claude plugin install content-ops@content-stack

claude plugin list --installed | grep -q "cost-tracker" || \
  claude plugin install cost-tracker@content-stack

echo "Plugins ready."

The setup script runs as root on Ubuntu 24.04, has network access to common registries by default, and only fires on new sessions — not resumed ones. The grep -q checks make it idempotent, so re-running won't break anything if the plugins are already installed.

One thing worth noting: this is different from a SessionStart hook (opens in a new tab), which runs after Claude Code launches. The setup script runs before, which is what makes it work here — by the time Claude Code starts, the plugins are already in place.

For Docker or CI environments there's an official alternative: the CLAUDE_CODE_PLUGIN_SEED_DIR environment variable. Point it to a pre-populated ~/.claude/plugins/ directory built into the image. No runtime installation, no script needed — but it requires building the seed directory at image creation time.

This is a known issue

I wasn't the first to hit this. There are multiple open issues in anthropics/claude-code (opens in a new tab) documenting the same problem:

The pattern across all of them: Anthropic has consistently closed these without shipping a declarative solution, while quietly shipping CLAUDE_CODE_PLUGIN_SEED_DIR as the intended path for container use cases.

Issue #32607 is the one worth watching — or upvoting. At minimum, Claude Code should warn when enabledPlugins references plugins that aren't installed. A single log line would have saved me the entire debugging session.

What to take from this

If you're building or using Claude Code plugins and expect them to work in cloud or CI environments, you need an explicit installation step. The enabledPlugins setting alone isn't enough.

The bootstrap script is simple and works today. If you're working with Docker or CI pipelines, CLAUDE_CODE_PLUGIN_SEED_DIR is the cleaner long-term approach. Either way, it's a one-time fix once you know why.

The harder problem is that nothing tells you this. You commit a correct-looking configuration, start a cloud session, and get no feedback on why the plugins didn't load. Until there's a warning for that — and there should be — now you know.