diff --git a/.agents/evals/marketplace/marketplace-architect/eval.yaml b/.agents/evals/marketplace/marketplace-architect/eval.yaml
new file mode 100644
index 0000000..7fbbe80
--- /dev/null
+++ b/.agents/evals/marketplace/marketplace-architect/eval.yaml
@@ -0,0 +1,62 @@
+skill_name: marketplace-architect
+
+trigger_tests:
+ - id: explicit-trigger-refactor
+ name: "Explicit trigger — refactor repo into marketplace"
+ query: "turn this repo into a plugin marketplace"
+ should_trigger: true
+
+ - id: implicit-trigger-team-sharing
+ name: "Implicit trigger — team distribution without saying marketplace"
+ query: "how do I share my skills with my team so they can install them"
+ should_trigger: true
+
+ - id: negative-trigger-new-skill
+ name: "Negative trigger — new skill authoring belongs to write-skill"
+ query: "write me a new skill for code review"
+ should_trigger: false
+
+output_tests:
+ - id: deterministic-cross-compat-loaded
+ name: "Deterministic — cross-compat reference loaded before tool-specific recommendations"
+ type: deterministic
+ prompt: "audit this repo and recommend how to convert it into a plugin marketplace for both Claude Code and Copilot CLI"
+ expected_output: >
+ The skill reads references/cross-compat.md early in its response and demonstrates
+ awareness of the Claude Code / Copilot CLI format differences — specifically that
+ manifest paths differ (.claude-plugin/ vs .github/plugin/), agent files differ
+ (.md vs .agent.md), and hooks placement differs — before recommending any layout.
+ assertions:
+ - "Output references or acknowledges the divergence between Claude Code and Copilot CLI manifest paths before proposing a directory layout"
+ - "Output does not recommend a single shared plugin.json location without noting the two-location requirement (.claude-plugin/ and plugin root)"
+ - "Output does not write or propose writing any files before presenting a plan"
+
+ - id: deterministic-gate-a-blocks-writes
+ name: "Deterministic — Gate A plan presented and approval requested before any writes"
+ type: deterministic
+ prompt: "help me migrate my skills and agents into a plugin marketplace layout"
+ expected_output: >
+ The skill produces a migration plan (checklist of old path → new path, one row per
+ file) and explicitly asks the user for approval before proceeding to generate any
+ manifest files. No plugin.json or marketplace.json is written or shown as written output.
+ assertions:
+ - "Output contains a migration plan or checklist with at least one file-move entry in the form 'old path → new path'"
+ - "Output explicitly asks the user to approve or confirm the plan before proceeding"
+ - "Output does not contain a complete plugin.json or marketplace.json file unless the user has already said 'yes' or equivalent in the prompt"
+
+ - id: llm-rubric-adopt-plugin
+ name: "LLM-rubric — adopt external plugin covers all required checks without premature writes"
+ type: llm-rubric
+ prompt: "I want to add this plugin to my marketplace: https://github.com/example/my-tool-plugin"
+ expected_output: >
+ The skill fetches and inspects the plugin source, classifies what assets it contains
+ (skills, agents, hooks, MCP servers), checks whether any existing plugin in the
+ marketplace has a naming conflict, evaluates cross-tool compatibility against the
+ divergence table, and summarises what would be added to marketplace.json — all without
+ writing any files and without proceeding past Gate A without explicit user approval.
+ assertions:
+ - "Response identifies what asset types the external plugin contains (skills, agents, hooks, and/or MCP servers)"
+ - "Response checks or asks about naming conflicts with existing plugins in the marketplace"
+ - "Response notes at least one Claude Code vs Copilot CLI compatibility consideration for the adopted plugin"
+ - "Response summarises the proposed change to marketplace.json without writing the file"
+ - "Response asks for user approval (Gate A) before any file is created or modified"
diff --git a/.agents/skills/marketplace-architect/META.md b/.agents/skills/marketplace-architect/META.md
new file mode 100644
index 0000000..daf0d8d
--- /dev/null
+++ b/.agents/skills/marketplace-architect/META.md
@@ -0,0 +1,21 @@
+```yaml
+version: "1.0"
+updated: 2026-06-20
+
+when: >
+ Invoked when the user wants to create, manage, or maintain a plugin marketplace for
+ Claude Code and/or GitHub Copilot CLI. Covers four operations: (a) audit and refactor
+ a repository of skills/agents/hooks into a plugin marketplace layout, (b) adopt external
+ plugins/skills/agents from outside sources, (c) update and maintain an existing
+ marketplace.json and plugin manifests, (d) validate existing plugin manifests for naming,
+ structure, and cross-tool compatibility. Also triggered implicitly when the user asks
+ about distributing skills to a team, organizing loose skills into installable units, or
+ setting up cross-tool distribution — even without saying "marketplace".
+
+references:
+ - https://code.claude.com/docs/en/plugins
+ - https://code.claude.com/docs/en/plugin-marketplaces
+ - https://code.claude.com/docs/en/plugins-reference
+ - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/plugins-creating
+ - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/plugins-marketplace
+```
diff --git a/.agents/skills/marketplace-architect/SKILL.md b/.agents/skills/marketplace-architect/SKILL.md
new file mode 100644
index 0000000..3449155
--- /dev/null
+++ b/.agents/skills/marketplace-architect/SKILL.md
@@ -0,0 +1,101 @@
+---
+name: marketplace-architect
+description: >
+ Manages and maintains a plugin marketplace for Claude Code and GitHub Copilot CLI.
+ Use this whenever the user wants to: create or update a marketplace (marketplace.json,
+ plugin.json manifests), adopt plugins/skills/agents/hooks from external sources, evaluate
+ cross-tool compatibility between Claude Code and Copilot CLI, plan plugin groupings and
+ boundaries, refactor a repository into marketplace format, validate plugin naming, detect
+ duplicate capabilities, or generate per-plugin install docs — even if they don't use the
+ word "marketplace". Do NOT use when the user wants to author a new skill from scratch
+ (use write-skill), debug an existing skill (use diagnose), or run a direct plugin CLI
+ command (copilot plugin install, claude plugin list).
+metadata:
+ category: marketplace
+---
+
+
+
+## Required inputs
+
+- **Target operation** — what the user wants to do; inferred from request. If ambiguous, ask: audit/refactor, adopt an external plugin, update/maintain an existing marketplace, or validate manifests.
+- **Repository path** — path to the repo to act on; defaults to current working directory if not stated.
+- **Marketplace name** — kebab-case identifier (e.g. `my-ai-marketplace`); required only when generating a new `marketplace.json`. Infer from repo name if obvious, ask if not.
+- **Plugin source** — URL, GitHub slug, or local path; required only when adopting an external plugin.
+
+## Constraints
+
+- Load `references/cross-compat.md` before any tool-specific decision — Claude Code and Copilot CLI diverge in ways that cause silent breakage at install time.
+- Never write files until the user has approved the plan at Gate A and the specific file contents at Gate B — two separate explicit approvals required.
+- If credential-shaped content is detected in any manifest field, halt and redirect to environment variable references (e.g. `$MY_TOKEN`) — do not generate the manifest.
+- Produce cross-tool deltas and per-plugin READMEs only when explicitly requested — do not generate them automatically.
+- Scripts in `scripts/` are loaded on demand by the step that needs them — never preloaded.
+- Flag any `../` cross-references in the audited repo before recommending plugin boundaries — plugins cannot reference files outside their own directory after install-time caching.
+- Plugin names must be kebab-case; validate against the reserved name list in `references/claude-code.md` before generating any manifest.
+- Do not set `version` in both `plugin.json` and the marketplace entry — `plugin.json` wins silently and causes update failures.
+
+
+
+
+
+## Process
+
+1. **Identify the operation.** Determine intent from the user's request — one of: (a) audit/refactor a repo into marketplace format, (b) adopt an external plugin/skill/agent, (c) maintain or update an existing marketplace, (d) validate existing manifests. Ask if the operation cannot be inferred.
+
+2. **Load the compatibility reference.** Read `references/cross-compat.md` before any tool-specific decision. Claude Code and Copilot CLI diverge in manifest paths, agent file naming, and hooks layout — every recommendation depends on this table.
+
+3. **Execute the operation phase.**
+
+ **(a) Audit/refactor:** Run `scripts/inventory.sh` against the repo to classify every asset (skill / command / agent / hook / prompt / MCP). Flag any `../` cross-references — these break under install-time caching. Recommend plugin groupings by user outcome (~10–20 plugins); warn if proposed count exceeds 20 or falls below 3. Diff skill descriptions for duplicate capabilities before finalising boundaries. Produce a concrete migration checklist: old path → new path, one row per file.
+
+ **(b) Adopt external plugin:** Fetch and inspect the plugin source. Classify included assets. Check for naming conflicts with existing plugins in the marketplace. Evaluate cross-tool compatibility using `references/cross-compat.md`. Summarise what will be added to `marketplace.json`.
+
+ **(c) Maintain/update:** Read current `marketplace.json` and all `plugin.json` files. Identify stale versions, reserved name violations, kebab-case violations, and `version` duplication between plugin.json and marketplace entry. Report findings as a prioritised fix list.
+
+ **(d) Validate:** Run `scripts/validate.sh` (wraps `claude plugin validate` plus custom JSON and naming checks). Report each violation with a recommended fix. Do not proceed to file writes until all errors are resolved.
+
+4. **Gate A — plan review.** Present the full plan or fix list to the user. Wait for explicit approval before proceeding. Do not interpret silence or "looks good" as approval — require a direct "yes" or equivalent.
+
+5. **Generate outputs.** After Gate A approval: for audit/refactor and adopt operations, run `scripts/gen_manifests.sh` to produce `plugin.json` (at both `.claude-plugin/plugin.json` and plugin root until the Copilot fallback is verified) and `marketplace.json` (at `.claude-plugin/marketplace.json`; optionally mirror to `.github/plugin/marketplace.json`). Read `references/claude-code.md` for Claude-specific path rules and `references/copilot-cli.md` for Copilot-specific requirements.
+
+6. **Gate B — file write approval.** Show the user every file that will be written with its full contents. Wait for explicit approval per file or as a batch. Write nothing until approved.
+
+7. **Validate post-write.** After writes complete, run `scripts/validate.sh` again. Report any remaining issues. Suggest local install test commands: `claude --plugin-dir ./plugins/` and `copilot plugin install ./plugins/`.
+
+8. **Optional deliverables.** Only when the user explicitly asks: emit cross-tool delta notes (what each plugin needs for Copilot vs Claude Code) and per-plugin README with install commands for both tools.
+
+## Output format
+
+Files generated depend on operation:
+- **Audit/refactor and adopt:** `plugin.json` (two locations per plugin until verified), `marketplace.json` (`.claude-plugin/`, optionally `.github/plugin/`), migration checklist as a markdown table
+- **Maintain/update:** updated `marketplace.json` and affected `plugin.json` files
+- **Validate:** report only — no file writes unless explicitly requested after review
+- **Optional:** per-plugin `README.md` with both `claude` and `copilot` install commands
+
+
+
+
+
+## Failure handling
+
+- `scripts/inventory.sh` not found or fails — perform manual asset classification using Read and Bash find; note the fallback in output.
+- `scripts/gen_manifests.sh` not found or fails — generate manifest JSON inline; flag that the output was not script-produced.
+- `scripts/validate.sh` not found or `claude plugin validate` unavailable — run manual JSON schema and naming checks using `references/claude-code.md`; flag that automated validation was skipped.
+- Plugin source unreachable (bad URL, private repo, missing path) — stop the adopt operation, report the error, ask the user to verify the source before retrying.
+- Reserved name detected in proposed plugin or marketplace name — halt, report the name and the reserved list from `references/claude-code.md`, ask for a replacement before proceeding.
+- Credential-shaped content detected in any manifest field — halt, do not generate the manifest, redirect to environment variable references.
+
+## Self-check
+
+- [ ] `references/cross-compat.md` loaded before any tool-specific recommendation was made
+- [ ] Operation identified before any scanning or file reading began
+- [ ] Gate A presented and explicit approval received before any manifest was generated
+- [ ] Gate B presented with full file contents and explicit approval received before any file was written
+- [ ] No credential-shaped content in any generated manifest field
+- [ ] All plugin names validated as kebab-case and checked against reserved name list
+- [ ] `version` field not set in both `plugin.json` and marketplace entry for the same plugin
+- [ ] Scripts loaded on demand by step — not preloaded at skill invocation
+- [ ] Cross-tool deltas and READMEs produced only if explicitly requested
+- [ ] Post-write validation run and findings reported
+
+
diff --git a/.agents/skills/marketplace-architect/references/claude-code.md b/.agents/skills/marketplace-architect/references/claude-code.md
new file mode 100644
index 0000000..716b8b4
--- /dev/null
+++ b/.agents/skills/marketplace-architect/references/claude-code.md
@@ -0,0 +1,169 @@
+# Claude Code Plugin Reference
+
+Verified against code.claude.com/docs as of June 2026.
+
+---
+
+## Directory structure
+
+```text
+plugin-root/
+├── .claude-plugin/
+│ └── plugin.json # ONLY plugin.json goes here; all other dirs at plugin root
+├── skills/ # skill directories: /SKILL.md
+├── commands/ # legacy flat .md files; promote to skills/ for new plugins
+├── agents/ # agent definitions: .md
+├── hooks/
+│ └── hooks.json
+├── .mcp.json
+├── .lsp.json
+├── monitors/
+│ └── monitors.json
+├── bin/ # executables added to PATH while plugin is enabled
+└── settings.json # default settings applied when plugin is enabled
+```
+
+A plugin that ships exactly one skill may place `SKILL.md` directly at the plugin root.
+Use `skills/` for plugins that may grow beyond one skill.
+
+---
+
+## plugin.json schema
+
+```json
+{
+ "name": "my-plugin", // kebab-case, no spaces — also the skill namespace prefix
+ "displayName": "My Plugin", // human-readable; shown in UI (v2.1.143+)
+ "description": "What it does",
+ "version": "1.0.0", // OPTIONAL — omit to use git SHA per commit
+ "author": { "name": "Name", "url": "https://..." },
+ "homepage": "https://...",
+ "repository": "https://github.com/...",
+ "license": "MIT",
+ "keywords": [],
+ "defaultEnabled": true, // set false to install disabled (v2.1.154+)
+ "dependencies": [
+ { "name": "other-plugin", "version": "~2.1.0" }
+ ]
+}
+```
+
+Only `name` is required. Add fields only when needed.
+
+---
+
+## marketplace.json schema
+
+```json
+{
+ "name": "my-ai-marketplace",
+ "owner": { "name": "Your Name", "email": "you@example.com" },
+ "description": "Description",
+ "version": "1.0.0",
+ "plugins": [
+ {
+ "name": "startup-cto",
+ "source": "./plugins/startup-cto",
+ "description": "...",
+ "strict": true
+ }
+ ]
+}
+```
+
+`description` and `version` are also accepted under a `metadata` key for backward compatibility.
+
+---
+
+## Plugin source types
+
+| Type | Format | Notes |
+|---|---|---|
+| Relative path | `"./plugins/my-plugin"` | Must start with `./`. Resolved from marketplace root. Only works with git-hosted marketplaces, not URL-based. |
+| GitHub | `{ "source": "github", "repo": "owner/repo", "ref": "main", "sha": "abc123" }` | sha pins exact commit; ref is branch/tag |
+| URL / git | `{ "source": "url", "url": "https://...", "ref": "main" }` | also accepts `owner/repo` shorthand and SSH URLs |
+| git-subdir | `{ "source": "git-subdir", "url": "...", "path": "packages/my-plugin" }` | sparse clone of a monorepo path |
+| npm | `{ "source": "npm", "package": "@scope/pkg", "version": "^2.0.0", "registry": "https://..." }` | installed via npm install |
+
+When both `ref` and `sha` are set, `sha` is the effective pin.
+
+---
+
+## Strict mode
+
+Controls whether `plugin.json` is the authority for component definitions.
+
+- **`strict: true`** (default) — plugin has its own `plugin.json`; marketplace entry can add extra skills/hooks on top.
+- **`strict: false`** — marketplace entry is the entire definition; plugin needs no `plugin.json`. The entry declares `skills`, `agents`, `hooks`, `mcpServers` path arrays.
+
+Do not use `strict: false` plus a component-declaring `plugin.json` — this is a conflict and fails to load.
+
+---
+
+## Reserved marketplace names
+
+These names are blocked for third-party use:
+`claude-code-marketplace`, `claude-code-plugins`, `claude-plugins-official`,
+`claude-plugins-community`, `claude-community`, `anthropic-marketplace`,
+`anthropic-plugins`, `agent-skills`, `anthropic-agent-skills`,
+`knowledge-work-plugins`, `life-sciences`, `claude-for-legal`,
+`claude-for-financial-services`, `financial-services-plugins`
+
+Names that impersonate official marketplaces are also blocked (e.g. `official-claude-plugins`,
+`anthropic-tools-v2`).
+
+Plugin names must be kebab-case (lowercase, digits, hyphens). Claude.ai marketplace sync
+rejects anything else even if the local CLI tolerates it.
+
+---
+
+## Version management
+
+- If `version` is set in `plugin.json`, users receive updates only when you bump it.
+- If `version` is omitted, git commit SHA is used — every commit is a new version.
+- If `version` is set in both `plugin.json` and the marketplace entry, `plugin.json` wins silently.
+- **Recommendation:** omit `version` unless you need explicit release gates.
+
+---
+
+## Environment variables
+
+- **`${CLAUDE_PLUGIN_ROOT}`** — absolute path to the plugin's installation directory. Use in hook commands and MCP/LSP configs for all in-plugin file references. This path changes on update.
+- **`${CLAUDE_PLUGIN_DATA}`** — persistent directory for plugin state that survives updates. Use for `node_modules`, generated code, caches.
+
+---
+
+## Validation and CLI commands
+
+```bash
+# Validate plugin structure and manifest
+claude plugin validate ./my-plugin
+claude plugin validate ./my-plugin --strict # treat warnings as errors
+
+# Install/manage
+claude plugin install @
+claude plugin update @
+claude plugin uninstall
+claude plugin list
+claude plugin enable
+claude plugin disable
+
+# Marketplace
+claude plugin marketplace add owner/repo
+claude plugin marketplace update
+
+# Development
+claude --plugin-dir ./my-plugin # load without installing
+claude --plugin-dir ./my-plugin.zip # load from zip (v2.1.128+)
+claude plugin init my-tool # scaffold a skills-dir plugin
+```
+
+---
+
+## Key gotchas
+
+1. **Plugins are copied to cache on install.** Cannot reference `../shared-utils` — those files are not copied. Duplicate shared files into each plugin or use symlinks.
+2. **`commands/` ≠ `skills/`.** Flat `foo.md` is a legacy command; `foo/SKILL.md` is a skill. Promote flat commands to skill directories during migration.
+3. **Only `plugin.json` in `.claude-plugin/`.** Skills, agents, hooks, and other directories must be at the plugin root, not inside `.claude-plugin/`.
+4. **Plugin names are skill namespace prefixes.** `name: my-plugin` means skills invoke as `/my-plugin:skill-name`.
+5. **`defaultEnabled: false` requires v2.1.154+.** Earlier versions ignore it and enable on install.
diff --git a/.agents/skills/marketplace-architect/references/copilot-cli.md b/.agents/skills/marketplace-architect/references/copilot-cli.md
new file mode 100644
index 0000000..10e2bc4
--- /dev/null
+++ b/.agents/skills/marketplace-architect/references/copilot-cli.md
@@ -0,0 +1,143 @@
+# GitHub Copilot CLI Plugin Reference
+
+Verified against docs.github.com as of June 2026.
+
+---
+
+## Directory structure
+
+```text
+plugin-root/
+├── plugin.json # at plugin root (NOT in .claude-plugin/)
+├── skills/ # skill directories: /SKILL.md (same as Claude Code)
+├── agents/ # agent files: .agent.md (differs from Claude Code)
+├── hooks.json # at plugin root (differs from Claude Code: hooks/hooks.json)
+└── .mcp.json # at plugin root (same as Claude Code)
+```
+
+---
+
+## plugin.json schema (Copilot)
+
+```json
+{
+ "name": "my-plugin",
+ "description": "What it does",
+ "version": "1.0.0",
+ "author": { "name": "Name", "email": "you@example.com" },
+ "license": "MIT",
+ "keywords": [],
+ "agents": "agents/",
+ "skills": ["skills/"],
+ "hooks": "hooks.json",
+ "mcpServers": ".mcp.json"
+}
+```
+
+Key difference from Claude Code: Copilot expects component path declarations inside
+`plugin.json` (`"skills": "skills/"`, `"agents": "agents/"`, etc.). Claude Code instead
+defaults to standard dirs and takes path overrides only via the marketplace entry.
+This means the same `plugin.json` may need these fields for Copilot but not for Claude.
+
+---
+
+## marketplace.json schema (Copilot)
+
+```json
+{
+ "name": "my-ai-marketplace",
+ "owner": { "name": "Your Name", "email": "you@example.com" },
+ "metadata": { "description": "Agents, skills and workflows", "version": "1.0.0" },
+ "plugins": [
+ {
+ "name": "startup-cto",
+ "source": "./plugins/startup-cto",
+ "description": "...",
+ "version": "1.0.0"
+ }
+ ]
+}
+```
+
+Copilot's primary marketplace manifest path is `.github/plugin/marketplace.json`.
+It also reads `.claude-plugin/marketplace.json` as a fallback.
+Relative `source` paths: `./x` and `x` are both valid (Claude requires `./`).
+
+---
+
+## Agent file format
+
+Copilot agents use `.agent.md` extension with frontmatter:
+
+```markdown
+---
+name: my-agent
+description: What this agent does
+tools:
+ - read_file
+ - run_command
+---
+
+Agent instructions here.
+```
+
+Claude Code agents use `.md` extension without the `.agent.md` suffix.
+If shipping agents for both tools, create both files:
+- `agents/my-agent.md` — Claude Code
+- `agents/my-agent.agent.md` — Copilot CLI
+
+---
+
+## CLI commands
+
+```bash
+# Install plugin locally (development)
+copilot plugin install ./my-plugin
+
+# List installed plugins
+copilot plugin list
+
+# In interactive mode
+/plugin list
+/skills list
+/agent
+
+# Reload after changes
+/reload-plugins
+
+# Uninstall (uses bare plugin name, not @marketplace form)
+copilot plugin uninstall
+
+# Marketplace
+copilot plugin marketplace add owner/repo
+```
+
+> ⚠️ **UNVERIFIED: Copilot marketplace install command.**
+> The `update`/`uninstall` commands take a bare ``. Whether install from a marketplace
+> uses `@` (Claude Code's form) or a bare `` is not confirmed in docs.
+> Run `copilot plugin install --help` before documenting the install command anywhere.
+
+---
+
+## Validation
+
+Copilot has no documented `plugin validate` command. For Copilot-side validation, run manual checks:
+- Valid JSON in `plugin.json` and `marketplace.json`
+- Required fields: `name`, `description`
+- Unique plugin names across marketplace
+- Kebab-case plugin names
+- All `source` paths resolve to existing directories
+- `.agent.md` files have valid YAML frontmatter with `name`, `description`, `tools`
+
+---
+
+## Key differences from Claude Code (summary)
+
+| What | Claude Code | Copilot CLI |
+|---|---|---|
+| Plugin manifest location | `.claude-plugin/plugin.json` | `plugin.json` at plugin root |
+| Agent files | `agents/.md` | `agents/.agent.md` |
+| Hooks file | `hooks/hooks.json` | `hooks.json` at plugin root |
+| Component paths | Declared in marketplace entry | Declared in `plugin.json` |
+| Validate command | `claude plugin validate` | None — manual checks only |
+| Relative source `./` | Required | Optional (`x` also valid) |
diff --git a/.agents/skills/marketplace-architect/references/cross-compat.md b/.agents/skills/marketplace-architect/references/cross-compat.md
new file mode 100644
index 0000000..82ae592
--- /dev/null
+++ b/.agents/skills/marketplace-architect/references/cross-compat.md
@@ -0,0 +1,79 @@
+# Cross-Tool Compatibility Reference
+
+Claude Code and GitHub Copilot CLI share the plugin concept but diverge in specific, breaking
+ways. **Skills are the portable core. Manifests and agents are where they split.**
+
+Make Claude Code the source of truth — it is the stricter, more fully specified format.
+Treat "loads in Copilot CLI" as a tested checklist item per plugin, not an assumption.
+
+---
+
+## Divergence table
+
+| Concern | Claude Code | GitHub Copilot CLI | Portable choice |
+|---|---|---|---|
+| Marketplace manifest path | `.claude-plugin/marketplace.json` (required) | `.github/plugin/marketplace.json` (primary); also reads `.claude-plugin/` | Put it in `.claude-plugin/` — both read it. Optionally mirror to `.github/plugin/`. |
+| Plugin manifest path | `.claude-plugin/plugin.json` (required; only `plugin.json` goes in this dir) | `plugin.json` at **plugin root** | Ship in both locations until verified — see ⚠️ below |
+| Skills | `skills//SKILL.md` | `skills//SKILL.md` | ✅ Identical |
+| Agents | `agents/.md` | `agents/.agent.md` (frontmatter incl. `tools:`) | Diverges — keep portable logic in skills; ship per-tool agent files only when needed |
+| Hooks | `hooks/hooks.json` | `hooks.json` at plugin root | Diverges; declare paths in manifest to be safe |
+| MCP servers | `.mcp.json` at plugin root | `.mcp.json` at plugin root | ✅ Same |
+| Relative `source` | must start with `./` | `./x` and `x` both valid | Always use `./` — valid for both |
+| Validate command | `claude plugin validate .` (or `/plugin validate .`) | none documented | Run Claude validator + manual JSON checks for Copilot |
+| Install marketplace | `claude plugin marketplace add owner/repo` | `copilot plugin marketplace add owner/repo` | Same shape |
+| Install plugin | `claude plugin install @` | install by plugin name; `@marketplace` suffix unconfirmed | ⚠️ Verify Copilot install string before documenting |
+| Local install (dev) | `claude --plugin-dir ./plugin` | `copilot plugin install ./plugin` | Tool-specific |
+| Component paths in plugin.json | Claude defaults to standard dirs; path overrides via marketplace entry only | `"skills": "skills/"`, `"agents": "agents/"`, etc. in plugin.json | Generate per-tool manifests rather than one shared file |
+
+> ⚠️ **UNVERIFIED — test before committing to a layout.**
+> Copilot docs confirm it reads the **marketplace** manifest from `.claude-plugin/`. They do NOT
+> confirm the same fallback for a plugin's `plugin.json`. Copilot docs show `plugin.json` at plugin
+> root; Claude requires it in `.claude-plugin/`. Until verified: ship `plugin.json` in BOTH
+> `plugin-name/plugin.json` and `plugin-name/.claude-plugin/plugin.json` (identical content), then
+> drop whichever proves redundant.
+
+---
+
+## `@` resolution
+
+`claude plugin install startup-cto@my-ai-marketplace` requires the marketplace manifest's
+top-level `name` field to be exactly `my-ai-marketplace`. It is **not** the GitHub repo name.
+Keep them aligned to avoid confusion, but they are separate fields.
+
+---
+
+## Canonical cross-compatible repo layout
+
+```text
+repo-root/
+├── .claude-plugin/
+│ └── marketplace.json # both tools read here
+├── .github/plugin/
+│ └── marketplace.json # OPTIONAL: Copilot canonical path (mirror)
+├── plugins/
+│ └── startup-cto/
+│ ├── plugin.json # Copilot root manifest ┐ ship both until
+│ ├── .claude-plugin/ # │ the note above is
+│ │ └── plugin.json # Claude manifest ┘ verified
+│ ├── skills/
+│ │ ├── fundraising/SKILL.md
+│ │ └── hiring/SKILL.md
+│ ├── agents/
+│ │ ├── startup-cto.md # Claude
+│ │ └── startup-cto.agent.md # Copilot (only if shipping native agents)
+│ ├── hooks/hooks.json # Claude
+│ ├── hooks.json # Copilot (if hooks used)
+│ └── README.md
+└── README.md
+```
+
+---
+
+## Open questions to resolve before generating layouts
+
+1. **Does Copilot CLI load a plugin whose `plugin.json` lives only in `.claude-plugin/`?**
+ Install a test plugin both ways. The answer decides whether to ship one manifest or two.
+
+2. **What is Copilot's exact install-from-marketplace command?**
+ Run `copilot plugin install --help`. The `update`/`uninstall` commands take a bare plugin
+ name — the `@marketplace` form may not apply.
diff --git a/.agents/skills/marketplace-architect/scripts/gen_manifests.sh b/.agents/skills/marketplace-architect/scripts/gen_manifests.sh
new file mode 100755
index 0000000..7f911b9
--- /dev/null
+++ b/.agents/skills/marketplace-architect/scripts/gen_manifests.sh
@@ -0,0 +1,194 @@
+#!/usr/bin/env bash
+# Generate plugin.json (in both locations) and marketplace.json.
+# Dry-run by default; pass --write to apply.
+#
+# Usage:
+# gen_manifests.sh --marketplace-name [options]
+#
+# Options:
+# --marketplace-name kebab-case marketplace identifier (required)
+# --author "Name " author string (default: "Unknown ")
+# --plugins-dir subdir containing plugin folders (default: plugins)
+# --mirror-github also write to .github/plugin/marketplace.json
+# --write apply changes (default is dry run)
+
+set -euo pipefail
+
+RESERVED_NAMES="claude-code-marketplace claude-code-plugins claude-plugins-official
+ claude-plugins-community claude-community anthropic-marketplace anthropic-plugins
+ agent-skills anthropic-agent-skills knowledge-work-plugins life-sciences
+ claude-for-legal claude-for-financial-services financial-services-plugins"
+
+RESERVED_PATTERNS="official-claude anthropic-tools claude-official"
+
+is_kebab_case() {
+ [[ "$1" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]
+}
+
+is_reserved() {
+ local name="$1"
+ for n in $RESERVED_NAMES; do
+ [[ "$name" == "$n" ]] && return 0
+ done
+ for p in $RESERVED_PATTERNS; do
+ [[ "$name" == "$p"* ]] && return 0
+ done
+ return 1
+}
+
+validate_name() {
+ local name="$1" context="$2"
+ local ok=true
+ if ! is_kebab_case "$name"; then
+ echo "ERROR: $context: name '$name' is not kebab-case (lowercase, digits, hyphens only)." >&2
+ ok=false
+ fi
+ if is_reserved "$name"; then
+ echo "ERROR: $context: name '$name' is reserved for official Anthropic use." >&2
+ ok=false
+ fi
+ [[ "$ok" == "true" ]]
+}
+
+write_json() {
+ local path="$1" content="$2" dry_run="$3"
+ if [[ "$dry_run" == "true" ]]; then
+ echo ""
+ echo "--- $path (dry run) ---"
+ echo "$content"
+ else
+ mkdir -p "$(dirname "$path")"
+ echo "$content" > "$path"
+ echo " Written: $path"
+ fi
+}
+
+# ── parse args ───────────────────────────────────────────────────────────────
+
+ROOT=""
+MARKETPLACE_NAME=""
+AUTHOR="Unknown "
+PLUGINS_DIR="plugins"
+MIRROR_GITHUB=false
+WRITE=false
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --marketplace-name) MARKETPLACE_NAME="$2"; shift 2 ;;
+ --author) AUTHOR="$2"; shift 2 ;;
+ --plugins-dir) PLUGINS_DIR="$2"; shift 2 ;;
+ --mirror-github) MIRROR_GITHUB=true; shift ;;
+ --write) WRITE=true; shift ;;
+ -*) echo "Unknown option: $1" >&2; exit 1 ;;
+ *) ROOT="$1"; shift ;;
+ esac
+done
+
+if [[ -z "$ROOT" || -z "$MARKETPLACE_NAME" ]]; then
+ echo "Usage: gen_manifests.sh --marketplace-name [--write]" >&2
+ exit 1
+fi
+
+ROOT="$(cd "$ROOT" && pwd)"
+DRY_RUN=$( [[ "$WRITE" == "true" ]] && echo "false" || echo "true" )
+
+[[ "$DRY_RUN" == "true" ]] && echo "DRY RUN — pass --write to apply changes"
+
+# Parse author
+AUTHOR_NAME="${AUTHOR%% <*}"
+AUTHOR_EMAIL=""
+if [[ "$AUTHOR" =~ \<(.+)\> ]]; then
+ AUTHOR_EMAIL="${BASH_REMATCH[1]}"
+fi
+
+# Validate marketplace name
+validate_name "$MARKETPLACE_NAME" "marketplace" || exit 1
+
+# Discover plugins
+PLUGINS_PATH="$ROOT/$PLUGINS_DIR"
+if [[ ! -d "$PLUGINS_PATH" ]]; then
+ echo "No plugins directory found at $PLUGINS_PATH" >&2
+ exit 1
+fi
+
+mapfile -t PLUGIN_DIRS < <(find "$PLUGINS_PATH" -mindepth 1 -maxdepth 1 -type d ! -name '.*' | sort)
+
+if [[ ${#PLUGIN_DIRS[@]} -eq 0 ]]; then
+ echo "No plugin directories found in $PLUGINS_PATH" >&2
+ exit 1
+fi
+
+echo "Found ${#PLUGIN_DIRS[@]} plugin(s)"
+
+# Build plugins array for marketplace.json
+PLUGINS_JSON="[]"
+
+for pd in "${PLUGIN_DIRS[@]}"; do
+ pname="$(basename "$pd")"
+ validate_name "$pname" "plugin '$pname'" || exit 1
+
+ # Read existing plugin.json if present
+ existing_claude="$pd/.claude-plugin/plugin.json"
+ existing_root="$pd/plugin.json"
+ existing_desc="Plugin: $pname"
+ existing_name="$pname"
+
+ for existing in "$existing_claude" "$existing_root"; do
+ if [[ -f "$existing" ]] && jq -e . "$existing" >/dev/null 2>&1; then
+ d=$(jq -r '.description // empty' "$existing")
+ n=$(jq -r '.name // empty' "$existing")
+ [[ -n "$d" ]] && existing_desc="$d"
+ [[ -n "$n" ]] && existing_name="$n"
+ break
+ fi
+ done
+
+ # Warn on version
+ for existing in "$existing_claude" "$existing_root"; do
+ if [[ -f "$existing" ]] && jq -e '.version' "$existing" >/dev/null 2>&1; then
+ echo " WARNING: plugin '$pname' sets version in plugin.json. Do not also set it in the marketplace entry — plugin.json wins silently."
+ break
+ fi
+ done
+
+ # Build plugin.json
+ plugin_json=$(jq -n \
+ --arg name "$existing_name" \
+ --arg desc "$existing_desc" \
+ --arg aname "$AUTHOR_NAME" \
+ --arg aemail "$AUTHOR_EMAIL" \
+ '{name: $name, description: $desc, author: {name: $aname, email: $aemail}}')
+
+ write_json "$pd/plugin.json" "$plugin_json" "$DRY_RUN"
+ write_json "$pd/.claude-plugin/plugin.json" "$plugin_json" "$DRY_RUN"
+
+ source="./$PLUGINS_DIR/$pname"
+ PLUGINS_JSON=$(echo "$PLUGINS_JSON" | jq \
+ --arg name "$existing_name" \
+ --arg src "$source" \
+ --arg desc "$existing_desc" \
+ '. + [{name: $name, source: $src, description: $desc}]')
+done
+
+# Build marketplace.json
+marketplace_json=$(jq -n \
+ --arg name "$MARKETPLACE_NAME" \
+ --arg aname "$AUTHOR_NAME" \
+ --arg aemail "$AUTHOR_EMAIL" \
+ --arg desc "$MARKETPLACE_NAME plugin marketplace" \
+ --argjson plugins "$PLUGINS_JSON" \
+ '{name: $name, owner: {name: $aname, email: $aemail}, description: $desc, plugins: $plugins}')
+
+write_json "$ROOT/.claude-plugin/marketplace.json" "$marketplace_json" "$DRY_RUN"
+
+if [[ "$MIRROR_GITHUB" == "true" ]]; then
+ write_json "$ROOT/.github/plugin/marketplace.json" "$marketplace_json" "$DRY_RUN"
+fi
+
+if [[ "$DRY_RUN" == "true" ]]; then
+ echo ""
+ echo "--- End dry run. Pass --write to apply. ---"
+else
+ echo ""
+ echo "Done. Run scripts/validate.sh to verify."
+fi
diff --git a/.agents/skills/marketplace-architect/scripts/inventory.sh b/.agents/skills/marketplace-architect/scripts/inventory.sh
new file mode 100755
index 0000000..bcaa69a
--- /dev/null
+++ b/.agents/skills/marketplace-architect/scripts/inventory.sh
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+# Scan a repository and classify every asset as skill/command/agent/hook/prompt/MCP.
+# Outputs a markdown table of findings plus a list of cross-reference warnings.
+#
+# Usage: inventory.sh
+
+set -euo pipefail
+
+if [[ $# -lt 1 ]]; then
+ echo "Usage: inventory.sh " >&2
+ exit 1
+fi
+
+ROOT="$(cd "$1" && pwd)"
+
+if [[ ! -d "$ROOT" ]]; then
+ echo "Error: $ROOT is not a directory" >&2
+ exit 1
+fi
+
+# ── classify assets ──────────────────────────────────────────────────────────
+
+declare -a ROWS=()
+declare -a CROSS_REFS=()
+
+while IFS= read -r -d '' path; do
+ rel="${path#"$ROOT/"}"
+ name="$(basename "$path")"
+ dir="$(dirname "$rel")"
+ parent="$(basename "$dir")"
+
+ # Skip hidden dirs except .claude-plugin and .github
+ skip=false
+ IFS='/' read -ra parts <<< "$dir"
+ for part in "${parts[@]}"; do
+ if [[ "$part" == .* && "$part" != ".claude-plugin" && "$part" != ".github" ]]; then
+ skip=true; break
+ fi
+ done
+ $skip && continue
+
+ asset_type=""
+
+ case "$name" in
+ SKILL.md) asset_type="skill" ;;
+ hooks.json) asset_type="hook" ;;
+ .mcp.json) asset_type="mcp" ;;
+ .lsp.json) asset_type="lsp" ;;
+ plugin.json) asset_type="manifest-plugin" ;;
+ marketplace.json) asset_type="manifest-marketplace" ;;
+ *.agent.md) asset_type="agent-copilot" ;;
+ *.md)
+ if [[ "$parent" == "agents" ]]; then
+ asset_type="agent-claude"
+ elif [[ "$parent" == "commands" ]]; then
+ asset_type="command"
+ elif [[ "$rel" != *"/skills/"* && "$rel" != *"/commands/"* && "$rel" != *"/agents/"* ]]; then
+ asset_type="prompt"
+ fi
+ ;;
+ esac
+
+ [[ -n "$asset_type" ]] && ROWS+=("$asset_type|$rel")
+
+ # Check for cross-references in text files
+ case "$name" in *.md|*.json|*.sh)
+ if grep -q '\.\.\/' "$path" 2>/dev/null; then
+ while IFS= read -r line; do
+ lineno="${line%%:*}"
+ content="${line#*:}"
+ CROSS_REFS+=("$rel:$lineno: $content")
+ done < <(grep -n '\.\.\/' "$path" 2>/dev/null | head -20)
+ fi
+ ;;
+ esac
+
+done < <(find "$ROOT" -type f -print0 | sort -z)
+
+# ── report ───────────────────────────────────────────────────────────────────
+
+echo "# Asset Inventory: $ROOT"
+echo ""
+echo "## Assets"
+echo ""
+echo "| Type | Path |"
+echo "|---|---|"
+for row in "${ROWS[@]+"${ROWS[@]}"}"; do
+ type="${row%%|*}"
+ path="${row#*|}"
+ echo "| \`$type\` | \`$path\` |"
+done | sort
+
+total="${#ROWS[@]}"
+echo ""
+echo "**Total: $total assets**"
+echo ""
+
+# Summary by type
+echo "## Summary by type"
+echo ""
+for row in "${ROWS[@]+"${ROWS[@]}"}"; do
+ echo "${row%%|*}"
+done | sort | uniq -c | while read -r count type; do
+ echo "- \`$type\`: $count"
+done
+
+# Cross-reference warnings
+echo ""
+if [[ ${#CROSS_REFS[@]} -gt 0 ]]; then
+ echo "## ⚠️ Cross-reference warnings (${#CROSS_REFS[@]} found)"
+ echo ""
+ echo "These \`../\` references will break after install-time caching:"
+ echo ""
+ for ref in "${CROSS_REFS[@]}"; do
+ echo "- \`$ref\`"
+ done
+else
+ echo "## Cross-references"
+ echo ""
+ echo "No \`../\` cross-references found. Safe to proceed with plugin boundaries."
+fi
diff --git a/.agents/skills/marketplace-architect/scripts/validate.sh b/.agents/skills/marketplace-architect/scripts/validate.sh
new file mode 100755
index 0000000..b844dff
--- /dev/null
+++ b/.agents/skills/marketplace-architect/scripts/validate.sh
@@ -0,0 +1,264 @@
+#!/usr/bin/env bash
+# Validate plugin marketplace manifests for Claude Code and GitHub Copilot CLI.
+# Wraps `claude plugin validate` (Claude-side) and runs manual checks (Copilot-side).
+#
+# Usage:
+# validate.sh
+# validate.sh --plugin plugins/my-plugin
+
+set -euo pipefail
+
+RESERVED_NAMES="claude-code-marketplace claude-code-plugins claude-plugins-official
+ claude-plugins-community claude-community anthropic-marketplace anthropic-plugins
+ agent-skills anthropic-agent-skills knowledge-work-plugins life-sciences
+ claude-for-legal claude-for-financial-services financial-services-plugins"
+
+RESERVED_PATTERNS="official-claude anthropic-tools claude-official"
+
+ERRORS=0
+WARNINGS=0
+
+error() { echo "ERROR: $1"; ((ERRORS++)) || true; }
+warn() { echo "WARN: $1"; ((WARNINGS++)) || true; }
+
+is_kebab_case() { [[ "$1" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; }
+
+is_reserved() {
+ local name="$1"
+ for n in $RESERVED_NAMES; do [[ "$name" == "$n" ]] && return 0; done
+ for p in $RESERVED_PATTERNS; do [[ "$name" == "$p"* ]] && return 0; done
+ return 1
+}
+
+validate_name() {
+ local name="$1" context="$2"
+ [[ -z "$name" ]] && { error "$context: name is missing or empty"; return 0; }
+ is_kebab_case "$name" || error "$context: name '$name' is not kebab-case"
+ if is_reserved "$name"; then
+ error "$context: name '$name' is reserved for official Anthropic use"
+ fi
+ return 0
+}
+
+valid_json() {
+ local path="$1"
+ if ! jq -e . "$path" >/dev/null 2>&1; then
+ error "Invalid JSON in $path"
+ return 1
+ fi
+ return 0
+}
+
+validate_marketplace_json() {
+ local path="$1"
+ [[ -f "$path" ]] || return 0
+ valid_json "$path" || return 0
+
+ local name
+ name=$(jq -r '.name // empty' "$path")
+ [[ -z "$name" ]] && error "$path: 'name' field is required" || validate_name "$name" "$path"
+
+ local plugins_type
+ plugins_type=$(jq -r 'if .plugins | type == "array" then "ok" else "bad" end' "$path")
+ if [[ "$plugins_type" != "ok" ]]; then
+ error "$path: 'plugins' must be an array"
+ return 0
+ fi
+
+ # Check each plugin entry
+ local seen_names=()
+ while IFS= read -r pname; do
+ # Duplicate check
+ for seen in "${seen_names[@]+"${seen_names[@]}"}"; do
+ if [[ "$seen" == "$pname" ]]; then error "$path: duplicate plugin name '$pname'"; fi
+ done
+ seen_names+=("$pname")
+ validate_name "$pname" "$path plugin '$pname'"
+
+ # Source path check
+ local src
+ src=$(jq -r --arg n "$pname" '.plugins[] | select(.name==$n) | .source // empty' "$path")
+ if [[ -n "$src" && "$src" != ./* && "$src" != "github" && "$src" != "npm" && "$src" != "url" && "$src" != "git-subdir" ]]; then
+ warn "$path plugin '$pname': relative source '$src' should start with './' for Claude Code compatibility"
+ fi
+
+ # Version duplication warning
+ local has_ver
+ has_ver=$(jq -r --arg n "$pname" '.plugins[] | select(.name==$n) | .version // empty' "$path")
+ if [[ -n "$has_ver" ]]; then
+ warn "$path plugin '$pname': version set in marketplace entry. If also set in plugin.json, plugin.json wins silently."
+ fi
+
+ done < <(jq -r '.plugins[].name // empty' "$path")
+ return 0
+}
+
+validate_plugin_json() {
+ local path="$1" marketplace_json="${2:-}"
+ [[ -f "$path" ]] || return 0
+ valid_json "$path" || return 0
+
+ local name
+ name=$(jq -r '.name // empty' "$path")
+ if [[ -z "$name" ]]; then
+ warn "$path: 'name' field missing (plugin dir name will be used)"
+ else
+ validate_name "$name" "$path"
+
+ # Version duplication check
+ if [[ -n "$marketplace_json" && -f "$marketplace_json" ]]; then
+ local pver mver
+ pver=$(jq -r '.version // empty' "$path")
+ mver=$(jq -r --arg n "$name" '.plugins[]? | select(.name==$n) | .version // empty' "$marketplace_json")
+ if [[ -n "$pver" && -n "$mver" ]]; then
+ error "$path: version '$pver' set in both plugin.json and marketplace entry — plugin.json wins silently. Remove one."
+ fi
+ fi
+ fi
+ return 0
+}
+
+validate_skill_md() {
+ local path="$1"
+ local content
+ content=$(cat "$path")
+ if [[ "$content" != ---* ]]; then
+ warn "$path: SKILL.md has no YAML frontmatter"
+ return
+ fi
+ if ! echo "$content" | awk 'NR>1 && /^---/' | grep -q '^---'; then
+ error "$path: SKILL.md frontmatter not closed"
+ return
+ fi
+ if ! echo "$content" | awk '/^---/{n++; if(n==2) exit} n==1' | grep -q 'description:'; then
+ warn "$path: SKILL.md frontmatter missing 'description' field"
+ fi
+}
+
+validate_plugin_dir() {
+ local pd="$1" marketplace_json="${2:-}"
+
+ local claude_manifest="$pd/.claude-plugin/plugin.json"
+ local root_manifest="$pd/plugin.json"
+
+ if [[ ! -f "$claude_manifest" && ! -f "$root_manifest" ]]; then
+ warn "$pd: no plugin.json found (will auto-discover components)"
+ else
+ validate_plugin_json "$claude_manifest" "$marketplace_json"
+ validate_plugin_json "$root_manifest" "$marketplace_json"
+
+ # Sync check
+ if [[ -f "$claude_manifest" && -f "$root_manifest" ]]; then
+ if ! diff <(jq -S . "$claude_manifest") <(jq -S . "$root_manifest") >/dev/null 2>&1; then
+ warn "$pd: .claude-plugin/plugin.json and plugin.json differ — keep them in sync"
+ fi
+ fi
+ fi
+
+ # Components must not be inside .claude-plugin/
+ for bad_dir in skills agents hooks commands; do
+ if [[ -d "$pd/.claude-plugin/$bad_dir" ]]; then
+ error "$pd/.claude-plugin/$bad_dir: only plugin.json belongs in .claude-plugin/; move $bad_dir/ to plugin root"
+ fi
+ done
+
+ # Validate SKILL.md files
+ while IFS= read -r -d '' skill_md; do
+ validate_skill_md "$skill_md"
+ done < <(find "$pd" -name "SKILL.md" -print0 2>/dev/null)
+
+ # Cross-reference check
+ while IFS= read -r -d '' f; do
+ if grep -q '\.\.\/' "$f" 2>/dev/null; then
+ local rel="${f#"$pd/"}"
+ error "$rel: contains '../' reference — plugins cannot access files outside their directory after caching"
+ fi
+ done < <(find "$pd" \( -name "*.md" -o -name "*.json" \) -print0 2>/dev/null)
+}
+
+run_claude_validate() {
+ local path="$1"
+ if command -v claude >/dev/null 2>&1; then
+ if ! claude plugin validate "$path" 2>&1; then
+ error "claude plugin validate failed for $path"
+ fi
+ else
+ warn "'claude' CLI not found — skipping claude plugin validate"
+ fi
+}
+
+# ── parse args ────────────────────────────────────────────────────────────────
+
+ROOT=""
+PLUGIN_ONLY=""
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --plugin) PLUGIN_ONLY="$2"; shift 2 ;;
+ -*) echo "Unknown option: $1" >&2; exit 1 ;;
+ *) ROOT="$1"; shift ;;
+ esac
+done
+
+if [[ -z "$ROOT" ]]; then
+ echo "Usage: validate.sh [--plugin ]" >&2
+ exit 1
+fi
+
+ROOT="$(cd "$ROOT" && pwd)"
+
+# ── validate marketplace.json ─────────────────────────────────────────────────
+
+MARKETPLACE_JSON=""
+for mp in "$ROOT/.claude-plugin/marketplace.json" "$ROOT/.github/plugin/marketplace.json"; do
+ if [[ -f "$mp" ]]; then
+ MARKETPLACE_JSON="$mp"
+ validate_marketplace_json "$mp"
+ break
+ fi
+done
+
+if [[ -z "$MARKETPLACE_JSON" ]]; then
+ warn "No marketplace.json found. Expected at .claude-plugin/marketplace.json"
+fi
+
+# ── validate plugins ──────────────────────────────────────────────────────────
+
+if [[ -n "$PLUGIN_ONLY" ]]; then
+ validate_plugin_dir "$(cd "$PLUGIN_ONLY" && pwd)" "$MARKETPLACE_JSON"
+ run_claude_validate "$(cd "$PLUGIN_ONLY" && pwd)"
+else
+ plugins_path="$ROOT/plugins"
+ if [[ -d "$plugins_path" ]]; then
+ while IFS= read -r -d '' pd; do
+ validate_plugin_dir "$pd" "$MARKETPLACE_JSON"
+ run_claude_validate "$pd"
+ done < <(find "$plugins_path" -mindepth 1 -maxdepth 1 -type d ! -name '.*' -print0 | sort -z)
+ else
+ warn "No plugins/ directory found at $ROOT"
+ fi
+fi
+
+# ── check source paths resolve ────────────────────────────────────────────────
+
+if [[ -n "$MARKETPLACE_JSON" ]]; then
+ while IFS= read -r src; do
+ [[ "$src" != ./* ]] && continue
+ src_path="$ROOT/${src#./}"
+ if [[ ! -d "$src_path" ]]; then error "Marketplace source path '$src' does not exist at $src_path"; fi
+ done < <(jq -r '.plugins[]?.source | strings' "$MARKETPLACE_JSON" 2>/dev/null)
+fi
+
+# ── report ────────────────────────────────────────────────────────────────────
+
+echo ""
+if [[ $ERRORS -eq 0 && $WARNINGS -eq 0 ]]; then
+ echo "✓ All checks passed."
+ exit 0
+elif [[ $ERRORS -eq 0 ]]; then
+ echo "Passed with $WARNINGS warning(s)."
+ exit 0
+else
+ echo "Failed. Fix $ERRORS error(s) before proceeding."
+ exit 1
+fi
diff --git a/.agents/skills/marketplace-architect/tests/test_scripts.sh b/.agents/skills/marketplace-architect/tests/test_scripts.sh
new file mode 100755
index 0000000..1045143
--- /dev/null
+++ b/.agents/skills/marketplace-architect/tests/test_scripts.sh
@@ -0,0 +1,194 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPTS_DIR="$(cd "$(dirname "$0")/../scripts" && pwd)"
+PASS=0; FAIL=0
+# Use += to avoid ((var++)) returning 0 exit code when var was 0 under set -e
+
+# ── helpers ─────────────────────────────────────────────────────────────────
+
+tmpdir() { mktemp -d; }
+
+assert_contains() {
+ local label="$1" expected="$2" actual="$3"
+ if echo "$actual" | grep -qF "$expected"; then
+ echo " PASS: $label"
+ PASS=$((PASS+1))
+ else
+ echo " FAIL: $label"
+ echo " expected to contain: $expected"
+ echo " got: $(echo "$actual" | head -5)"
+ FAIL=$((FAIL+1))
+ fi
+}
+
+assert_not_contains() {
+ local label="$1" unexpected="$2" actual="$3"
+ if echo "$actual" | grep -qF "$unexpected"; then
+ echo " FAIL: $label"
+ echo " expected NOT to contain: $unexpected"
+ FAIL=$((FAIL+1))
+ else
+ echo " PASS: $label"
+ PASS=$((PASS+1))
+ fi
+}
+
+assert_exit() {
+ local label="$1" expected="$2" actual="$3"
+ if [[ "$actual" -eq "$expected" ]]; then
+ echo " PASS: $label"
+ PASS=$((PASS+1))
+ else
+ echo " FAIL: $label"
+ echo " expected exit $expected, got $actual"
+ FAIL=$((FAIL+1))
+ fi
+}
+
+assert_file_exists() {
+ local label="$1" path="$2"
+ if [[ -f "$path" ]]; then
+ echo " PASS: $label"
+ PASS=$((PASS+1))
+ else
+ echo " FAIL: $label"
+ echo " file not found: $path"
+ FAIL=$((FAIL+1))
+ fi
+}
+
+assert_file_absent() {
+ local label="$1" path="$2"
+ if [[ ! -e "$path" ]]; then
+ echo " PASS: $label"
+ PASS=$((PASS+1))
+ else
+ echo " FAIL: $label"
+ echo " file should not exist: $path"
+ FAIL=$((FAIL+1))
+ fi
+}
+
+# ── inventory.sh tests ───────────────────────────────────────────────────────
+
+echo "=== inventory.sh ==="
+
+# 1. SKILL.md classified as skill
+t=$(tmpdir)
+mkdir -p "$t/skills/my-skill"
+echo "---" > "$t/skills/my-skill/SKILL.md"
+out=$("$SCRIPTS_DIR/inventory.sh" "$t")
+assert_contains "SKILL.md classified as skill" "skill" "$out"
+rm -rf "$t"
+
+# 2. agents/foo.agent.md classified as agent-copilot
+t=$(tmpdir)
+mkdir -p "$t/agents"
+touch "$t/agents/my-agent.agent.md"
+out=$("$SCRIPTS_DIR/inventory.sh" "$t")
+assert_contains "agents/*.agent.md classified as agent-copilot" "agent-copilot" "$out"
+rm -rf "$t"
+
+# 3. ../ in file content produces cross-reference warning
+t=$(tmpdir)
+mkdir -p "$t/skills/my-skill"
+printf -- '---\ndescription: test\n---\nSee ../shared/file.md\n' > "$t/skills/my-skill/SKILL.md"
+out=$("$SCRIPTS_DIR/inventory.sh" "$t")
+assert_contains "../ cross-reference warning emitted" "Cross-reference" "$out"
+assert_contains "../ path shown in warning" "../shared/file.md" "$out"
+rm -rf "$t"
+
+# ── gen_manifests.sh tests ───────────────────────────────────────────────────
+
+echo ""
+echo "=== gen_manifests.sh ==="
+
+# 4. Without --write, no files are created
+t=$(tmpdir)
+mkdir -p "$t/plugins/my-plugin/skills/hello"
+echo "---" > "$t/plugins/my-plugin/skills/hello/SKILL.md"
+"$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name my-marketplace >/dev/null
+assert_file_absent "dry run: .claude-plugin/marketplace.json not written" "$t/.claude-plugin/marketplace.json"
+assert_file_absent "dry run: plugin.json not written" "$t/plugins/my-plugin/plugin.json"
+rm -rf "$t"
+
+# 5. With --write, creates plugin.json in both locations
+t=$(tmpdir)
+mkdir -p "$t/plugins/my-plugin/skills/hello"
+echo "---" > "$t/plugins/my-plugin/skills/hello/SKILL.md"
+"$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name my-marketplace --write >/dev/null
+assert_file_exists "--write: plugin root plugin.json created" "$t/plugins/my-plugin/plugin.json"
+assert_file_exists "--write: .claude-plugin/plugin.json created" "$t/plugins/my-plugin/.claude-plugin/plugin.json"
+rm -rf "$t"
+
+# 6. Reserved name exits 1
+t=$(tmpdir)
+mkdir -p "$t/plugins/my-plugin"
+set +e
+out=$("$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name claude-plugins-official 2>&1)
+code=$?
+set -e
+assert_exit "reserved name: exit 1" 1 "$code"
+assert_contains "reserved name: error message" "reserved" "$out"
+rm -rf "$t"
+
+# ── validate.sh tests ────────────────────────────────────────────────────────
+
+echo ""
+echo "=== validate.sh ==="
+
+# 7. Invalid JSON exits 1
+t=$(tmpdir)
+mkdir -p "$t/.claude-plugin"
+echo "not json" > "$t/.claude-plugin/marketplace.json"
+set +e
+out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
+code=$?
+set -e
+assert_exit "invalid JSON: exit 1" 1 "$code"
+assert_contains "invalid JSON: error message" "ERROR" "$out"
+rm -rf "$t"
+
+# 8. Reserved marketplace name exits 1
+t=$(tmpdir)
+mkdir -p "$t/.claude-plugin"
+printf '{"name":"claude-plugins-official","plugins":[]}\n' > "$t/.claude-plugin/marketplace.json"
+set +e
+out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
+code=$?
+set -e
+assert_exit "reserved marketplace name: exit 1" 1 "$code"
+assert_contains "reserved marketplace name: error message" "reserved" "$out"
+rm -rf "$t"
+
+# 9. ../ in plugin file exits 1
+t=$(tmpdir)
+mkdir -p "$t/.claude-plugin" "$t/plugins/my-plugin/skills/hello"
+printf '{"name":"my-marketplace","plugins":[{"name":"my-plugin","source":"./plugins/my-plugin"}]}\n' \
+ > "$t/.claude-plugin/marketplace.json"
+printf -- '---\ndescription: test\n---\nSee ../shared.md\n' \
+ > "$t/plugins/my-plugin/skills/hello/SKILL.md"
+set +e
+out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
+code=$?
+set -e
+assert_exit "..// in plugin: exit 1" 1 "$code"
+assert_contains "..// in plugin: error message" "../" "$out"
+rm -rf "$t"
+
+# 10. No marketplace.json warns but exits 0
+t=$(tmpdir)
+set +e
+out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
+code=$?
+set -e
+assert_exit "no marketplace.json: exit 0" 0 "$code"
+assert_contains "no marketplace.json: warning emitted" "WARN" "$out"
+rm -rf "$t"
+
+# ── summary ──────────────────────────────────────────────────────────────────
+
+echo ""
+echo "Results: $PASS passed, $FAIL failed"
+[[ $FAIL -eq 0 ]]
diff --git a/.agents/skills/write-skill/CATEGORIES.md b/.agents/skills/write-skill/CATEGORIES.md
index aa9339b..2efefdd 100644
--- a/.agents/skills/write-skill/CATEGORIES.md
+++ b/.agents/skills/write-skill/CATEGORIES.md
@@ -12,4 +12,5 @@
| `iac` | write-ansible-role, write-terraform-module, write-k8s-manifest, write-docker-compose, proxmox-vm-spec, iac-security-review, write-molecule-test |
| `cross-cutting` | zoom-out, caveman, session-handoff, governance-check, git-guardrails, git-commit-message |
| `factory` | write-skill, write-adr, write-workflow, write-eval, validate-skill, upgrade-skill, write-issue-spec |
+| `marketplace` | marketplace-architect — plugin and skill distribution tooling for Claude Code / GitHub Copilot CLI |
| `roles` | architect, developer, reviewer, security, qa, ops — Chunk 5 |
diff --git a/docs/research/plugin-marketplace-architecture.md b/docs/research/plugin-marketplace-architecture.md
new file mode 100644
index 0000000..95b130a
--- /dev/null
+++ b/docs/research/plugin-marketplace-architecture.md
@@ -0,0 +1,334 @@
+# Plugin Marketplace Architecture
+
+Reference for refactoring this repo of skills/agents/hooks/prompts into a single Git-based
+plugin marketplace installable by **Claude Code** and **GitHub Copilot CLI**, and for building
+the `marketplace-architect` skill that automates the migration.
+
+> **Provenance & staleness:** Verified against the official Claude Code plugin docs
+> (`code.claude.com/docs`) and GitHub Copilot CLI plugin docs (`docs.github.com`) as of
+> **June 2026**. Both ecosystems are moving fast; re-verify the divergence table before a
+> big migration. One item below (Copilot reading `.claude-plugin/plugin.json` per-plugin) is
+> **explicitly unverified** — see the flagged note. Don't treat that part as settled.
+
+---
+
+## 1. Core model (this part is correct and stable)
+
+- The **Git repository is the marketplace.** No backend, registry API, database, SaaS, or MCP
+ server is required. A marketplace is just a manifest file that lists plugins and where to find them.
+- A **plugin is the deployable unit.** Each plugin bundles one or more of: skills, agents, hooks,
+ prompts/commands (flat `.md`), MCP servers, and — Claude Code only — output styles, LSP servers,
+ background monitors, a `bin/` on PATH, and default `settings.json`. "Workflows" from the handoff
+ aren't a distinct file type; express them as a skill that orchestrates steps, or a command.
+- **Organize by user outcome, not file type.** `startup-cto/` and `security-reviewer/`, not
+ `all-skills/` and `all-agents/`.
+- **Aim for ~10–20 opinionated plugins**, not 50 tiny ones. (This is a usability judgment, not a
+ hard rule from either vendor — but it's sound. Many skills can live inside one plugin.) The
+ handoff's suggested set, as a starting shape: `startup-cto`, `system-architect`,
+ `security-reviewer`, `product-manager`, `growth-marketer`, `developer-relations`,
+ `technical-writer`, `research-analyst`.
+
+Everything below is where the original handoff was either wrong or incomplete.
+
+---
+
+## 2. The two tools are convergent, NOT identical
+
+This is the single most important correction. The handoff assumed "write once, run both."
+In reality the formats overlap heavily but diverge in specific, breaking ways. **Skills are the
+portable core; manifests and agents are where they split.**
+
+**Recommended stance:** make **Claude Code the source of truth** (it's the stricter, more
+fully-specified format) and treat "loads in Copilot CLI" as a **tested checklist item per plugin**,
+not an assumption. Encode the Copilot deltas (manifest location, `.agent.md` naming) explicitly in
+the architect skill rather than pretending the two are the same. This is more honest than "write
+once, run both" and stops surprises at install time.
+
+### Divergence table (ground truth)
+
+| Concern | Claude Code | GitHub Copilot CLI | Portable choice |
+|---|---|---|---|
+| Marketplace manifest path | `.claude-plugin/marketplace.json` (required) | `.github/plugin/marketplace.json` (primary); **also reads `.claude-plugin/`** | Put it in `.claude-plugin/` — both read it. Optionally also `.github/plugin/`. |
+| Plugin manifest path | `.claude-plugin/plugin.json` (required; **only** plugin.json goes in this dir) | `plugin.json` at **plugin root** | ⚠️ See flagged note — may need it in **both** locations |
+| Skills | `skills//SKILL.md` | `skills//SKILL.md` | ✅ Identical — lean on these |
+| Agents | `agents/.md` | `agents/.agent.md` (frontmatter incl. `tools:`) | Diverges — keep portable logic in skills; ship per-tool agent files only when needed |
+| Hooks | `hooks/hooks.json` | `hooks.json` at plugin root | Diverges; declare paths in manifest to be safe |
+| MCP servers | `.mcp.json` at plugin root | `.mcp.json` at plugin root | ✅ Same |
+| Relative `source` | must start with `./` | `./x` and `x` both valid | Always use `./` — valid for both |
+| Validate command | `claude plugin validate .` (or `/plugin validate .`) | none documented | Claude validator + custom JSON checks for Copilot |
+| Install marketplace | `claude plugin marketplace add owner/repo` | `copilot plugin marketplace add owner/repo` | Same shape |
+| Install plugin | `claude plugin install @` | from a registered marketplace by plugin name; **`@marketplace` suffix not confirmed** — `update`/`uninstall` take a bare ``, so don't assume Claude's `@marketplace` form | ⚠️ Verify the Copilot install string before documenting it |
+| Local install (dev) | `claude --plugin-dir ./plugin` | `copilot plugin install ./plugin` | Tool-specific |
+
+> ⚠️ **FLAGGED / UNVERIFIED — test this by hand before committing to a layout.**
+> Copilot's docs explicitly confirm it falls back to reading the **marketplace** manifest from
+> `.claude-plugin/`. They do **not** confirm the same fallback for an individual plugin's
+> `plugin.json`; the Copilot docs only show `plugin.json` at the plugin root. Claude *requires*
+> it in `.claude-plugin/`. Until you verify, the pragmatic move is to **ship `plugin.json` in
+> both** `plugin-name/plugin.json` and `plugin-name/.claude-plugin/plugin.json` (identical
+> content), then drop whichever proves redundant. The architect skill should generate both and
+> note the duplication.
+
+### `@` resolves to the manifest `name`, not the repo
+
+`claude plugin install startup-cto@my-ai-marketplace` requires the marketplace manifest's
+top-level `name` field to be exactly `my-ai-marketplace`. It is **not** the GitHub repo name.
+Keep them aligned to avoid confusion, but know they're separate things.
+
+---
+
+## 3. Canonical repo layout (cross-compatible)
+
+```text
+repo-root/
+├── .claude-plugin/
+│ └── marketplace.json # both tools read here
+├── .github/plugin/
+│ └── marketplace.json # OPTIONAL: Copilot's canonical path (mirror of above)
+├── plugins/
+│ └── startup-cto/
+│ ├── plugin.json # Copilot root manifest ┐ ship both until
+│ ├── .claude-plugin/ # │ the §2 note is
+│ │ └── plugin.json # Claude manifest ┘ verified
+│ ├── skills/
+│ │ ├── fundraising/SKILL.md
+│ │ └── hiring/SKILL.md
+│ ├── agents/
+│ │ ├── startup-cto.md # Claude
+│ │ └── startup-cto.agent.md # Copilot (only if you ship native agents)
+│ ├── hooks/hooks.json # Claude
+│ ├── hooks.json # Copilot (if hooks used)
+│ ├── docs/
+│ └── README.md
+└── README.md
+```
+
+If maintaining two manifest copies is annoying, generate the mirrors from one source in CI
+(see §7) rather than hand-editing both.
+
+### Manifest shapes
+
+`marketplace.json` (root):
+
+```json
+{
+ "name": "my-ai-marketplace",
+ "owner": { "name": "Your Name", "email": "you@example.com" },
+ "metadata": { "description": "Agents, skills and workflows", "version": "1.0.0" },
+ "plugins": [
+ { "name": "startup-cto", "source": "./plugins/startup-cto", "description": "..." },
+ { "name": "system-architect", "source": "./plugins/system-architect", "description": "..." }
+ ]
+}
+```
+
+`plugin.json` (keep minimal; add fields only when needed):
+
+```json
+{
+ "name": "startup-cto",
+ "version": "1.0.0",
+ "description": "Startup technical leadership toolkit",
+ "author": { "name": "Your Name" }
+}
+```
+
+Plugin names must be **kebab-case** (lowercase, digits, hyphens). Claude.ai's marketplace sync
+rejects anything else even though the local CLI may tolerate it.
+
+---
+
+## 4. Gotchas the original handoff omitted
+
+These will cause real breakage during refactor. The architect skill must check for them.
+
+1. **Plugins are copied to a cache on install.** A plugin **cannot** reference files outside its
+ own directory (e.g. `../shared-utils`) — those files aren't copied. If your current repo shares
+ helper files across skills/agents, that sharing breaks. Fix by **duplicating** the shared file
+ into each plugin or using **symlinks**. Audit for cross-references before moving anything.
+
+2. **Version-pinning footgun.** If `plugin.json` sets `"version"` and you don't bump it on a new
+ release, existing users get **no update** — the cached copy is kept. Either bump every release,
+ or **omit `version`** so the git commit SHA is used (every commit = new version). Don't set
+ `version` in both `plugin.json` and the marketplace entry; the `plugin.json` value wins silently.
+
+3. **Reserved marketplace names.** Claude blocks a set of names (`anthropic-*`, `claude-*`,
+ `agent-skills`, and impersonators like `official-claude-plugins`). Validate against these.
+
+4. **`commands/` ≠ `skills/` in Claude.** A flat `foo.md` is a legacy *command*; a
+ `foo/SKILL.md` directory is a *skill*. Promote flat command files to skill directories during
+ migration — don't treat them as interchangeable.
+
+5. **Use `${CLAUDE_PLUGIN_ROOT}`** in Claude hook/MCP configs to reference in-plugin files, since
+ the plugin runs from a cache path, not its repo location.
+
+6. **Strict mode (Claude).** A marketplace plugin entry defaults to `strict: true` — `plugin.json`
+ is authoritative and the entry can only supplement it. Set `strict: false` to make the
+ marketplace entry the *entire* definition (it then declares `skills`/`agents`/`hooks`/`mcpServers`
+ path arrays itself, and the plugin needs no `plugin.json`). Useful when the architect curates a
+ plugin's exposed components differently from how the files are laid out. Don't mix the two — a
+ `strict:false` entry plus a component-declaring `plugin.json` is a conflict and fails to load.
+
+7. **Plugin sources beyond relative paths (Claude).** This repo uses `./plugins/x` relative sources
+ (simplest for a monorepo). If you later split a plugin into its own repo, the `source` field also
+ supports `github` (`owner/repo` + `ref`/`sha`), `git-subdir` (sparse clone of a monorepo path),
+ `url` (any git host), and `npm` (published package). Copilot's docs only *show* relative-path
+ sources — other source types aren't documented there, so don't rely on them cross-tool. Stay on
+ relative paths unless you have a reason not to.
+
+8. **Copilot declares component paths in `plugin.json` (Claude does it differently).** Copilot's
+ `plugin.json` can carry `"skills": "skills/"`, `"agents": "agents/"`, `"hooks": "hooks.json"`,
+ `"mcpServers": ".mcp.json"` fields that tell it where components live. Claude instead defaults to
+ the standard dirs and only takes path overrides via the *marketplace entry* (see strict mode,
+ #6). So the same `plugin.json` may need these path fields for Copilot but not for Claude — another
+ reason the architect should generate per-tool manifests rather than one shared file.
+
+---
+
+## 5. The `marketplace-architect` skill spec
+
+Build this skill **on the corrected spec above** — not on the original handoff, which would bake
+in the format errors. It's a Claude Code skill (`skills/marketplace-architect/SKILL.md`) following
+standard skill conventions: a tight SKILL.md body (<500 lines) plus bundled `references/` and
+`scripts/` loaded progressively.
+
+### Frontmatter (description is the trigger — make it pushy)
+
+```yaml
+---
+name: marketplace-architect
+description: >
+ Audits a repository of Claude Code / Copilot CLI skills, agents, hooks, and prompts and
+ refactors it into an installable plugin marketplace. Use this whenever the user wants to
+ organize loose skills/agents into plugins, define plugin boundaries, generate plugin.json
+ or marketplace.json manifests, plan a migration to a plugin marketplace, validate plugin
+ naming or detect duplicate capabilities, or set up cross-tool (Claude Code + GitHub Copilot
+ CLI) distribution — even if they don't say the word "marketplace".
+---
+```
+
+### Responsibilities (from the handoff, refined)
+
+1. **Audit** — walk the repo; classify every asset as skill / command / agent / hook / prompt / MCP.
+2. **Detect cross-references** — flag any `../` or shared-file dependencies that break under caching (§4.1).
+3. **Recommend plugin boundaries** — group by outcome; warn on 50-tiny-plugins sprawl.
+4. **Prevent duplicate capabilities** — diff skill descriptions/agents for overlap before splitting.
+5. **Generate manifests** — emit `plugin.json` (both locations per §2 note) and `marketplace.json`
+ (`.claude-plugin/`, optionally mirror to `.github/plugin/`).
+6. **Validate naming** — kebab-case, reserved names, unique plugin names, `@name` ↔ manifest `name`.
+7. **Produce a migration plan** — concrete file-move list (old path → new path) as a checklist.
+8. **Emit cross-tool deltas** — for each plugin, note what's needed for Copilot (`.agent.md`,
+ root `plugin.json`) vs Claude.
+9. **Generate release notes + install docs** — per-plugin README with both `claude` and `copilot`
+ install commands.
+
+### Suggested bundled structure
+
+```text
+skills/marketplace-architect/
+├── SKILL.md
+├── references/
+│ ├── claude-code.md # Claude paths, validate, version rules, reserved names
+│ ├── copilot-cli.md # Copilot paths, .agent.md, marketplace fallback
+│ └── cross-compat.md # the §2 divergence table — the heart of the skill
+└── scripts/
+ ├── inventory.py # scan repo → classify assets → emit a table
+ ├── gen_manifests.py # write plugin.json + marketplace.json (both layouts)
+ └── validate.py # wraps `claude plugin validate .` + JSON/naming checks
+```
+
+Put the §2 divergence table verbatim into `references/cross-compat.md` — that's the knowledge the
+skill exists to apply. Keep SKILL.md to the workflow (audit → boundaries → generate → validate)
+and point it at the reference files.
+
+### Authoring notes
+
+- Use **imperative** instructions ("Scan the repo", "Emit the manifest").
+- Explain *why* a rule matters (e.g. the cache constraint) rather than bare MUSTs — the model
+ applies judgment better with rationale.
+- After drafting, run 2–3 realistic test prompts (e.g. "turn this repo into a marketplace",
+ "which of these skills belong together?") and iterate.
+
+---
+
+## 6. Refactor playbook (corrected phases)
+
+Run these *with* the architect skill once it exists; it automates 1–5.
+
+1. **Inventory.** Classify every asset (skill/command/agent/hook/prompt/MCP). Record current path.
+2. **Detect breakage.** Find cross-references and shared files (§4.1). Decide duplicate vs symlink.
+3. **Draw boundaries.** Group by outcome into ~10–20 plugins. De-dupe overlapping capabilities.
+4. **Move files.**
+ - `skills/react.md` (flat command) → `plugins/system-architect/skills/react/SKILL.md`
+ - `agents/startup-founder.md` → `plugins/startup-cto/agents/startup-founder.md`
+ (+ `startup-founder.agent.md` if shipping Copilot-native agents)
+5. **Generate manifests.** Per-plugin `plugin.json` (both locations); root `marketplace.json`.
+6. **Validate.** `claude plugin validate .` — fix every warning. Then test-install in both tools:
+ - `claude --plugin-dir ./plugins/` then `/plugin install @`
+ - `copilot plugin install ./plugins/` then `copilot plugin list` / `/skills list` / `/agent`
+7. **Document.** Per-plugin README with both install commands; root README listing all plugins.
+
+---
+
+## 7. Future / roadmap (preserved from the handoff)
+
+Three post-migration features the original handoff called for. Not needed for the first cut, but
+recorded here so the intent isn't lost.
+
+### Marketplace website
+
+Generate a docs site **directly from `marketplace.json`** — no separate content source. Iterate
+over the `plugins` array to produce a browsable catalog (one page per plugin from its
+`description`/`README.md`), publishable to something like `marketplace.example.com` via GitHub
+Pages. Because the manifest is the single source of truth, the site never drifts from what's
+installable.
+
+### Plugin templates
+
+Add a `templates/` directory so contributors never start from scratch:
+
+```text
+templates/
+ skill-plugin/ # plugin.json + skills//SKILL.md skeleton
+ agent-plugin/ # plugin.json + agents/ skeleton (both .md and .agent.md)
+ workflow-plugin/ # plugin.json + a multi-step orchestration skill
+```
+
+Each ships the dual-manifest layout from §3 so new plugins are cross-tool by default.
+
+### CI validation (the cross-tool catch)
+
+A GitHub Action can gate PRs, but remember: **`claude plugin validate` covers the Claude side
+only.** There's no Copilot validator, so the Action needs custom JSON checks for the Copilot
+layout. Minimum checks:
+
+- Valid JSON in every `marketplace.json` / `plugin.json`.
+- Each plugin's `SKILL.md` files have valid YAML frontmatter.
+- Unique plugin names; kebab-case; no reserved names.
+- Every `source` path resolves to an existing directory.
+- (If mirroring) `.claude-plugin/` and `.github/plugin/` manifests are in sync.
+- Version consistency (no conflicting `version` in plugin.json vs marketplace entry).
+
+Fail the PR on any violation so the contributor flow stays self-service.
+
+### Success criteria (the target end-state)
+
+A new contributor should be able to, with **no manual registry edits, no backend, no MCP
+dependency**: (1) fork the repo, (2) create a plugin folder, (3) add `plugin.json`, (4) add
+skills/agents, (5) open a PR, (6) have the plugin appear in the marketplace automatically once
+merged. If a step requires hand-editing a central list, the automation isn't done.
+
+---
+
+## Open questions to resolve first
+
+Two facts couldn't be confirmed from the published docs. Settle both with a one-skill test plugin
+before the architect generates layouts:
+
+1. **Does Copilot CLI load a plugin whose `plugin.json` lives only in `.claude-plugin/`?** (Install
+ the test plugin both ways.) The answer decides whether you ship one manifest or two. Copilot's
+ docs put `plugin.json` at the plugin root; Claude requires `.claude-plugin/`.
+2. **What is Copilot's exact install-from-marketplace command?** The how-to pages don't show the
+ literal string, and Copilot's `update`/`uninstall` take a bare plugin name — so it may *not* use
+ Claude's `@` form. Run `copilot plugin install --help` and confirm before
+ putting the command in any README or the architect's generated docs.