Local (skills, dotfiles): beads + our dual-publish Remote (ops-jrz1 VPS): tissue + emes ecosystem They coexist by environment, not replacing each other. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
3.8 KiB
3.8 KiB
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.jsonfor metadataskills/directory for auto-discovery- Marketplace distribution via
/plugin install - Lifecycle hooks (SessionStart, PostToolUse, etc.)
We already had a working system:
SKILL.mdfiles with YAML frontmatter- Nix deployment to
~/.claude/skills/ - Cross-agent support (Gemini, OpenCode, Claude)
- Lenses pattern for multi-pass code review
The Problem
- Claude's system is Claude-only - Gemini can't read Claude plugins (see skills-bo8: path restrictions)
- Our system lacks hooks - No lifecycle events, mechanical enforcement
- 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):
deploy-skill.shcopies skill to dotfiles- Home-manager deploys to
~/.claude/skills/ - Agents read
SKILL.mddirectly
Claude plugin path:
- User adds marketplace:
/plugin marketplace add dan/skills - User installs:
/plugin install orch@dan-skills - Claude discovers
skills/orch.mdautomatically
Content is identical - skills/orch.md is a copy of SKILL.md.
Marketplace Structure
{
"$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.mdandskills/<name>.mdmust 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/<name>.md - CI validation: Check files are identical
- Documentation:
docs/emes-conversion-guide.md
Deployment Environments
| Environment | Issue Tracker | Plugin System |
|---|---|---|
| Local (skills, dotfiles) | beads | Our dual-publish |
| Remote (ops-jrz1 VPS) | tissue | emes ecosystem |
We use beads locally, tissue on the remote. They coexist by environment.
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
- emes org - Inspiration for plugin patterns
- Anthropic marketplace.json