Skip to content

feat(runner): add Claude Code plugin loading via PLUGINS_JSON#1109

Draft
jeremyeder wants to merge 1 commit intomainfrom
feat/plugin-loading
Draft

feat(runner): add Claude Code plugin loading via PLUGINS_JSON#1109
jeremyeder wants to merge 1 commit intomainfrom
feat/plugin-loading

Conversation

@jeremyeder
Copy link
Copy Markdown
Contributor

Summary

Adds support for loading Claude Code plugins into ACP sessions via the existing spec.environmentVariables field. No CRD or operator changes required.

  • hydrate.sh: Parses PLUGINS_JSON env var, shallow-clones each plugin repo to /workspace/plugins/<name>/
  • bridge.py: Reads PLUGINS_JSON, resolves cloned paths, passes SdkPluginConfig entries to the Claude Agent SDK

Reproducer

Prerequisites

A plugin repo that follows the Anthropic plugin spec (.claude-plugin/plugin.json + commands/, agents/, skills/ at root). For testing, use jeremyeder/ai-helpers-fixed -- a patched fork of opendatahub-io/ai-helpers with the required manifest and symlinks (one-commit diff).

1. Create a dev cluster from this PR

gh pr checkout <this-pr-number>
make kind-up LOCAL_IMAGES=true CONTAINER_ENGINE=docker

Note: If images hit ImagePullBackOff due to the localhost/ prefix issue (PR #1105), tag and reload:

CLUSTER=$(make kind-status 2>&1 | grep Cluster | awk '{print $2}')
for img in vteam_backend vteam_frontend vteam_operator vteam_claude_runner vteam_state_sync vteam_public_api vteam_api_server; do
  docker tag "$img:latest" "localhost/$img:latest"
  kind load docker-image "localhost/$img:latest" --name $CLUSTER
done
kubectl rollout restart deployment -n ambient-code

2. Create the runner secrets

kubectl create secret generic ambient-runner-secrets -n ambient-code \
  --from-literal=ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY"

3. Create the MinIO bucket

kubectl exec deployment/minio -n ambient-code -- mc alias set local http://localhost:9000 minioadmin minioadmin123
kubectl exec deployment/minio -n ambient-code -- mc mb local/ambient-sessions

4. Apply the test CR

cat <<'EOF' | kubectl apply -f -
apiVersion: vteam.ambient-code/v1alpha1
kind: AgenticSession
metadata:
  name: test-plugin
  namespace: ambient-code
spec:
  initialPrompt: "Run /odh-ai-helpers:rpm-examine https://download.copr.fedorainfracloud.org/results/@ocp-on-ppc64le/4_18_ocp_rebuild/fedora-41-ppc64le/08906879-cri-o/builder-live.log.gz https://download.copr.fedorainfracloud.org/results/@ocp-on-ppc64le/4_18_ocp_rebuild/fedora-41-ppc64le/08906879-cri-o/cri-o-1.31.5-3.rhaos4.18.gitf0d4a53.fc41.src.rpm"
  timeout: 600
  llmSettings:
    model: "claude-sonnet-4-20250514"
  environmentVariables:
    PLUGINS_JSON: '[{"url":"https://github.com/jeremyeder/ai-helpers-fixed","branch":"main"}]'
EOF

5. Verify

# Check init container cloned the plugin
kubectl logs test-plugin-runner -c init-hydrate -n ambient-code | grep plugin
# Expected: ✓ Cloned plugin ai-helpers-fixed

# Check runner discovered the plugin
kubectl logs test-plugin-runner -c ambient-code-runner -n ambient-code | grep -i plugin
# Expected: Plugin discovered: ai-helpers-fixed at /workspace/plugins/ai-helpers-fixed

Open the UI (make kind-port-forward) and confirm the session shows odh-ai-helpers:* skills in the response, with RPM build analysis output from the /odh-ai-helpers:rpm-examine command.

How it works

CR spec.environmentVariables.PLUGINS_JSON
  -> operator passes to init container + runner container (existing mechanism)
  -> hydrate.sh clones to /workspace/plugins/<name>/
  -> bridge.py reads PLUGINS_JSON, builds SdkPluginConfig list
  -> ClaudeSDKClient(options={..., plugins=[{"type": "local", "path": "..."}]})
  -> SDK loads .claude-plugin/plugin.json, discovers commands/agents/skills

Test plan

  • Runner unit tests pass (474 passed, 0 failures)
  • Plugin clone succeeds in init container
  • Runner discovers plugin and passes to SDK
  • SDK loads plugin, skills/commands available in session
  • Verify with private plugin repo + GitHub credentials
  • Test multiple plugins in single session

Add support for loading Claude Code plugins into ACP sessions via
the existing spec.environmentVariables field. No CRD or operator
changes required.

Init container (hydrate.sh):
- Parses PLUGINS_JSON env var (JSON array of {url, branch} objects)
- Shallow-clones each plugin repo to /workspace/plugins/<name>/

Runner bridge (bridge.py):
- Reads PLUGINS_JSON during platform setup
- Resolves cloned paths to SdkPluginConfig entries
- Passes plugins to Claude Agent SDK options

Usage:
  spec:
    environmentVariables:
      PLUGINS_JSON: '[{"url":"https://github.com/org/plugin","branch":"main"}]'

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2f7b1b69-bada-4bc4-87c5-26368a06b0d7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/plugin-loading

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant