---
name: deploy-local-plugin
description: Deploy local plugin files from repository source to Claude Code plugin cache for immediate testing
version: 1.0.0
level: advanced
debug: true
category: tooling
tags:
  - deployment
  - plugin
  - development
  - tooling
author: OmniClaude Team
---

# Deploy Local Plugin Skill

Automate deployment of local plugin development to the Claude Code plugin cache.

## Problem Solved

During plugin development, changes in the repository are not automatically reflected in Claude Code because:
1. Plugins are loaded from `~/.claude/plugins/cache/` not the repository
2. Manual file copying is error-prone and tedious
3. Version management requires updating multiple locations

This skill solves the deployment gap between development and testing.

## Quick Start

```
# Preview what would change
/deploy-local-plugin

# Actually deploy (syncs files + builds lib/.venv)
/deploy-local-plugin --execute

# Deploy without bumping version
/deploy-local-plugin --execute --no-version-bump

# New user install — daily driver skills only (excludes debug: true skills)
/deploy-local-plugin --execute --level basic

# Intermediate user install
/deploy-local-plugin --execute --level intermediate

# Full install including debug/diagnostic skills
/deploy-local-plugin --execute --include-debug

# Repair: build lib/.venv in the active deployed version (no file sync, no version bump)
# Use when hooks fail with "No valid Python found" after a deploy
/deploy-local-plugin --repair-venv
```

## Skill Tier Filtering

`--level basic|intermediate|advanced` controls which skills are copied into the plugin cache.
Filtering is **inclusive downward** — lower tiers are always included when a higher tier is requested:

| Flag | Skills included |
|------|----------------|
| `--level basic` | Only `level: basic` skills |
| `--level intermediate` | `level: basic` + `level: intermediate` skills |
| `--level advanced` | All non-debug skills (all levels); `debug: true` skills excluded unless `--include-debug` is passed |

Skills marked `debug: true` are **excluded** from all filtered deploys (any explicit `--level`)
unless `--include-debug` is also passed. When no `--level` flag is used, debug skills are
included as before (backwards-compatible default).

Internal support library dirs (prefixed with `_`) are always included regardless of filter.

## How It Works

### Source → Target Mapping

| Source (Repository) | Target (Cache) |
|---------------------|----------------|
| `plugins/onex/commands/` | `~/.claude/plugins/cache/omninode-tools/onex/{version}/commands/` |
| `plugins/onex/skills/` | `~/.claude/plugins/cache/omninode-tools/onex/{version}/skills/` |
| `plugins/onex/agents/` | `~/.claude/plugins/cache/omninode-tools/onex/{version}/agents/` |
| `plugins/onex/hooks/` | `~/.claude/plugins/cache/omninode-tools/onex/{version}/hooks/` |
| `plugins/onex/.claude-plugin/` | `~/.claude/plugins/cache/omninode-tools/onex/{version}/.claude-plugin/` |

### Version Management

By default, each deployment:
1. Reads current version from `plugin.json` (e.g., `2.1.2`)
2. Bumps patch version (e.g., `2.1.3`)
3. Creates new directory for the new version
4. Syncs all files to the new version directory
5. Updates `installed_plugins.json` registry

Use `--no-version-bump` to overwrite the current version in-place.

### Registry Update

The `installed_plugins.json` registry is updated with:
- New `version` field
- New `installPath` pointing to the new version directory
- Updated `lastUpdated` timestamp

## Safety Features

### Dry Run by Default

The command shows what would change without making modifications:

```
[DRY RUN] Would deploy local plugin to cache

Current version: 2.1.2
New version: 2.1.3

Files to sync:
  commands/:      16 files
  skills/:        31 directories
  agents/configs: 53 files
  hooks/:         7 items
  .claude-plugin: plugin.json + metadata

Target: ~/.claude/plugins/cache/omninode-tools/onex/2.1.3/

Use --execute to apply changes.
```

### Versioned Directories

Each deployment creates a new version directory and removes all prior versions.
Only the current version is kept in cache.

### Atomic Updates

The registry is updated atomically using temp file + move pattern to prevent corruption.

## After Deployment

After running `/deploy-local-plugin --execute`:

1. **Restart Claude Code** to pick up changes (plugins load at session start)
2. Verify with `/help` to see new commands
3. Old version directories are removed automatically

### Version-Agnostic `current/` Symlink

Every `--execute` deploy creates or updates a stable symlink:

```
~/.claude/plugins/cache/omninode-tools/onex/current/  ->  <version>/
```

If `PLUGIN_PYTHON_BIN` is set in `~/.omnibase/.env` with a version-pinned path (e.g.
`/onex/2.2.5/lib/.venv/bin/python3`), the deploy script automatically rewrites it to
the version-agnostic form:

```bash
PLUGIN_PYTHON_BIN=~/.claude/plugins/cache/omninode-tools/onex/current/lib/.venv/bin/python3
```

This means `PLUGIN_PYTHON_BIN` survives future version upgrades without manual changes.
The `current/` symlink is updated atomically on every deploy so the path always resolves
to the live venv.

## Troubleshooting

### "command not found: jq"

Install jq: `brew install jq` (macOS) or `apt install jq` (Linux)

### Permissions Error

Ensure write access to `~/.claude/plugins/`:
```bash
ls -la ~/.claude/plugins/
```

### Changes Not Appearing

1. Restart Claude Code session
2. Check the correct version is in registry:
   ```bash
   cat ~/.claude/plugins/installed_plugins.json | jq '.plugins["onex@omninode-tools"]'
   ```

### "No valid Python found" / hooks fail with exit 1

This means `lib/.venv` is missing from the active plugin cache directory. This can happen if:
- The cache directory was populated by a source other than `deploy.sh --execute`
- The deploy was interrupted between the file sync and venv build steps
- A manual rsync was used to copy plugin files without building the venv

**Fix**:
```bash
${CLAUDE_PLUGIN_ROOT}/skills/deploy-local-plugin/deploy.sh --repair-venv
```

This builds `lib/.venv` in the currently-active deployed version (from `installed_plugins.json`)
without syncing files or bumping the version. A smoke test confirms the venv is healthy before
the command returns. Restart Claude Code after the repair completes.

### `PLUGIN_PYTHON_BIN` points to wrong version after upgrade

If `PLUGIN_PYTHON_BIN` was set with a version-pinned path (e.g. `.../onex/2.2.5/lib/.venv/...`)
and a new version was deployed, the path silently resolves to an old or missing venv.

**Fix — run a deploy**: The next `--execute` deploy auto-rewrites `PLUGIN_PYTHON_BIN` in
`~/.omnibase/.env` to the version-agnostic form using the `current/` symlink.

**Fix — manual one-liner**:
```bash
# Set PLUGIN_PYTHON_BIN to the version-agnostic current symlink path
AGNOSTIC="$HOME/.claude/plugins/cache/omninode-tools/onex/current/lib/.venv/bin/python3"
sed -i.bak -E \
  "s|^(PLUGIN_PYTHON_BIN=).*/onex/[0-9]+\.[0-9]+\.[0-9]+/lib/\.venv/bin/python3|\1${AGNOSTIC}|" \
  ~/.omnibase/.env
```

After this change, `PLUGIN_PYTHON_BIN` will always resolve to the live venv regardless of
which version is deployed. No further manual updates needed.

## Skills Location

**Executable**: `${CLAUDE_PLUGIN_ROOT}/skills/deploy-local-plugin/deploy.sh`

## See Also

- Plugin development: `plugins/onex/.claude-plugin/plugin.json`
- Installed plugins registry: `~/.claude/plugins/installed_plugins.json`
