# 9. Claude Code stack skills are plugin-only; the local copy is retired

**Status:** Accepted · 2026-08 (v15.0.0) · Supersedes the "install destination is unchanged" clause of ADR-0006

## Context

ADR-0006 split the source tree into `shared/core/` + `shared/external/` but kept the install unchanged: both trees flattened into `~/.claude/skills/`. Since then the same external catalog also became the authoring source for the `multi-agent-plugins` marketplace (`build-stack-plugins.mjs` derives each plugin's `knowledge/` layer from it), and Claude Code loads those plugins natively, namespaced (`ai-ios-toolkit:swiftui-pro`).

That left Claude Code receiving every stack skill **twice**:

- 110 of 157 local skill dirs duplicated the enabled plugins byte-for-byte - ~10k tokens of duplicate descriptions per session, 4.4 MB on disk.
- The local copy shadowed the plugin the moment it went stale, and it *was* stale in practice: the plugin cache and the local copy advanced on different schedules.
- The duplication hid real bugs: `skill-conformance.mjs` and `match-skills.mjs` only knew the local root, so they kept working by accident - against the stale copy.

## Decision

1. **Claude Code receives no local copy of the stack skills.** The marketplace plugins (`ai-<stack>-toolkit`, enablement managed by `/multi-agent:stack`, multi-select) are its only stack-skill source. Prompt tables, `Skill` invocations and the skills index all use the plugin-namespaced name.
2. **Exactly two skills stay local on Claude Code**: `apple-archive-compliance` and `google-play-compliance` (`PIPELINE_LOCAL_SKILLS` in `install/claude.mjs`). They are pipeline-owned compliance catalogs, kept out of the public marketplace by policy (they may carry audit rules not meant for it), and `uninstall.mjs` already treats exactly this pair as pipeline-owned.
3. **`shared/external/` stays in the repo as the authoring source.** It feeds `build-stack-plugins.mjs` and the Copilot/Codex copies; it is simply never copied to `~/.claude/skills` again. Installs migrate old machines by removing the dirs named in `.external-skills-manifest.json` (manifest-scoped - user-authored dirs survive).
4. **Copilot CLI and Codex CLI keep local copies** (no plugin loader / silently truncating skill list), now **filtered to the enabled stacks**: `pluginsToDeliver` reads `enabledPlugins` from `~/.claude/settings.json` (fallback `--platform`), `partitionExternalSkillsByPlugins` routes each skill through the same `_stack-routing.mjs` table the marketplace is built with. One stack selection governs all three hosts.
5. **Scripts that resolve skills know the plugin roots**: `skill-conformance.mjs` probes the marketplace checkout and version-named plugin cache (newest first) alongside the install roots; `build-skills-index.mjs` stamps `plugin` + `invokeAs` per entry so `match-skills.mjs` returns namespaced names.

## Consequences

Positive: one source of truth per skill at runtime; ~13.5k tokens/session and ~5.9 MB reclaimed on Claude Code; a disabled stack is genuinely absent instead of half-present; the smoke suite now asserts the compliance-only contract (`smoke-install-layout.sh` 5b2b) and the filter's both directions (5b2).

Negative / accepted:

- A stack not enabled in `enabledPlugins` is invisible to Claude Code until `/multi-agent:stack` enables it. This is the intended behavior, not a regression.
- `dynamicSkillLoading`'s index now names skills the local tree does not hold; consumers must use `invokeAs`, not a filesystem path.
- Copilot/Codex copies go stale when the stack selection changes until `install --copilot --codex` is re-run; `/multi-agent:stack` offers that refresh after every change.
