Files
max-sixty__worktrunk/.claude-plugin
Maximilian Roos d22917702e refactor(plugins): consolidate Claude + Codex into one payload dir (#2789)
The Claude plugin lived at the repo root (`.claude-plugin/`) while the
Codex plugin lived in `plugins/worktrunk/` — two homes for one logical
plugin, with the description string duplicated across both and drifting
independently. This collapses them into a single payload directory.

**What moved.** `git mv
.claude-plugin/{plugin.json,hooks/,CLAUDE.md,README.md} →
plugins/worktrunk/` (history-preserving renames). The repo root keeps
only the two marketplace pointers — Claude and Codex each hardcode their
marketplace path with no fallback, so two pointer files is the
irreducible floor. Both pointers' `source` now resolves to
`./plugins/worktrunk`. `.claude-plugin/` is now a single 2-line file.

**The load-bearing constraint** (verified live against claude-cli
2.1.x): for a *subdirectory* `source`, Claude expects `plugin.json` at
the plugin root **without** a `.claude-plugin/` wrapper — that wrapper
is marketplace-root-only. (First attempt with the wrapper failed `Plugin
not found`; the corrected layout installs cleanly.) Codex keeps its own
required `.codex-plugin/` wrapper. So inside `plugins/worktrunk/`:
`plugin.json` is Claude's, `.codex-plugin/plugin.json` is Codex's,
`hooks/` is Claude's, `skills → ../../skills` is shared.

**Path edits inside moved files:** `plugin.json` `hooks` →
`./hooks/hooks.json`; `hooks.json`
`${CLAUDE_PLUGIN_ROOT}/.claude-plugin/hooks/wt.sh` →
`${CLAUDE_PLUGIN_ROOT}/hooks/wt.sh`.

**Reviewer navigation:** `git log` shows the moves as renames.
`plugins/worktrunk/CLAUDE.md` was rewritten to document the unified
layout + per-tool path resolution; the repo `CLAUDE.md` "Plugin Layout"
section likewise. `tests/integration_tests/config_show.rs` adds
`test_plugin_layout_is_consolidated`, which locks the layout invariants
(`.claude-plugin/` is marketplace-only, Claude manifest at plugin root,
hooks relative to it) **and** asserts the duplicated Claude description
stays byte-identical across the marketplace pointer and the manifest —
that was the standing follow-up; JSON can't `include!`, so a drift test
is the right tool, not a generator.

**Verification:** Live end-to-end on both real CLIs, twice — once with
copied skill dirs, once mirroring the real tree *including the
`plugins/worktrunk/skills` symlink* (Claude's `skills` array resolves
through it). Full pre-merge gate green: 3720 passed, 0 skipped, all
pre-commit lints, no snapshot churn. No user-facing docs/help text
changed (the consolidation is repo-internal), so `test_docs_are_in_sync`
needed no resync.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 16:35:25 -07:00
..