ADR-0007: Dual Distribution — Git-Clone Dotfiles AND Claude Code Plugin¶
Status¶
Accepted
Context¶
Scope. This ADR is specific to the Claude Code adapter's distribution surface; other harness adapters (Copilot, Cursor, Gemini CLI, …) integrate via their own native mechanisms documented at
docs/harnesses/<harness>.md.
Modern Claude Code ecosystems can ship via two distinct distribution channels, each with its own constraints and audience:
- Git-clone dotfiles. The operator clones the published repo and runs
install.{sh,ps1}(ormake install), which symlinks or copies content into~/.claude/. This brings the full ecosystem —src/apothem/agents/,src/apothem/commands/,src/apothem/skills/,src/apothem/hooks/,src/apothem/output-styles/,src/apothem/schemas/,scripts/, plussrc/apothem/rules/,CLAUDE.md,tests/,docs/,examples/,memory/,projects/— and lands the user-scope governance scaffolding (rules, CLAUDE.md, tooling, test suites) the operator may want to inspect, audit, or extend. - Claude Code plugins. Generally available per Anthropic's plugin specification at code.claude.com/docs/en/plugins.md. The operator runs
/plugin install <plugin-name>@<marketplace>and Claude Code installs the plugin's payload into the user-scope plugin directory. Plugins ship a constrained payload: per Anthropic's specification, plugins can shipsrc/apothem/agents/,src/apothem/commands/,src/apothem/skills/,src/apothem/hooks/,src/apothem/output-styles/,src/apothem/schemas/,scripts/— but notsrc/apothem/rules/, notCLAUDE.md, nottests/ordocs/(those are user-scope-only governance surfaces, outside the plugin payload boundary). In exchange, plugins offer one-command discoverable install, auto-update onversionbump, namespaced commands (/<plugin-name>:plan-spec), and marketplace-listing surface.
The two channels are not adversarial; they serve different deployment scenarios:
- Dotfiles is for operators who want the full governance surface — rules, CLAUDE.md, the audit tools, the validators, the tests — installable, inspectable, and editable on their own machine. The operator is the maintainer's peer; the dotfiles ship the maintainer's full working environment.
- Plugin is for operators who want the runtime ecosystem (agents + commands + skills + hooks + output-styles + MCP + schemas + scripts) without the governance scaffolding — for the case where they already maintain their own CLAUDE.md and rules and want to layer the runtime on top.
Three plausible postures were considered:
- Dotfiles only. Forfeits the GA plugin distribution's discoverability + auto-update + namespacing.
- Plugin only. Drops
src/apothem/rules/+CLAUDE.md(the ecosystem's primary governance value). - Both, simultaneously, with the plugin form being a documented subset of the dotfiles form.
Decision¶
Ship as both distribution forms simultaneously, with the plugin form being a documented subset of the dotfiles form.
The plugin's payload is the runtime-ecosystem subset:
- Included in the plugin:
src/apothem/agents/,src/apothem/commands/,src/apothem/skills/,src/apothem/hooks/,src/apothem/output-styles/,src/apothem/schemas/,scripts/. - Excluded from the plugin (dotfiles-only):
src/apothem/rules/,CLAUDE.md,tests/,docs/,memory/,projects/,plans/(gitignored anyway).
The marketplace manifest at .claude-plugin/marketplace.json registers the plugin as a single-plugin marketplace (source: "."); the plugin manifest at .claude-plugin/plugin.json carries the canonical metadata (name, version, description, payload paths). Phase 06F authors both manifests; Phase 09A's AskUserQuestion batch ratifies the plugin name, the marketplace name, and the submission opt-in to the official Anthropic marketplace.
Plugin commands are namespaced (/<plugin-name>:plan-spec) so they coexist with user ~/.claude/ content (whose commands are unprefixed) without precedence conflict. An operator who has both the dotfiles and the plugin installed can invoke /plan-spec (their own / dotfiles' definition) or /<plugin-name>:plan-spec (the plugin's namespaced form) deliberately.
Consequences¶
- Operators choose their preferred install method without losing functionality. Dotfiles = full governance; plugin = lightweight runtime. The operator picks the deployment scope that matches their use case.
- Plugin commands are namespaced. The plugin's command surface coexists with the operator's existing
~/.claude/content. Operators with their own/plan-spec(whether through their dotfiles or their own authoring) keep theirs as the unprefixed default; the plugin's version is reachable as/<plugin-name>:plan-spec. - Maintenance surface doubles slightly. Every release must bump
versionin bothplugin.json(which triggers plugin auto-update for installed users) and the dotfilesCHANGELOG.md. The release workflow at.github/workflows/release.ymlhandles both bumps in one tag-push event. - Marketplace submission is operator-opt-in at Phase 09A. If the operator opts in, the marketplace becomes publicly discoverable through the official Anthropic marketplace's listing surface; if not, the marketplace remains private to the operator's invocation chain (
/plugin install <plugin-name>@<own-source>). The marketplace's source repo can be private if Anthropic's permissions allow; otherwise a public-mirror approach with selective sync covers the case. - The plugin payload is a subset, not a fork. The plugin's source files are the same files the dotfiles ship; the marketplace manifest enumerates the subset, but the underlying files are not duplicated. A bug fix in
src/apothem/commands/plan-spec.mdships through both channels from a single edit. - Plugin manifest schema is the per-payload-class boundary. Adding a new artifact class (e.g., a future
prompts/directory) requires updatingplugin.json's payload enumeration to include or exclude it; the inclusion/exclusion decision is itself a future ADR. - The release-engineering pattern is documented. The CONTRIBUTING.md release-process subsection describes the dual-distribution release flow: tag → CI release workflow → both channels updated atomically.
Alternatives Considered¶
- Dotfiles only. Rejected: forfeits the GA plugin distribution's discoverability + auto-update + namespacing. Operators who would prefer one-command install via
/plugin installare forced into a clone-and-symlink flow that reduces ecosystem reach. - Plugin only. Rejected: drops
src/apothem/rules/+CLAUDE.md(the ecosystem's primary governance value). Operators who want to inspect / audit / extend the governance surface lose access; the maintainer's full working environment becomes invisible to peers. - Plugin via official Anthropic marketplace only (no self-hosted marketplace). Rejected: barriers to entry — submission review, public-mirror requirement may conflict with the operator's "private repo" mandate during the engagement's pre-publication phase. The self-hosted-plus-optional-Anthropic-submission pattern preserves the publication option while allowing private-only invocation in the interim.
- Two repos (one dotfiles, one plugin). Rejected: doubles the maintenance surface for no architectural benefit; bug fixes would need to land in both repos with cross-repo coordination. The single-repo, dual-channel pattern keeps the source of truth singular.
Cross-references: ADR-0004, .claude-plugin/marketplace.json (Phase 06F), .claude-plugin/plugin.json (Phase 06F), .github/workflows/release.yml (Phase 06C), Phase 09A AskUserQuestion batch (plugin-name + marketplace-name + submission opt-in).