# ADR-005: Dual-Publish Plugin Architecture ## Status Accepted (2026-01-09) ## Context Claude Code introduced an official plugin system (October 2025) with: - `.claude-plugin/plugin.json` for metadata - `skills/` directory for auto-discovery - Marketplace distribution via `/plugin install` - Lifecycle hooks (SessionStart, PostToolUse, etc.) We already had a working system: - `SKILL.md` files with YAML frontmatter - Nix deployment to `~/.claude/skills/` - Cross-agent support (Gemini, OpenCode, Claude) - Lenses pattern for multi-pass code review ### The Problem 1. **Claude's system is Claude-only** - Gemini can't read Claude plugins (see skills-bo8: path restrictions) 2. **Our system lacks hooks** - No lifecycle events, mechanical enforcement 3. **Distribution differs** - Nix vs marketplace ### Alternatives Considered | Option | Pros | Cons | |--------|------|------| | **Migrate fully to Claude plugins** | Native UX, hooks, marketplace | Lose Gemini/OpenCode support | | **Keep Nix-only** | Cross-agent, system-level | No hooks, no marketplace | | **Dual-publish (chosen)** | Best of both | Maintenance overhead | ## Decision **Dual-publish**: Maintain both systems in parallel. Each skill has: ``` skills/my-skill/ ├── .claude-plugin/ │ └── plugin.json # Claude plugin metadata ├── skills/ │ └── my-skill.md # Claude auto-discovery ├── SKILL.md # Nix deployment (cross-agent) └── README.md ``` The repo root has: ``` .claude-plugin/ └── marketplace.json # Plugin registry for /plugin install ``` ### How It Works **Nix path (Gemini, OpenCode, system-level):** 1. `deploy-skill.sh` copies skill to dotfiles 2. Home-manager deploys to `~/.claude/skills/` 3. Agents read `SKILL.md` directly **Claude plugin path:** 1. User adds marketplace: `/plugin marketplace add dan/skills` 2. User installs: `/plugin install orch@dan-skills` 3. Claude discovers `skills/orch.md` automatically **Content is identical** - `skills/orch.md` is a copy of `SKILL.md`. ### Marketplace Structure ```json { "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "dan-skills", "version": "1.0.0", "description": "Dual-publish for cross-agent support", "owner": { "name": "dan" }, "plugins": [ { "name": "orch", "source": "./skills/orch" } ] } ``` ## Consequences ### Positive - **Cross-agent support preserved** - Gemini, OpenCode continue working - **Claude features available** - Hooks, marketplace, `/plugin install` - **Gradual migration** - Convert skills one at a time - **No breaking changes** - Existing Nix deployment unchanged ### Negative - **Duplication** - `SKILL.md` and `skills/.md` must stay in sync - **Two mental models** - Nix vs plugin system - **Testing complexity** - Must verify both paths work ### Mitigations - **Automation**: Script to sync `SKILL.md` → `skills/.md` - **CI validation**: Check files are identical - **Documentation**: `docs/emes-conversion-guide.md` ## Deployment Environments **Current:** | Environment | Issue Tracker | Plugin System | |-------------|---------------|---------------| | **Local** (skills, dotfiles) | beads | Our dual-publish | | **Remote** (ops-jrz1 VPS) | tissue | emes ecosystem | **Goal:** Deploy our cross-agent skills to ops-jrz1: | Environment | Issue Tracker | Plugin System | Agents | |-------------|---------------|---------------|--------| | **Local** | beads | Our dual-publish | Claude, Gemini, OpenCode | | **Remote** (ops-jrz1) | tissue | **Our dual-publish** | Claude, Gemini, OpenCode | The VPS becomes a "skills for all agents" environment - same cross-agent portability we have locally. tissue handles issue tracking, skills are ours. ## Related - **skills-6x1**: Epic for emes plugin architecture - **skills-bo8**: Gemini path restriction issue (motivates cross-agent need) - **skills-1ks**: Task to convert remaining skills - **skills-17f**: Forgejo access for distribution ## References - [Claude Code Plugin Docs](https://code.claude.com/docs/en/plugins) - [emes org](https://github.com/evil-mind-evil-sword) - Inspiration for plugin patterns - [Anthropic marketplace.json](https://github.com/anthropics/claude-code/blob/main/.claude-plugin/marketplace.json)