Problem
The claude-phase plugin tree-copy in vat build is verbatim. packages/cli/src/commands/claude/plugin/tree-copy.ts copies everything under the plugin source: dir into the dist plugin tree with only a hardcoded exclusion plus gitignore:
const EXCLUDE_PATTERNS = ['.claude-plugin/**'];
...
const files = await crawlDirectory({
baseDir: sourceDir,
include: ['**/*'],
exclude: EXCLUDE_PATTERNS,
...
respectGitignore: true,
...
});
There is no config-driven exclude for this phase.
Consequence: a draft / work-in-progress skill that is deliberately excluded from skill packaging — via skills.exclude globs and omission from the marketplace plugin's explicit skills: allowlist — is still copied wholesale into dist/.claude/plugins/marketplaces/<mp>/plugins/<plugin>/skills/<draft-skill>/. That dist tree is what gets published, and skills under a plugin's skills/ directory are auto-discoverable by the consuming runtime, so the draft ships and becomes invocable despite being excluded everywhere the config currently allows.
It also breaks the verify gate: vat verify --only marketplace validates the dist marketplace tree (packages/cli/src/commands/verify.ts), so validation errors in the intentionally-unfinished draft skill fail the gate even when every shipped skill is clean.
Why drafts live in the plugin tree at all: when a plugin is co-designed in its source repo (non-developer contributors reviewing and editing skills in place), in-progress skills need to live next to shipped ones on the same branch — reviewable in place, but must not ship. The files are tracked source, so .gitignore is not an option (and the tree-copy's respectGitignore rightly wouldn't be the place for real source anyway).
Proposed feature
Either (in preference order):
- Have the claude plugin tree-copy honor the existing
skills.exclude globs (and/or the per-plugin explicit skills: allowlist), so anything intentionally excluded from skill packaging also stays out of the copied plugin tree in dist; or
- A dedicated tree-copy exclude list in config, e.g.:
claude:
marketplaces:
<mp>:
plugins:
- name: <plugin>
source: <dir>
exclude:
- "skills/<draft-skill>/**"
Precedent: the skills phase already supports both skills.exclude (consumed in packages/cli/src/commands/skills/skill-discovery.ts, which reads skills.include/exclude from vibe-agent-toolkit.config.yaml) and the per-plugin explicit skills: list. The claude tree-copy is the only packaging surface without an equivalent exclusion mechanism, so it silently reintroduces exactly what the other phases removed.
Workaround in use
Temporary build-side prune: a small zero-dep post-build script deletes dist/**/skills/<draft-skill>/ before the verify gate / publish runs. It works, but it is machinery every project with a draft skill under co-design will have to reinvent.
Observed on vat 0.1.35 (macOS, npm global install).
Problem
The claude-phase plugin tree-copy in
vat buildis verbatim.packages/cli/src/commands/claude/plugin/tree-copy.tscopies everything under the pluginsource:dir into the dist plugin tree with only a hardcoded exclusion plus gitignore:There is no config-driven exclude for this phase.
Consequence: a draft / work-in-progress skill that is deliberately excluded from skill packaging — via
skills.excludeglobs and omission from the marketplace plugin's explicitskills:allowlist — is still copied wholesale intodist/.claude/plugins/marketplaces/<mp>/plugins/<plugin>/skills/<draft-skill>/. That dist tree is what gets published, and skills under a plugin'sskills/directory are auto-discoverable by the consuming runtime, so the draft ships and becomes invocable despite being excluded everywhere the config currently allows.It also breaks the verify gate:
vat verify --only marketplacevalidates the dist marketplace tree (packages/cli/src/commands/verify.ts), so validation errors in the intentionally-unfinished draft skill fail the gate even when every shipped skill is clean.Why drafts live in the plugin tree at all: when a plugin is co-designed in its source repo (non-developer contributors reviewing and editing skills in place), in-progress skills need to live next to shipped ones on the same branch — reviewable in place, but must not ship. The files are tracked source, so
.gitignoreis not an option (and the tree-copy'srespectGitignorerightly wouldn't be the place for real source anyway).Proposed feature
Either (in preference order):
skills.excludeglobs (and/or the per-plugin explicitskills:allowlist), so anything intentionally excluded from skill packaging also stays out of the copied plugin tree in dist; orPrecedent: the skills phase already supports both
skills.exclude(consumed inpackages/cli/src/commands/skills/skill-discovery.ts, which readsskills.include/excludefromvibe-agent-toolkit.config.yaml) and the per-plugin explicitskills:list. The claude tree-copy is the only packaging surface without an equivalent exclusion mechanism, so it silently reintroduces exactly what the other phases removed.Workaround in use
Temporary build-side prune: a small zero-dep post-build script deletes
dist/**/skills/<draft-skill>/before the verify gate / publish runs. It works, but it is machinery every project with a draft skill under co-design will have to reinvent.Observed on vat 0.1.35 (macOS, npm global install).