@vibe-agent-toolkit/vat-development-agents 0.1.33-rc.3 → 0.1.34-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.claude/plugins/marketplaces/vat-skills/CHANGELOG.md +49 -3
- package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/.claude-plugin/plugin.json +3 -3
- package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vat-adoption-and-configuration/SKILL.md +0 -1
- package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vat-skill-distribution/SKILL.md +19 -13
- package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vat-skill-distribution/resources/marketplace-distribution.md +427 -0
- package/dist/generated/resources/skills/vat-adoption-and-configuration.js +3 -3
- package/dist/generated/resources/skills/vat-skill-distribution.d.ts +1 -0
- package/dist/generated/resources/skills/vat-skill-distribution.js +10 -5
- package/dist/skills/vat-adoption-and-configuration/SKILL.md +0 -1
- package/dist/skills/vat-skill-distribution/SKILL.md +19 -13
- package/dist/skills/vat-skill-distribution/resources/marketplace-distribution.md +427 -0
- package/package.json +4 -4
|
@@ -8,6 +8,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
|
+
- **Skill-claude-plugin recognition in `vat audit`.** Introduces the **skill-claude-plugin** artifact shape — a skill that self-publishes as a Claude plugin by co-locating `.claude-plugin/plugin.json` alongside its root `SKILL.md`. Audit now emits independent `ValidationResult` entries for each surface (one `agent-skill`, one `claude-plugin`) instead of reporting only the plugin and silently ignoring the skill. The skill remains platform-agnostic; the graduation to skill-claude-plugin adds Claude-specific packaging only. See [`docs/architecture/skill-packaging.md`](docs/architecture/skill-packaging.md) for the full packaging-shape terminology (standalone skill / skill-claude-plugin / claude-plugin / claude-marketplace).
|
|
12
|
+
- **`SKILL_CLAUDE_PLUGIN_NAME_MISMATCH`** validation code (default `warning`). Fires on the plugin result when a skill-claude-plugin's `plugin.json.name` disagrees with the co-located `SKILL.md` frontmatter `name`. The skill is authoritative; the plugin manifest is a distribution wrapper and should match unless the plugin is intentionally namespaced (in which case use `validation.severity` or `validation.allow`).
|
|
13
|
+
- **Self-contained Claude Code plugin support in `vat claude plugin build`.**
|
|
14
|
+
Adopters can now bundle commands, hooks, agents, MCP servers, scripts, raw
|
|
15
|
+
plugin-local `SKILL.md` files, and author-supplied `plugin.json` metadata from a
|
|
16
|
+
per-plugin `plugins/<name>/` directory. The entire directory is tree-copied
|
|
17
|
+
verbatim (respecting `.gitignore`). Pre-existing pool-to-plugin skill selectors
|
|
18
|
+
(`marketplace.plugins[].skills`) are preserved — a plugin can still declare
|
|
19
|
+
`skills: "*"` or `skills: [names]` to import pool skills (built by
|
|
20
|
+
`vat skills build`) into its bundle. The skills stream is unchanged: `vat skills
|
|
21
|
+
build` continues to produce `dist/skills/<name>/` only. New schema fields on
|
|
22
|
+
marketplace plugin entries: `source` (path override, default `plugins/<name>`)
|
|
23
|
+
and `files[]` (compiled-artifact mappings). The 5-phase plugin build pipeline
|
|
24
|
+
is deterministically ordered (discovery → tree-copy → pool-skill import →
|
|
25
|
+
`files[]` → merged `plugin.json`). YAML summary adds `commandsCopied`,
|
|
26
|
+
`hooksCopied`, `agentsCopied`, `mcpCopied`, `treeFilesCopied`,
|
|
27
|
+
`explicitFilesCopied` per plugin. Case-sensitivity mismatches between declared
|
|
28
|
+
plugin names and on-disk dirs now fail the build to catch Linux-CI drift.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- `vat audit` directory-entry detection uses a new `enumerateSurfaces()` helper that returns every manifest present at the directory root, replacing single-result detection in the multi-surface case. Single-surface directories retain their legacy single-validator dispatch, including the marketplace-with-co-located-plugin collapse.
|
|
32
|
+
- `packages/cli/src/commands/audit/hierarchical-output.ts` comments standardized on the new terminology: the pattern previously documented as "standalone plugin skill (no skills subdir)" is now called **skill-claude-plugin**.
|
|
33
|
+
- Upgraded `vibe-validate` and `@vibe-validate/cli` dev dependencies from `^0.19.1` to `^0.19.4`.
|
|
34
|
+
|
|
35
|
+
### Documentation
|
|
36
|
+
- New reference doc `docs/architecture/skill-packaging.md` enumerates the four packaging shapes with layouts and applicable validation.
|
|
37
|
+
- `docs/README.md` gains a "Validation & Quality Framework" section indexing the three stance docs (`skill-quality-and-compatibility.md`, `validation-codes.md`, `skill-smell-philosophy.md`).
|
|
38
|
+
- New `docs/CLAUDE.md` and `docs/architecture/CLAUDE.md` agent navigators pull in each directory's README via `@README.md` and add agent-only guidance for audit/validation work.
|
|
39
|
+
- Root `/CLAUDE.md` "Questions?" section now links to directories rather than README files — child CLAUDE.md files auto-trigger and pull in their README once, avoiding the previous double-read pattern.
|
|
40
|
+
- `packages/cli/CLAUDE.md` gains a "Validation Framework References" section.
|
|
41
|
+
|
|
42
|
+
## [0.1.33] - 2026-04-21
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- **Cross-platform ESM helpers in `@vibe-agent-toolkit/utils`.** Two new exports address Windows path footguns that can bite adopters once their code runs on Windows CI:
|
|
46
|
+
- `resolveFromImportMeta(importMetaUrl, ...segments)`: OS-native absolute path from a module's `import.meta.url` and optional relative segments. Use instead of `new URL(rel, import.meta.url).pathname`, which returns `/D:/...` on Windows and breaks `fs` operations.
|
|
47
|
+
- `dynamicImportPath<T>(absPath)`: wraps `await import(pathToFileURL(absPath).href)`. Use instead of `await import(absPath)` on an OS-native filesystem path — the bare form throws on Windows (ESM dynamic import requires a `file://` URL there).
|
|
48
|
+
- **Two new local ESLint rules** (registered in `@vibe-agent-toolkit/dev-tools/eslint-local-rules` and wired as `error` in the root `eslint.config.js`):
|
|
49
|
+
- `local/no-url-pathname-for-fs`: flags `.pathname` access on `new URL(..., import.meta.url)`. Message points at the new `resolveFromImportMeta()` helper or `fileURLToPath()`.
|
|
50
|
+
- `local/no-bare-dynamic-import-path`: flags `await import(expr)` where `expr` is a computed filesystem path (absolute literal, `path.join/resolve` result, path-shaped identifier). Message points at the new `dynamicImportPath()` helper or `pathToFileURL(p).href`. Intentionally narrow heuristic with one documented false-positive escape hatch (suppress per-line with `eslint-disable-next-line local/no-bare-dynamic-import-path` when the identifier already holds a `file://` URL).
|
|
51
|
+
- RuleTester-based unit tests land alongside the rules via a shared harness (`packages/dev-tools/test/eslint-rule-test-harness.ts`). Adding a new local rule is now one row in `local-eslint-rules.test.ts`, not a new test file.
|
|
11
52
|
- Three new skill-smell validation codes (all default `warning`, per skill-smell philosophy):
|
|
12
53
|
- `SKILL_FRONTMATTER_EXTRA_FIELDS`: frontmatter contains keys beyond the standard agentskills.io + Claude Code set. Allowed keys derive from `AgentSkillFrontmatterSchema` at module load, so the rule tracks the schema. Actionable when adopters put project-specific fields (`version:`, `tools:`, `permissions:`) at top level — `metadata.*` is the right home for custom data.
|
|
13
54
|
- `SKILL_CROSS_SKILL_AUTH_UNDECLARED`: body prose declares a sibling-skill or `ANTHROPIC_*_KEY` dependency (e.g., "Requires `vibe-agent-toolkit:vat-enterprise-org`", "Requires `ANTHROPIC_ADMIN_API_KEY`") but the description omits it. Narrow heuristic to keep false-positive rate low; bare `ANTHROPIC_API_KEY` (the universal Claude-API default) is explicitly excluded.
|
|
@@ -18,17 +59,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
59
|
- `actions/checkout` and `actions/setup-node` bumped from `@v4` to `@v6` across `.github/workflows/*.yml`. Runs on Node 24; removes the Sept-2026 deprecation warning on `v4` runners.
|
|
19
60
|
|
|
20
61
|
### Fixed
|
|
21
|
-
- `
|
|
62
|
+
- **Windows path-normalization regression in `GitTracker.isIgnored()`.** The cache was populated at init with `safePath.resolve(projectRoot, relPath)` (which drive-prefixes on Windows, e.g. `C:/project/README.md`), but `isIgnored()` queried the cache with the raw caller-supplied path. Every lookup missed on Windows and fell through to spawn `git check-ignore`, triggering three `packages/utils/test/git-tracker.test.ts` performance-assertion failures on every Windows CI run since rc.2. Fix normalizes the lookup key to match population. Sibling methods `hasActiveDescendant` and `isIgnoredByActiveSet` already normalized correctly; `isIgnored` was the outlier. Added a POSIX-visible regression test using a non-canonical path (containing `..`) so the invariant is guarded against future changes that might reintroduce raw-path lookups.
|
|
63
|
+
- **Windows infinite loop in `findConfigPath()` when scanning paths outside a VAT-configured project.** The root-detection used a hardcoded `/`, which never matches Windows drive roots (`C:\`, `D:\`), causing the walk-up loop to spin indefinitely. Fixed via `path.parse(dir).root` + `dirname()` with a `parent === currentDir` safety break so traversal halts at the filesystem root on every OS. Manifested as `vat audit` hangs on Windows whenever the scan target (or the caller's cwd for a `.` scan) had no `vibe-agent-toolkit.config.yaml` ancestor — common for temp-directory test fixtures and any audit run outside a project.
|
|
22
64
|
- Stale JSDoc examples referencing `vibe-agent-toolkit:resources` (renamed to `vibe-agent-toolkit:vat-knowledge-resources` during the 0.1.32 plugin restructure) replaced with `vibe-agent-toolkit:vat-audit` in `packages/cli/src/commands/claude/plugin/build.ts`, `packages/cli/src/commands/skills/build.ts`, `packages/agent-schema/src/package-metadata.ts`, and the companion test constant.
|
|
65
|
+
- **`duplication-check` now runs on Windows.** Previously it was skipped because `@jscpd/finder` calls `realpathSync()` on the input patterns, which on Windows fails when paths contain `..`/glob patterns and prevents the report from being generated (upstream issue [jscpd#143](https://github.com/kucherenko/jscpd/issues/143), unfixed since 2020). The fix ships as a Bun `patchedDependencies` entry at `patches/@jscpd%2Ffinder@4.0.4.patch` — Bun applies it automatically on `bun install`. The patch is a two-line removal of the `realpathSync()` call; jscpd doesn't depend on the resolved path for anything downstream. Cross-platform baseline portability is ensured by a companion change: `jscpd-check-new.ts` and `jscpd-update-baseline.ts` now normalize clone paths to forward slashes via `toForwardSlash()`, so a baseline captured on Linux/CI matches when `duplication-check` runs on Windows (where jscpd reports backslashes).
|
|
66
|
+
- **`safeExecSync` / `safeExecResult` in `@vibe-agent-toolkit/utils` no longer silently fail on Windows under Node 24+.** When the resolved command was a shell wrapper (`.cmd`/`.bat`) — e.g. `npx.cmd`, `bunx.cmd`, `npm.cmd` — the previous code passed args through `shell:true` as a separate array, which Node 24 rejects with `EINVAL` per [DEP0190](https://nodejs.org/api/deprecations.html#DEP0190) whenever any arg contains a shell metacharacter (`*`, `?`, `(`, `)` …). Symptom: the spawned process would fail immediately and produce no output, leaving callers to misattribute the crash to the downstream tool. Fix joins the command and args into a single string when the shell path is needed, keeping `shell:false` + absolute-path spawning as the default for all non-wrapper commands (the secure path). Was the actual reason `bun run duplication-check` failed on Windows CI even after the jscpd patch landed.
|
|
67
|
+
- **Windows `bun install` postinstall failures from `link-workspace-packages.ts`.** The postinstall script created workspace symlinks with `symlinkSync(target, link, 'dir')`, which requires the `SeCreateSymbolicLinkPrivilege` admin right on Windows and fails with `EPERM` in non-elevated shells. Fix uses directory **junctions** on Windows (`symlinkSync(absoluteTarget, link, 'junction')`) — junctions don't require elevation and are transparent to both Node's ESM resolver and Bun's workspace linking. POSIX platforms continue to use relative-path `'dir'` symlinks as before. Windows developers can now `bun install` in a standard (non-admin) shell.
|
|
23
68
|
|
|
24
69
|
### Performance
|
|
25
|
-
- **Walker unification on `GitTracker`.** Every `vat audit` / `vat skills validate` / `vat verify` scan now shares one pre-populated `GitTracker` per repo. The tracker pre-loads the full active file set (tracked + untracked-not-ignored) via `git ls-files --cached --others --exclude-standard`, precomputes the ancestor directory set, and answers every ignore check from an in-memory `Set` instead of spawning `git check-ignore`. Per-directory `gitCheckIgnoredBatch` calls and per-link `isGitIgnored` calls are gone from the hot paths in `packages/cli/src/commands/audit.ts`, `packages/agent-skills/src/walk-link-graph.ts`, `packages/agent-skills/src/validators/packaging-validator.ts`, and `packages/discovery/src/scanners/local-scanner.ts`.
|
|
70
|
+
- **Walker unification on `GitTracker`.** Every `vat audit` / `vat skills validate` / `vat verify` scan now shares one pre-populated `GitTracker` per repo. The tracker pre-loads the full active file set (tracked + untracked-not-ignored) via `git ls-files --cached --others --exclude-standard`, precomputes the ancestor directory set, and answers every ignore check from an in-memory `Set` instead of spawning `git check-ignore`. Per-directory `gitCheckIgnoredBatch` calls and per-link `isGitIgnored` calls are gone from the hot paths in `packages/cli/src/commands/audit.ts`, `packages/agent-skills/src/walk-link-graph.ts`, `packages/agent-skills/src/validators/packaging-validator.ts`, and `packages/discovery/src/scanners/local-scanner.ts`. `@vibe-agent-toolkit/utils` **removes the `gitCheckIgnoredBatch` export** (no remaining in-tree or external callers); `isGitIgnored` is kept as the single-spawn fallback for code paths that don't have a tracker threaded in (e.g. one-off callers in `link-validator.ts` and `walk-link-graph.ts`).
|
|
26
71
|
- **Shared `ResourceRegistry` across skills in `vat skills validate`.** When a single `vat skills validate` invocation covers multiple skills that share one project root, the command now builds one crawled/link-resolved `ResourceRegistry` once and reuses it for every skill's validation instead of re-parsing the same markdown per skill. Heterogeneous scans (mixed project roots) transparently fall back to per-skill registries.
|
|
27
72
|
- **Measured wall-time (median of 3 runs on the VAT monorepo, M-series laptop):**
|
|
28
73
|
- `vat audit .`: 6.85s → 2.50s (~2.7x, under the 3s target set in the rc.1 plan)
|
|
29
74
|
- `vat verify --cwd packages/vat-development-agents`: 12.68s → 2.85s (~4.4x)
|
|
30
75
|
- `vat skills validate packages/vat-development-agents`: 10.05s → 1.44s (~7x)
|
|
31
|
-
-
|
|
76
|
+
- No observable output changes for `vat audit` / `vat skills validate` / `vat verify` — YAML output diffs clean pre/post across all three commands except wall-time fields. One internal shift worth noting: `@vibe-agent-toolkit/discovery`'s `LocalScanner.scan()` now instantiates and eagerly `initialize()`s a `GitTracker` on every call so in-project gitignore checks are O(1); this adds a single `git ls-files` spawn per scan invocation (was effectively a no-op when only one file was scanned). New `GitTracker` APIs (`hasActiveDescendant`, `isIgnoredByActiveSet`) are non-breaking additions; `initialize()` accepts an options bag with `includeUntracked` defaulting to `true`.
|
|
77
|
+
- **Final spawn sweep (post-rc.3).** Two independent spawn-eliminations that together recover the rc.2 baseline and beat it for single-config projects. (1) `vat audit` now caches `discoverSkillsFromConfig` by governing-config root, so per-skill walk-up resolution no longer re-expands the same config's globs N times for an N-skill package. (2) `packages/resources/src/link-validator.ts` switched both `gitTracker.isIgnored()` call sites (source + target) to `isIgnoredByActiveSet`, which answers O(1) against the pre-populated active set for in-project paths. Link validation fires per link and skills typically have dozens of links, so this was the largest remaining spawn source in the audit hot path. Post-fix medians (M-series Mac, 3 runs): VAT self `vat audit .` ~2.5s (recovered rc.2 baseline after rc.3's ~12% regression); vibe-validate `vat audit .` 0.96s → ~0.20s (~5x faster); avonrisk-sdlc `vat audit .` 5.43s → ~4.0s. Windows sees roughly 2x these wins since process-spawn overhead there is ~10x higher than on Linux.
|
|
32
78
|
|
|
33
79
|
## [0.1.32] - 2026-04-19
|
|
34
80
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-agent-toolkit",
|
|
3
|
-
"
|
|
4
|
-
"version": "0.1.33-rc.3",
|
|
3
|
+
"version": "0.1.34-rc.2",
|
|
5
4
|
"author": {
|
|
6
5
|
"name": "vibe-agent-toolkit contributors"
|
|
7
|
-
}
|
|
6
|
+
},
|
|
7
|
+
"description": "Development agents and skills for building with vibe-agent-toolkit"
|
|
8
8
|
}
|
|
@@ -182,15 +182,14 @@ claude:
|
|
|
182
182
|
plugins:
|
|
183
183
|
- name: my-plugin # installable unit
|
|
184
184
|
description: My plugin description
|
|
185
|
-
skills: "*" # all discovered skills
|
|
186
185
|
```
|
|
187
186
|
|
|
188
|
-
The `skills:` section
|
|
187
|
+
The top-level `skills:` section drives standalone skill builds (output: `dist/skills/`). The `claude:` section defines plugins, which are assembled from their own `plugins/<name>/` directories (plugin-local skills under `plugins/<name>/skills/**/SKILL.md`). Each marketplace has `owner` and `plugins` fields (strict schema — no extra fields).
|
|
189
188
|
|
|
190
189
|
**Naming convention:** marketplace = org identity (e.g. `acme`), plugin = this package
|
|
191
190
|
(e.g. `acme-tools`). Registers as `my-plugin@my-marketplace` in Claude's plugin registry.
|
|
192
191
|
|
|
193
|
-
### Multiple skills in one
|
|
192
|
+
### Multiple skills in one plugin
|
|
194
193
|
|
|
195
194
|
List all skills in `vat.skills` for npm discoverability:
|
|
196
195
|
|
|
@@ -201,18 +200,16 @@ List all skills in `vat.skills` for npm discoverability:
|
|
|
201
200
|
}
|
|
202
201
|
```
|
|
203
202
|
|
|
204
|
-
|
|
203
|
+
Each skill lives as a subdirectory of the plugin under `plugins/<name>/skills/<skill>/SKILL.md`:
|
|
205
204
|
|
|
206
|
-
```
|
|
207
|
-
plugins
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
- "my-linting"
|
|
212
|
-
- "my-testing"
|
|
205
|
+
```
|
|
206
|
+
plugins/my-plugin/
|
|
207
|
+
skills/
|
|
208
|
+
my-linting/SKILL.md
|
|
209
|
+
my-testing/SKILL.md
|
|
213
210
|
```
|
|
214
211
|
|
|
215
|
-
|
|
212
|
+
All plugin-local skills found under `plugins/<name>/skills/` are packaged into the plugin automatically — no per-plugin selector is needed or supported. Skill names must be globally unique across all plugins.
|
|
216
213
|
|
|
217
214
|
## Step 3: Build
|
|
218
215
|
|
|
@@ -264,7 +261,6 @@ claude:
|
|
|
264
261
|
plugins:
|
|
265
262
|
- name: my-plugin
|
|
266
263
|
description: My plugin description
|
|
267
|
-
skills: "*"
|
|
268
264
|
publish:
|
|
269
265
|
github:
|
|
270
266
|
repo: owner/repo # GitHub repo to publish to
|
|
@@ -406,3 +402,13 @@ All `vat` commands in this skill work with these alternatives.
|
|
|
406
402
|
## Future: Zero-Dependency Postinstall (Option B)
|
|
407
403
|
|
|
408
404
|
A planned improvement: `vat build` would bundle the plugin install logic into `dist/postinstall.js` — a fully self-contained script with no npm dependencies. The postinstall script would become simply `node ./dist/postinstall.js`. This eliminates `vibe-agent-toolkit` as a runtime dependency entirely, reducing install footprint for end users. Until then, Option C (runtime `vibe-agent-toolkit` dep) is the correct approach.
|
|
405
|
+
|
|
406
|
+
## Full-plugin authoring (commands, hooks, agents, MCP)
|
|
407
|
+
|
|
408
|
+
VAT supports bundling any Claude Code plugin asset — not just skills. Drop the plugin
|
|
409
|
+
under `plugins/<name>/` in the same native layout Claude expects. VAT tree-copies
|
|
410
|
+
everything (minus `skills/` and `.claude-plugin/`), merges author `plugin.json` with
|
|
411
|
+
VAT-owned identity fields, and applies any `files[]` mappings for artifacts built
|
|
412
|
+
outside the plugin dir.
|
|
413
|
+
|
|
414
|
+
See [docs/guides/marketplace-distribution.md](resources/marketplace-distribution.md) section "Full-plugin authoring".
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
# Marketplace Distribution
|
|
2
|
+
|
|
3
|
+
**Guide for building, validating, and publishing Claude plugin marketplaces.**
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
A Claude plugin marketplace is a Git repository containing `.claude-plugin/marketplace.json` and plugin directories. Marketplaces are the distribution unit for Claude Code (via `/plugin marketplace add`) and Cowork (via GitHub App sync). VAT supports three modes of marketplace management.
|
|
8
|
+
|
|
9
|
+
## Three Marketplace Modes
|
|
10
|
+
|
|
11
|
+
| Mode | Description | VAT commands |
|
|
12
|
+
|------|-------------|-------------|
|
|
13
|
+
| **Built** | Source repo with skills → `vat build` → publish to `claude-marketplace` branch | `vat build`, `vat validate`, `vat claude marketplace publish` |
|
|
14
|
+
| **Separate repo** | Source repo → `vat build` → publish to a different Git repo | Same as Built (remote configured in YAML) |
|
|
15
|
+
| **Manual/native** | The repo IS the marketplace — no build step | `vat validate` (with config) or `vat claude marketplace validate` (without config) |
|
|
16
|
+
|
|
17
|
+
## Distribution Surfaces
|
|
18
|
+
|
|
19
|
+
Custom skills and plugins **do not sync across Claude surfaces**. Each surface is independent:
|
|
20
|
+
|
|
21
|
+
| Surface | Source | Scope | Marketplace format? |
|
|
22
|
+
|---------|--------|-------|---------------------|
|
|
23
|
+
| **Claude Code** | Git repo with `marketplace.json` | Self-service install | Yes |
|
|
24
|
+
| **Cowork (claude.ai)** | Admin UI → GitHub App sync from private repo | Org-wide, admin-controlled | Yes (same format) |
|
|
25
|
+
| **Skills API** | `POST /v1/skills` multipart upload | Workspace-wide | No (direct API upload) |
|
|
26
|
+
| **Claude Code (managed)** | `managed-settings.json` via MDM | Per-machine, IT-managed | Yes (marketplace ref in settings) |
|
|
27
|
+
|
|
28
|
+
Public and private GitHub marketplaces use the **same format**. The only difference is authentication (private repos require `GITHUB_TOKEN` or `GH_TOKEN` for auto-updates).
|
|
29
|
+
|
|
30
|
+
## Marketplace Structure
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
marketplace-repo/ # or claude-marketplace branch
|
|
34
|
+
├── .claude-plugin/
|
|
35
|
+
│ └── marketplace.json # marketplace manifest (required)
|
|
36
|
+
├── plugins/
|
|
37
|
+
│ └── plugin-name/
|
|
38
|
+
│ ├── .claude-plugin/
|
|
39
|
+
│ │ └── plugin.json # plugin manifest (required)
|
|
40
|
+
│ ├── skills/
|
|
41
|
+
│ │ └── skill-name/
|
|
42
|
+
│ │ ├── SKILL.md
|
|
43
|
+
│ │ └── references/
|
|
44
|
+
│ ├── commands/ # slash commands (*.md)
|
|
45
|
+
│ ├── agents/ # agent definitions (*.md)
|
|
46
|
+
│ └── hooks/ # hooks.json
|
|
47
|
+
├── CHANGELOG.md # marketplace changelog
|
|
48
|
+
├── README.md # marketplace "storefront" for GitHub
|
|
49
|
+
└── LICENSE # required for distribution
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Versioning Strategy
|
|
53
|
+
|
|
54
|
+
**Marketplace version is the distribution version.** One version for the whole marketplace.
|
|
55
|
+
|
|
56
|
+
| Artifact | Versioned? | Required? | Source |
|
|
57
|
+
|----------|-----------|-----------|--------|
|
|
58
|
+
| Marketplace | Yes | Yes (error if missing) | `package.json` or config |
|
|
59
|
+
| Plugin | Yes | Yes (error if missing) | Defaults to marketplace version |
|
|
60
|
+
| Skill | No | N/A | Tracked by marketplace version |
|
|
61
|
+
|
|
62
|
+
Skills are not independently versioned by VAT. The SKILL.md frontmatter spec has no version field. Skill changes are tracked at the marketplace level.
|
|
63
|
+
|
|
64
|
+
Plugin version defaults to the marketplace version when not explicitly set. The top-level version defaults to `package.json` when available.
|
|
65
|
+
|
|
66
|
+
## Branch Convention
|
|
67
|
+
|
|
68
|
+
**Default publish branch: `claude-marketplace`** — analogous to GitHub Pages' `gh-pages`.
|
|
69
|
+
|
|
70
|
+
- Source code and SDLC on `main` (tests, lint, CI, PRs)
|
|
71
|
+
- Built marketplace artifacts on `claude-marketplace` (clean, generated)
|
|
72
|
+
- Extensible: `claude-marketplace-beta`, `claude-marketplace-next` for staging channels
|
|
73
|
+
- Configurable via `publish.branch` in config or `--branch` flag
|
|
74
|
+
|
|
75
|
+
**Default-branch-only surfaces:** Both Cowork (claude.ai) and Claude Enterprise GitHub sync read from the repository's **default branch only** — they cannot target a specific branch. This means the branch-based publish pattern (`claude-marketplace` / `claude-marketplace-next`) does not work for these surfaces.
|
|
76
|
+
|
|
77
|
+
**Workaround: dedicated marketplace repo.** Create a separate repository where the default branch (`main`) IS the marketplace. Configure `publish.remote` to point to this repo:
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
publish:
|
|
81
|
+
remote: https://github.com/org/my-marketplace-repo.git
|
|
82
|
+
branch: main
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
This keeps your source code and SDLC on the original repo while the marketplace repo contains only the published artifacts.
|
|
86
|
+
|
|
87
|
+
**Enterprise lockdown:** `managed-settings.json` supports `ref` on marketplace sources:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"strictKnownMarketplaces": [
|
|
92
|
+
{ "source": "github", "repo": "acme/plugins", "ref": "claude-marketplace" }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
In `vibe-agent-toolkit.config.yaml`:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
version: 1
|
|
103
|
+
|
|
104
|
+
claude:
|
|
105
|
+
marketplaces:
|
|
106
|
+
my-marketplace:
|
|
107
|
+
owner:
|
|
108
|
+
name: Your Name or Org
|
|
109
|
+
publish:
|
|
110
|
+
branch: claude-marketplace # default
|
|
111
|
+
remote: origin # git remote name, or full URL for cross-repo publish
|
|
112
|
+
changelog: docs/marketplace-changelog.md
|
|
113
|
+
readme: docs/marketplace-readme.md
|
|
114
|
+
license: mit # SPDX identifier or file path
|
|
115
|
+
sourceRepo: false # optional linkback in commit metadata
|
|
116
|
+
plugins:
|
|
117
|
+
- name: my-plugin
|
|
118
|
+
description: What this plugin does
|
|
119
|
+
skills: "*" # or list: ["skill-a", "skill-b"]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### License field
|
|
123
|
+
|
|
124
|
+
The `license` field accepts:
|
|
125
|
+
- **SPDX identifier string** (e.g., `mit`, `apache-2.0`, `gpl-3.0`) — generates standard license text with owner name and current year
|
|
126
|
+
- **File path** (e.g., `./LICENSE` or `docs/LICENSE-ENTERPRISE`) — copies the file as-is
|
|
127
|
+
|
|
128
|
+
Strings are validated against known SPDX identifiers. Paths are distinguished by containing `/` or `.` characters.
|
|
129
|
+
|
|
130
|
+
## Changelog
|
|
131
|
+
|
|
132
|
+
Each marketplace maintains its own `CHANGELOG.md` following [Keep a Changelog](https://keepachangelog.com/) format. The marketplace release cadence may differ from source package releases.
|
|
133
|
+
|
|
134
|
+
- Author maintains the changelog source file in the repo (path configured in YAML)
|
|
135
|
+
- On publish, it's copied to `CHANGELOG.md` in the published tree
|
|
136
|
+
- The `[Unreleased]` section is required for publish — the command refuses if empty
|
|
137
|
+
- On publish, `[Unreleased]` is stamped with version + date
|
|
138
|
+
- The changelog delta becomes the Git commit message body
|
|
139
|
+
|
|
140
|
+
Categories: `Added`, `Changed`, `Removed`, `Fixed`, `Security`.
|
|
141
|
+
|
|
142
|
+
## Publish Flow
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# 1. Build marketplace artifacts
|
|
146
|
+
vat build
|
|
147
|
+
|
|
148
|
+
# 2. Validate everything
|
|
149
|
+
vat validate
|
|
150
|
+
|
|
151
|
+
# 3. Publish to claude-marketplace branch
|
|
152
|
+
vat claude marketplace publish
|
|
153
|
+
|
|
154
|
+
# Or dry-run first
|
|
155
|
+
vat claude marketplace publish --dry-run
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**What publish does:**
|
|
159
|
+
|
|
160
|
+
1. Verifies `vat build` output exists
|
|
161
|
+
2. Checks marketplace changelog has `[Unreleased]` content
|
|
162
|
+
3. Composes the publish tree (marketplace artifacts + CHANGELOG.md + README.md + LICENSE)
|
|
163
|
+
4. Creates a single squashed commit: `publish v{version}` with changelog delta as body
|
|
164
|
+
5. Pushes to the configured branch/remote
|
|
165
|
+
|
|
166
|
+
**Flags:**
|
|
167
|
+
- `--dry-run` — compose and show diff, don't push
|
|
168
|
+
- `--branch <name>` — override configured branch
|
|
169
|
+
- `--force` — force-push (first publish or recovery only)
|
|
170
|
+
|
|
171
|
+
**Commit history:** Each publish adds one commit. The `claude-marketplace` branch accumulates a clean release timeline — `git log` shows the version history of the marketplace.
|
|
172
|
+
|
|
173
|
+
## CI/CD: Cross-Repo Publishing
|
|
174
|
+
|
|
175
|
+
When publishing to a **separate repository** (via `publish.remote`), the default `GITHUB_TOKEN` in GitHub Actions is scoped to the source repo and cannot push to the target. You need a Personal Access Token (PAT) or fine-grained token with write access to the marketplace repo.
|
|
176
|
+
|
|
177
|
+
**Setup:**
|
|
178
|
+
|
|
179
|
+
1. Create a PAT with `contents: write` permission on the marketplace repo
|
|
180
|
+
2. Store it as a repository secret (e.g., `MARKETPLACE_GITHUB_PUSH_TOKEN`)
|
|
181
|
+
3. Expose it as `GH_TOKEN` in your workflow — `vat claude marketplace publish` uses `GH_TOKEN` (or `GITHUB_TOKEN`) to authenticate pushes
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
# .github/workflows/marketplace-publish.yml
|
|
185
|
+
- name: Publish marketplace
|
|
186
|
+
env:
|
|
187
|
+
GH_TOKEN: ${{ secrets.MARKETPLACE_GITHUB_PUSH_TOKEN }}
|
|
188
|
+
run: |
|
|
189
|
+
vat build
|
|
190
|
+
vat claude marketplace publish --branch main
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Why a separate token?** GitHub Actions' built-in `GITHUB_TOKEN` has repo-scoped permissions and cannot push to other repositories. This is a standard pattern for any cross-repo CI operation.
|
|
194
|
+
|
|
195
|
+
## Validation
|
|
196
|
+
|
|
197
|
+
### With config (`vat validate`)
|
|
198
|
+
|
|
199
|
+
When marketplace config exists, `vat validate` orchestrates in dependency order:
|
|
200
|
+
|
|
201
|
+
1. `resources validate` — links, frontmatter, schemas
|
|
202
|
+
2. `skills validate` — SKILL.md structure, frontmatter
|
|
203
|
+
3. `marketplace validate` — marketplace.json, plugin.json, structure
|
|
204
|
+
|
|
205
|
+
Each layer fails fast — bad links block skill validation, bad skills block marketplace validation.
|
|
206
|
+
|
|
207
|
+
### Without config (`vat claude marketplace validate`)
|
|
208
|
+
|
|
209
|
+
Standalone validation for manual/native marketplaces. Uses the same discovery logic as `vat audit` but with **strict expectations** — this must be a valid marketplace:
|
|
210
|
+
|
|
211
|
+
| Check | `vat audit` (liberal) | `marketplace validate` (strict) |
|
|
212
|
+
|-------|----------------------|--------------------------------|
|
|
213
|
+
| Missing version | Warning | Error |
|
|
214
|
+
| Missing LICENSE | Ignored | Error |
|
|
215
|
+
| Bad plugin.json | Warning | Error |
|
|
216
|
+
| Missing README | Ignored | Warning |
|
|
217
|
+
| Missing CHANGELOG | Ignored | Warning |
|
|
218
|
+
| Bad SKILL.md | Warning | Error |
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# Validate a marketplace directory or repo
|
|
222
|
+
vat claude marketplace validate .
|
|
223
|
+
vat claude marketplace validate path/to/marketplace
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Examples
|
|
227
|
+
|
|
228
|
+
### Built mode: monorepo publishes to same repo
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
# vibe-agent-toolkit.config.yaml
|
|
232
|
+
claude:
|
|
233
|
+
marketplaces:
|
|
234
|
+
vat-skills:
|
|
235
|
+
owner:
|
|
236
|
+
name: vibe-agent-toolkit contributors
|
|
237
|
+
publish:
|
|
238
|
+
changelog: docs/marketplace-changelog.md
|
|
239
|
+
readme: docs/marketplace-readme.md
|
|
240
|
+
license: mit
|
|
241
|
+
plugins:
|
|
242
|
+
- name: vibe-agent-toolkit
|
|
243
|
+
description: Development agents and skills
|
|
244
|
+
skills: "*"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
vat build && vat validate && vat claude marketplace publish
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Consumers install via:
|
|
252
|
+
```
|
|
253
|
+
/plugin marketplace add owner/repo#claude-marketplace
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Separate repo: private source, public marketplace
|
|
257
|
+
|
|
258
|
+
```yaml
|
|
259
|
+
# vibe-agent-toolkit.config.yaml in private source repo
|
|
260
|
+
claude:
|
|
261
|
+
marketplaces:
|
|
262
|
+
acme-skills:
|
|
263
|
+
owner:
|
|
264
|
+
name: Acme Corp
|
|
265
|
+
publish:
|
|
266
|
+
remote: git@github.com:acme/acme-skills-marketplace.git
|
|
267
|
+
changelog: docs/marketplace-changelog.md
|
|
268
|
+
readme: docs/marketplace-readme.md
|
|
269
|
+
license: apache-2.0
|
|
270
|
+
plugins:
|
|
271
|
+
- name: acme-tools
|
|
272
|
+
description: Acme engineering tools
|
|
273
|
+
skills: "*"
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Manual/native: repo IS the marketplace
|
|
277
|
+
|
|
278
|
+
No `vat build`, no publish. Author maintains `marketplace.json` and plugin directories directly. Validate with:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# With vibe-agent-toolkit.config.yaml
|
|
282
|
+
vat validate
|
|
283
|
+
|
|
284
|
+
# Without config
|
|
285
|
+
vat claude marketplace validate .
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Testing Your Marketplace
|
|
289
|
+
|
|
290
|
+
After publishing, test the marketplace locally before sharing with users. This flow validates the full consumer experience — clone, install, and skill loading.
|
|
291
|
+
|
|
292
|
+
### Test flow
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# 1. Add the marketplace (uses the published branch)
|
|
296
|
+
claude plugin marketplace add owner/repo#claude-marketplace
|
|
297
|
+
|
|
298
|
+
# 2. Install the plugin from the marketplace
|
|
299
|
+
claude plugin install my-plugin@my-marketplace
|
|
300
|
+
|
|
301
|
+
# 3. Validate the installed plugin
|
|
302
|
+
claude plugin validate ~/.claude/plugins/cache/my-marketplace/my-plugin/<version>
|
|
303
|
+
|
|
304
|
+
# 4. List plugins and verify status
|
|
305
|
+
claude plugin list
|
|
306
|
+
|
|
307
|
+
# 5. Start a new Claude Code session — skills should appear in /skill-name
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### What to verify
|
|
311
|
+
|
|
312
|
+
- **Marketplace add** succeeds and `known_marketplaces.json` shows the correct source
|
|
313
|
+
- **Plugin install** resolves the correct version from plugin.json
|
|
314
|
+
- **All skills** are present in the cache directory
|
|
315
|
+
- **`claude plugin validate`** passes on the installed plugin
|
|
316
|
+
- **`claude plugin list`** shows the plugin as enabled
|
|
317
|
+
- **Skills load** in a new session (check the system reminder for skill names)
|
|
318
|
+
|
|
319
|
+
### Updating after changes
|
|
320
|
+
|
|
321
|
+
After publishing a new version:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
# Update the marketplace cache
|
|
325
|
+
claude plugin marketplace update my-marketplace
|
|
326
|
+
|
|
327
|
+
# Update the installed plugin
|
|
328
|
+
claude plugin update my-plugin@my-marketplace
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Known issues
|
|
332
|
+
|
|
333
|
+
**Name collision on marketplace add (Claude Code v2.1.81):** If a marketplace with the same `name` field already exists (e.g., previously registered via npm), `claude plugin marketplace add` reports success but silently reuses the old source in `known_marketplaces.json`. The workaround is to remove the old marketplace first, then add:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
claude plugin marketplace remove my-marketplace
|
|
337
|
+
claude plugin marketplace add owner/repo#branch
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Verify by checking `~/.claude/plugins/known_marketplaces.json` to confirm the source switched to `github`.
|
|
341
|
+
|
|
342
|
+
**`claude plugin validate` rejects `$schema` key (Claude Code v2.1.81):** The marketplace validator treats `$schema` as an unrecognized key, even though Anthropic's own official marketplace uses it. This does not affect runtime behavior — the marketplace installs and works correctly. This is a Claude Code validation bug, not a marketplace authoring issue.
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
## Full-plugin authoring
|
|
346
|
+
|
|
347
|
+
`vat claude plugin build` ships any Claude Code plugin asset — not just skills. Drop the plugin under `plugins/<name>/` in the same native layout Claude Code expects, declare it in `vibe-agent-toolkit.config.yaml`, and `vat claude plugin build` assembles the output from that plugin's own directory. Pool skills (from the top-level `skills:` discovery) are still imported into the plugin via the `skills:` selector — the plugin directory and the pool skills are both sources, composed into one bundle.
|
|
348
|
+
|
|
349
|
+
### Layout
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
plugins/<name>/
|
|
353
|
+
.claude-plugin/
|
|
354
|
+
plugin.json # author-supplied metadata; VAT merges on top
|
|
355
|
+
commands/ # slash commands (*.md)
|
|
356
|
+
hooks/
|
|
357
|
+
hooks.json # hook registry (JSON; parse-only validated)
|
|
358
|
+
agents/ # subagent definitions (*.md)
|
|
359
|
+
.mcp.json # MCP server config (JSON; parse-only validated)
|
|
360
|
+
scripts/ # arbitrary scripts (tree-copied verbatim)
|
|
361
|
+
skills/ # plugin-local SKILL.md files — tree-copied verbatim
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Everything under `plugins/<name>/` is tree-copied to `dist/.claude/plugins/marketplaces/<mp>/plugins/<name>/`, except:
|
|
365
|
+
|
|
366
|
+
- `.claude-plugin/` — owned by the `plugin.json` merge-write (see "plugin.json merge")
|
|
367
|
+
|
|
368
|
+
Tree-copy respects `.gitignore` (safe: `node_modules/`, build detritus never ship). `plugins/<name>/skills/` is just a regular tree-copied directory — drop raw `SKILL.md` files there and they ship as-is.
|
|
369
|
+
|
|
370
|
+
### Minimum content — empty-plugin guard
|
|
371
|
+
|
|
372
|
+
Every declared plugin must supply at least one of:
|
|
373
|
+
|
|
374
|
+
- a `plugins/<name>/` directory on disk (or an alternate `source:` override pointing at one), **or**
|
|
375
|
+
- a non-empty `files: [{ source, dest }, ...]` mapping, **or**
|
|
376
|
+
- a non-empty `skills:` selector that matches at least one pool skill.
|
|
377
|
+
|
|
378
|
+
A plugin with none of these is rejected with the empty-plugin guard.
|
|
379
|
+
|
|
380
|
+
### `source` override
|
|
381
|
+
|
|
382
|
+
```yaml
|
|
383
|
+
claude:
|
|
384
|
+
marketplaces:
|
|
385
|
+
mp1:
|
|
386
|
+
owner: { name: Example }
|
|
387
|
+
plugins:
|
|
388
|
+
- name: my-plugin
|
|
389
|
+
skills: []
|
|
390
|
+
source: custom/path/to/my-plugin # default: plugins/my-plugin
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### `files[]` — compiled artifacts outside the plugin dir
|
|
394
|
+
|
|
395
|
+
Use `files: [{ source, dest }]` to inject build artifacts (compiled hooks, generated configs) into the plugin output:
|
|
396
|
+
|
|
397
|
+
```yaml
|
|
398
|
+
plugins:
|
|
399
|
+
- name: my-plugin
|
|
400
|
+
skills: []
|
|
401
|
+
files:
|
|
402
|
+
- source: dist/hooks/compiled-hook.mjs # relative to project root
|
|
403
|
+
dest: hooks/compiled-hook.mjs # relative to plugin output dir
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
`dest` cannot escape the plugin output dir and cannot target `.claude-plugin/plugin.json` (owned by merge-write). Overwrites are allowed and logged at info level.
|
|
407
|
+
|
|
408
|
+
### `plugin.json` merge rules
|
|
409
|
+
|
|
410
|
+
VAT writes `.claude-plugin/plugin.json` last, merging the author's `.claude-plugin/plugin.json` (if present) with VAT-owned identity fields:
|
|
411
|
+
|
|
412
|
+
- **VAT wins** on `name`, `version`, `author` (shallow replace — mismatches produce warnings, never errors).
|
|
413
|
+
- **Author wins** on all other keys (`keywords`, `repository`, `homepage`, `license`, …).
|
|
414
|
+
- **Description chain:** `config.description ?? author.description ?? "${name} plugin"`.
|
|
415
|
+
- `version` falls back to the author's value when VAT has no version (no `package.json`).
|
|
416
|
+
|
|
417
|
+
### Ordering contract
|
|
418
|
+
|
|
419
|
+
`vat claude plugin build` runs per plugin in this order:
|
|
420
|
+
|
|
421
|
+
1. Discovery + validators (case-match, `hooks.json`/`.mcp.json` parse, empty-plugin guard)
|
|
422
|
+
2. Tree-copy `plugins/<name>/` verbatim (skips `.claude-plugin/`, respects `.gitignore`)
|
|
423
|
+
3. Pool-skill import via the plugin's `skills:` selector (from `dist/skills/`)
|
|
424
|
+
4. `files[]` mapping (may overwrite tree-copied files; logged at info)
|
|
425
|
+
5. `.claude-plugin/plugin.json` merge-write (always last, always wins)
|
|
426
|
+
|
|
427
|
+
**Run order:** `vat skills build && vat claude plugin build`. The plugin build reads pre-built pool skills from `dist/skills/` and raw plugin-local skills directly from `plugins/<name>/skills/`.
|