Skip to content

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:

  1. Git-clone dotfiles. The operator clones the published repo and runs install.{sh,ps1} (or make 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/, plus src/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.
  2. 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 ship src/apothem/agents/, src/apothem/commands/, src/apothem/skills/, src/apothem/hooks/, src/apothem/output-styles/, src/apothem/schemas/, scripts/ — but not src/apothem/rules/, not CLAUDE.md, not tests/ or docs/ (those are user-scope-only governance surfaces, outside the plugin payload boundary). In exchange, plugins offer one-command discoverable install, auto-update on version bump, 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:

  1. Dotfiles only. Forfeits the GA plugin distribution's discoverability + auto-update + namespacing.
  2. Plugin only. Drops src/apothem/rules/ + CLAUDE.md (the ecosystem's primary governance value).
  3. 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 version in both plugin.json (which triggers plugin auto-update for installed users) and the dotfiles CHANGELOG.md. The release workflow at .github/workflows/release.yml handles 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.md ships 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 updating plugin.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 install are 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).