Skip to content

feat: unify skills + plugins into a multi-agent marketplace#23

Open
sidneyswift wants to merge 12 commits into
mainfrom
feat/unified-marketplace
Open

feat: unify skills + plugins into a multi-agent marketplace#23
sidneyswift wants to merge 12 commits into
mainfrom
feat/unified-marketplace

Conversation

@sidneyswift
Copy link
Copy Markdown
Contributor

@sidneyswift sidneyswift commented May 12, 2026

Summary

Consolidates three previously-separate repos (recoupable/skills, recoupable/plugins, recoupable/music-catalog-diligence) into a single multi-agent marketplace + plugin host. After this lands, customers add ONE marketplace and install whichever plugins they need; Claude Code, Codex, and Cursor all work from the same source.

Four logical changes, one cohesive shipment:

  1. Marketplace unificationmarketplace.source.json is the single source of truth. A zero-dependency Python generator (scripts/generate-marketplaces.py) produces the three platform marketplace files (.claude-plugin/, .agents/plugins/, .cursor-plugin/) on every change. CI runs a validator (scripts/validate-manifests.py) on every PR that checks marketplace parity, plugin source paths, plugin manifests, and every SKILL.md frontmatter.
  2. Catalog plugin merged via git subtreeplugins/music-catalog-diligence/ brings in the full standalone catalog plugin with history preserved (commit a95f3dc). 9 catalog skills + 5 specialist agents + 6 slash commands + scripts + templates + evals + fixtures, all in-tree.
  3. getting-started becomes an onboarding orchestrator — was a one-shot CLI install doc, is now a 5-step orchestrator: detects environment + auth state, installs CLI/key only when needed, identifies the account via /api/whoami, fetches roster (orgs + artists), inspects scaffold state, then routes to create-artist / setup-sandbox / artist-workspace based on the detected state vector. Handles both target user journeys: BYOA via developers.recoupable.com (paste-prompt onboarding) and Recoup-hosted via chat.recoupable.com (injected-token sandbox).
  4. recoupablerecoup rename across marketplace + plugin identifiers and display names. Repo path stays recoupable/skills. Real URLs (recoupable.com, agent@recoupable.com) and the legal entity in LICENSE stay unchanged. Install commands become /plugin install recoup-skills@recoup and /plugin install music-catalog-diligence@recoup.

After merging:

# Claude Code
/plugin marketplace add recoupable/skills
/plugin install recoup-skills@recoup
/plugin install music-catalog-diligence@recoup

# Codex
codex plugin marketplace add recoupable/skills
codex plugin install recoup-skills@recoup
codex plugin install music-catalog-diligence@recoup

# Cursor — adds `recoupable/skills` as a plugin marketplace source

# Vercel skills CLI (works in 18+ agents) — `npx skills add recoupable/skills`

What's deliberately NOT in this PR

These are real follow-ups, scoped to separate branches/PRs after this lands. Documented in SCRATCHPAD.md at the mono root.

  • Update mono/tasks/src/sandboxes/installSkills.ts to scope sandbox installs to broad skills only via --skill <comma-list> from marketplace.source.json. Verified earlier: npx skills add recoupable/skills discovers all 21 skills (12 broad + 9 catalog) by default. Without scoping, customer sandboxes would silently install catalog skill descriptions whose Python runtime isn't in the sandbox.
  • Archive recoupable/plugins and recoupable/music-catalog-diligence once consumers are migrated.
  • Drop the plugins submodule from mono/.gitmodules after Open Agents migration.
  • Catalog plugin scripts → MCP tools migration as customer demand validates each (long-term, driven by API endpoint cleanup).
  • Adaptive methodology layer (ETHOS, detection utility, Layer 1 primitives, customer-profile skill) — separate branch, multi-week design iteration. See SCRATCHPAD.md Parts VIII-XI for full plan.

Test plan

  • python3 scripts/generate-marketplaces.py --check — exits 0, generated files match source
  • python3 scripts/validate-manifests.py — exits 0, all 21 SKILL.md files pass frontmatter validation, all plugin paths resolve, all marketplace JSONs in sync
  • npx skills add 'https://github.com/recoupable/skills.git#feat/unified-marketplace' --list — finds all 21 skills as expected
  • npx skills add ... --all --copy — installs all 21 SKILL.md files into .agents/skills/{name}/
  • (post-merge) Open Claude Code, run /plugin marketplace add recoupable/skills, verify both plugins are discoverable
  • (post-merge) Run /plugin install recoup-skills@recoup in Claude Code, verify all 12 broad skills load
  • (post-merge) Run /plugin install music-catalog-diligence@recoup in Claude Code, verify catalog plugin loads with skills + agents + commands
  • (post-merge) Validate that developers.recoupable.com "getting started" prompt successfully runs /getting-started and routes to create-artist for a fresh account

Files

  • marketplace.source.json — single source of truth (edit this; regenerate)
  • scripts/generate-marketplaces.py — regenerate the three platform marketplace files
  • scripts/validate-manifests.py — CI validator
  • .github/workflows/validate.yml — runs validator on every PR
  • .claude-plugin/marketplace.json, .agents/plugins/marketplace.json, .cursor-plugin/marketplace.json — generated, do not edit
  • skills/ — 12 broad music skills (existing + the new create-artist from prior PR)
  • plugins/music-catalog-diligence/ — full catalog plugin (skills + agents + commands + scripts + templates + evals + fixtures)
  • skills/getting-started/SKILL.md — rewritten as 5-step orchestrator
  • README.md, AGENTS.md, contributing.md, CHANGELOG.md — rewritten for the unified model

Why the recoupable/skills repo path stays unchanged

GitHub repo paths are real-world references (CLI installers, npm cache keys, customer bookmarks). Renaming would break every existing consumer. Only the marketplace and plugin identifiers are renamed — what users type into install commands.

Made with Cursor


Summary by cubic

Unifies skills and plugins into a single multi‑agent marketplace with generated manifests for Claude Code, Codex, and Cursor. Adds the music-catalog-diligence plugin, a guided onboarding flow, CI validation, and follow‑up hardening across diligence scripts and guardrails.

  • New Features

    • Single source of truth marketplace.source.json with generator scripts/generate-marketplaces.py and CI validator scripts/validate-manifests.py; produces .claude-plugin/marketplace.json, .agents/plugins/marketplace.json, .cursor-plugin/marketplace.json.
    • New plugins/music-catalog-diligence/ plugin with skills, agents, commands, scripts, fixtures, tests, and guardrails (PreToolUse to protect deals/*/source/, Stop hook for QC).
    • skills/getting-started becomes a 5‑step onboarding orchestrator that detects env/auth and routes to create-artist, setup-sandbox, or artist-workspace.
    • Marketplace and plugin identifiers renamed to recoup (e.g., recoup-skills@recoup); repo path and recoupable.com URLs unchanged.
  • Bug Fixes

    • Guardrails and validation: PreToolUse deny glob now blocks relative/dot‑relative/absolute writes into deals/*/source/; manifest validator enforces a .cursor-plugin/plugin.json on each plugin; normalized ledger validator flags blank ledger_line_id.
    • Diligence script hardening: monetary math in calculate-nps-nls-bridge.py uses Decimal and rejects bad inputs; extract-pdf-statement.py fails fast and reports partial status on errors; normalize-royalty-statement.py treats zero‑row outputs as partial.
    • Evidence and workspace checks: validate-evidence-ledger.py requires object top‑level and string evidence_ids; validate-deal-workspace.py handles unreadable files without crashing; findings/evidence and workspace consistency validators tightened.
    • Auth/docs/deps: getting-started now validates cached account_id against the current token; fixed docs and command args; pinned pillow>=12.2.0 in requirements.txt.

Written for commit 32d7f76. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added a Recoup marketplace and two plugins (recoup-skills + music-catalog-diligence) with installable skills, tooling, hooks, and end-to-end diligence workflows.
  • Documentation

    • Overhauled README, AGENTS, contributing, changelog and extensive plugin docs, templates, runbooks, evals, and skill guides for ingestion, analysis, valuation, QC, and workflows.
  • Chores

    • Added marketplace generator and manifest validator; CI workflow to validate manifests.
  • Tests

    • Added comprehensive unit/integration tests and evaluation scenarios for plugin scripts and skills.

sidneyswift and others added 9 commits April 29, 2026 00:36
Made-with: Cursor
Adds the full music catalog deal review plugin foundation with diligence
workflows, commands, specialist agents, validation scripts, templates, evals,
and test-backed royalty normalization fixtures.

Verification:
- python3 scripts/test-normalize-royalty-statement.py
- python3 scripts/test-golden-fixtures.py
- JSON validation for plugin manifests, templates, and eval fixtures
- script --help checks for every Python script
- validate-normalized-ledger.py for all expected fixture ledgers
- Neon River synthetic data room smoke test: 3,188 normalized rows

Made-with: Cursor
Improve deal-readiness reliability with full provider fixture coverage, stronger workspace validation, readiness checks, dashboard output, structured QC, Cursor support, and expanded diligence evals.

Made-with: Cursor
Replaces the SPDX shorthand license file with the full Apache 2.0 text for a
clearer public plugin submission package.

Verification:
- claude plugin validate .
- python3 scripts/test-normalize-royalty-statement.py
- python3 scripts/test-golden-fixtures.py
- python3 scripts/test-validate-deal-workspace.py
- python3 scripts/test-diligence-readiness.py

Made-with: Cursor
…guardrails

Add new ingest automation scripts (manual-review queue, dataroom hygiene
scan, PDF statement extractor, findings/evidence validator, workspace
consistency validator) plus a shared `_helpers.py` module and
unit tests for each.

Wire the new validators into `run-diligence-checks.py` so the readiness
check covers findings-to-evidence traceability and cross-artifact
consistency. Extend `normalize-royalty-statement.py`, `build-file-manifest.py`,
`calculate-concentration.py`, and `build-diligence-dashboard.py` with
provider classification, parse-status hints, threshold-driven concentration
findings, and richer dashboards. Add a BMI real-headers golden fixture
and update the golden test runner.

Introduce hooks: a `PreToolUse` script that denies writes into
`deals/{deal-id}/source/` (immutable evidence) and a prompt-based `Stop`
hook that gates completion claims against the deal-workspace checklist
in references/deal-workspace.md.

Document hooks in the README, point the catalog-ingest skill and command
at the new scripts, refresh red-flags references and the QC reviewer
agent, and add `requirements.txt` for the optional pdfplumber/openpyxl
extractors. Add `.gitignore` to keep Python bytecode out of the repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
…95c90f0cda9685554ea085c'

git-subtree-dir: plugins/music-catalog-diligence
git-subtree-mainline: 7993be6
git-subtree-split: a95f3dc
…place

Convert recoupable/skills into the single discoverable home for all Recoupable
agent skills and plugins. The repo now ships:

- A platform marketplace for Claude Code, Codex, and Cursor (three generated
  marketplace.json files at the repo root) listing every installable plugin.
- A virtual `recoupable-skills` plugin over the existing 12 broad music skills
  under `skills/` (Anthropic `anthropics/skills` pattern).
- A self-contained `music-catalog-diligence` plugin under
  `plugins/music-catalog-diligence/` merged in via git subtree with full
  history preserved (Anthropic `claude-plugins-official` pattern).
- A single `marketplace.source.json` source-of-truth plus
  `scripts/generate-marketplaces.py` so the three platform files never drift.
- `scripts/validate-manifests.py` and a GitHub Actions workflow that runs it
  on every PR — validates marketplace parity, plugin paths, plugin manifests,
  and every SKILL.md frontmatter.

After this lands, users add one marketplace and choose which plugin to install:

    /plugin marketplace add recoupable/skills
    /plugin install recoupable-skills@recoupable
    /plugin install music-catalog-diligence@recoupable

Legacy root `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json` are
removed; they are superseded by the `recoupable-skills` virtual plugin entry
in the marketplace. No skill paths under `skills/` changed, so existing
manual-clone consumers keep working.

Follow-up work (separate PRs):
- Archive `recoupable/plugins` and `recoupable/music-catalog-diligence`.
- Update mono/.gitmodules to drop the `plugins` submodule.
- Update sandbox/Trigger.dev installers to point at recoupable/skills.

Co-authored-by: Cursor <cursoragent@cursor.com>
…etection + skill routing

The skill now drives a 5-step flow:

  Step 0  Detect environment + auth state (env vars + CLI + filesystem)
  Step 1  Install CLI (BYOA only, skipped if already installed)
  Step 2  Get an API key (BYOA only, skipped if RECOUP_API_KEY/ACCESS_TOKEN set)
  Step 3  Verify auth + identify the account via /api/whoami
  Step 4  Detect roster + filesystem state (orgs, artists, scaffold)
  Step 5  Route to the right next skill based on the detected state

This handles both target user journeys end-to-end:

- BYOA from developers.recoupable.com: user pastes a getting-started prompt,
  agent runs Step 0-5 in sequence — installs CLI, creates an account, detects
  state, and routes to the right follow-up skill (create-artist for empty
  rosters, artist-workspace for established ones, setup-sandbox when the
  workspace tree is missing).
- Recoup-hosted on chat.recoupable.com: RECOUP_ACCESS_TOKEN is already
  injected, so the skill skips install/auth and goes straight to state
  detection + routing.

Also adds a throwaway-account warning (per the create-artist skill's caveat
about agent+ emails) and a routing table that picks between create-artist,
setup-sandbox, and artist-workspace based on the (orgs, artists, filesystem)
state vector.

No env vars or endpoints invented — uses the same `RECOUP_API_KEY` /
`RECOUP_ACCESS_TOKEN` / `RECOUP_ACCOUNT_ID` / `RECOUP_ORG_ID` already
documented in `recoup-api` and `setup-sandbox` skills, and the same
`/api/whoami`, `/api/organizations`, and `/api/organizations/{id}/artists`
endpoints used elsewhere.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ble" to "recoup"

Renames the brand inside our agent surface — what users type into install
commands and what's displayed in plugin manifests — from "recoupable" to the
shorter "recoup". Same product, cleaner identifier.

Renamed (identifiers + display names):

- Marketplace name:  `recoupable` → `recoup`
- Plugin name:       `recoupable-skills` → `recoup-skills`
- Display names:     "Recoupable Skills" → "Recoup Skills", developerName "Recoupable" → "Recoup"
- Owner/author name: "Recoupable" → "Recoup" (in marketplace.source.json + catalog plugin manifests)
- Install paths:     `@recoupable` → `@recoup`
- MCP server key:    `"recoupable":` → `"recoup":` (in getting-started skill's MCP config snippet)
- Brand references in skill bodies + README/AGENTS/CHANGELOG/contributing.md: "Recoupable" → "Recoup"

Intentionally NOT renamed (real-world resources that can't just rebrand):

- All `recoupable.com` URLs (recoupable.com, chat.recoupable.com, developers.recoupable.com, api.recoupable.com)
- Email address `agent@recoupable.com` (real account, real `agent+*@...` signup pattern)
- GitHub repo paths `recoupable/skills`, `recoupable/music-catalog-diligence`, `recoupable/plugins`
- NPM package `@recoupable/cli`
- LICENSE legal entity `Copyright 2026 Recoupable Inc.`

After this change, users install with:

  /plugin marketplace add recoupable/skills        # repo path unchanged
  /plugin install recoup-skills@recoup             # new identifier branding
  /plugin install music-catalog-diligence@recoup

Regenerated all three platform marketplace JSONs from marketplace.source.json.
Validator passes (`python3 scripts/validate-manifests.py`).

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

📝 Walkthrough

Walkthrough

This PR creates a unified "Recoup" skills marketplace (source: marketplace.source.json) with generation/validation tooling, CI checks, and generated platform manifests; introduces a new self-contained plugin music-catalog-diligence (manifests, skills, agents, commands, hooks, scripts, templates, tests, fixtures, docs); and updates repository docs/branding and numerous skill frontmatter/installation instructions.

Changes

Marketplace Platform Infrastructure

Layer / File(s) Summary
Marketplace source and generation
marketplace.source.json, scripts/generate-marketplaces.py, .agents/plugins/marketplace.json, .claude-plugin/marketplace.json, .cursor-plugin/marketplace.json, .codex-plugin/marketplace.json
Adds marketplace.source.json as the single source-of-truth and a stdlib Python generator scripts/generate-marketplaces.py that emits platform-specific marketplace manifests for Claude/Codex/Cursor and supports a --check mode to detect stale generated files.
Manifest validation and CI integration
scripts/validate-manifests.py, .github/workflows/validate.yml
Adds scripts/validate-manifests.py to verify generator sync, plugin directory structure, required plugin manifests, and SKILL.md frontmatter (name & description). Adds GitHub Actions workflow .github/workflows/validate.yml to run generation-check and manifest validation on pushes to main and on PRs.

Music Catalog Diligence Plugin

Layer / File(s) Summary
Plugin metadata and packaging
plugins/music-catalog-diligence/.claude-plugin/plugin.json, plugins/music-catalog-diligence/.codex-plugin/plugin.json, plugins/music-catalog-diligence/.cursor-plugin/plugin.json, plugins/music-catalog-diligence/.gitignore, plugins/music-catalog-diligence/LICENSE, plugins/music-catalog-diligence/requirements.txt
Adds platform manifests, .gitignore, Apache-2.0 license, and optional Python deps (pdfplumber, openpyxl) for the music-catalog-diligence plugin.
Plugin documentation and references
plugins/music-catalog-diligence/README.md, plugins/music-catalog-diligence/references/*
Adds comprehensive plugin README and reference docs (deal-workspace, diligence workflow, normalization, red-flags, tooling landscape, etc.).
Skills and evals
plugins/music-catalog-diligence/skills/*/SKILL.md, plugins/music-catalog-diligence/skills/*/evals/evals.json
Introduces multiple skills (catalog-ingest, catalog-analysis, diligence-kickoff, royalty-audit, rights-diligence, financing-underwrite, ic-memo-package, post-close-admin, seller-prep) with decision trees, workflows, outputs and eval cases.
Agent prompts/specs
plugins/music-catalog-diligence/agents/*.md
Adds agent specifications (diligence-qc-reviewer, metadata-reconciler, rights-chain-reviewer, royalty-audit-analyst, valuation-sensitivity-analyst) including tools and required JSON output contracts.
Commands / runbooks
plugins/music-catalog-diligence/commands/*.md
Adds command runbooks (catalog-kickoff, catalog-ingest, catalog-analyze, catalog-qc, catalog-package, catalog-diligence) with ordered steps and gating rules.
Hooks and protection scripts
plugins/music-catalog-diligence/hooks/hooks.json, plugins/music-catalog-diligence/hooks/protect-source-files.sh
Adds PreToolUse hook (bash script) that denies edits under deals/*/source/ and a Stop hook that enforces a completion gate checking evidence/assumptions/dashboard/findings traceability.
Data processing & validation scripts
plugins/music-catalog-diligence/scripts/*.py (normalize-, extract-, build-, calculate-, validate-, run-)
Adds ~20+ stdlib Python CLI scripts for manifest building, normalization (CSV/XLSX/PDF), extraction, concentration/NPS-NLS bridging, hygiene scans, validation (ledger/findings/evidence/workspace consistency), dashboard building, and a run-all readiness orchestrator. Each emits structured JSON and file outputs.
Shared utilities
plugins/music-catalog-diligence/scripts/_helpers.py
Adds load_yaml() (PyYAML when available, otherwise a minimal fallback parser) and deep_get() for dotted-path lookup to support zero-dependency runs.
Templates and workspace scaffolds
plugins/music-catalog-diligence/templates/deal-workspace/*
Adds assumptions.yaml, evidence-ledger.json, findings.json templates and memo templates (ic-memo.md, financing-pack.md, seller-cleanup-report.md) plus missing-files.md.
Fixtures, eval scenarios, golden tests
plugins/music-catalog-diligence/fixtures/*, plugins/music-catalog-diligence/evals/scenarios/*
Adds synthetic fixtures, external-sources mapping, and multiple eval scenarios for buy-side/financing/seller-prep/concentration/recoupment cases.
Tests
plugins/music-catalog-diligence/scripts/test-*.py
Adds extensive unittest modules that exercise scripts end-to-end (golden fixtures, normalization, concentration, dataroom hygiene, manifest/ledger/findings validators, dashboard/readiness, helpers). Tests run scripts via subprocess and assert JSON outputs/files.

Repository Documentation and Branding

Layer / File(s) Summary
Marketplace and contribution docs
AGENTS.md, README.md, contributing.md
Rewrites AGENTS.md to document Recoup Skills Marketplace and validation rules; rewrites README.md with marketplace, install, plugin/skill layout, and maintenance commands; expands contributing.md with step-by-step guidance for skills vs plugins, release checklist, and validation steps.
Changelog and CI notes
CHANGELOG.md, .github/workflows/validate.yml
Adds 1.0.0 changelog entry documenting migration to unified marketplace, new scripts, and plugin inclusion; CI workflow added to enforce manifest generation/validation.
Skill branding updates
skills/* (artist-workspace, getting-started, recoup-api, setup-sandbox, trend-to-song, chart-metric, create-artist)
Applies terminology updates from "Recoupable" → "Recoup", rewrites getting-started into an onboarding orchestrator, and updates curl/API base URLs and auth header guidance across install/usage docs.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Repo as Repository
    participant Gen as Generator
    participant Val as Validator
    participant CI as GitHub Actions

    Dev->>Repo: Update `marketplace.source.json` or plugin files
    CI->>Gen: Run `scripts/generate-marketplaces.py --check`
    Gen->>Repo: Load `marketplace.source.json` and compare generated targets
    Gen-->>CI: Return sync / diff result
    CI->>Val: Run `scripts/validate-manifests.py`
    Val->>Repo: Verify plugin dirs, manifests, and `SKILL.md` frontmatter
    Val-->>CI: Return validation result
    CI-->>Dev: PR check passes/fails
Loading
sequenceDiagram
    participant User as User/Agent
    participant Skill as Plugin Skill
    participant Scripts as Plugin Scripts
    participant Workspace as Deal Workspace
    participant Findings as Findings & Ledger
    participant Hooks as Hooks

    User->>Skill: Run `catalog-kickoff`
    Skill->>Workspace: Create `deals/{deal-id}` and `assumptions.yaml`
    User->>Skill: Run `catalog-ingest`
    Skill->>Scripts: run `build-file-manifest.py` -> `file-manifest.json`
    Skill->>Scripts: run `normalize-royalty-statement.py` -> `royalty-ledger.csv`
    Skill->>Scripts: run `validate-normalized-ledger.py`
    Scripts-->>Findings: Write `workpapers` / `findings`
    User->>Skill: Run `catalog-qc`
    Skill->>Hooks: Invoke `Stop` hook for completion gate
    Hooks->>Findings: Load `assumptions`, `evidence-ledger.json`, `findings.json`
    Hooks-->>User: Approve or Block package completion
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • recoupable/skills#14: Related branding/skill content changes for skills/recoup-api/SKILL.md (Recoupable → Recoup).
  • recoupable/skills#7: Related changes touching plugin/marketplace manifests and generation.

Suggested reviewers

  • sweetmantech

Poem

🐰 Hopped in code with tidy paws,

I stitched a marketplace with thoughtful laws.
Plugins, hooks, and tests in a row—
Deal workspaces tidy, evidence to show.
Hop, review, merge — let the Recoup garden grow!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/unified-marketplace

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

🧹 Nitpick comments (3)
plugins/music-catalog-diligence/scripts/_helpers.py (1)

35-60: ⚡ Quick win

Consider handling escaped quotes in the minimal YAML parser.

The _parse_scalar function (line 43) extracts quoted string content as s[1:-1] without processing escape sequences. This means a value like "foo\"bar" in YAML would be incorrectly parsed as foo\"bar instead of foo"bar.

While this is acceptable for the documented "limited grammar" and the function falls back to PyYAML when available, consider either:

  1. Adding basic escape handling for common cases (\", \\)
  2. Documenting this specific limitation in the docstring at lines 15-25
📝 Example: Add escape handling
     if (s.startswith('"') and s.endswith('"')) or (s.startswith("'") and s.endswith("'")):
-        return s[1:-1]
+        content = s[1:-1]
+        if s[0] == '"':
+            content = content.replace(r'\"', '"').replace(r'\\', '\\')
+        return content
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/music-catalog-diligence/scripts/_helpers.py` around lines 35 - 60,
The quoted-string branch in _parse_scalar currently returns s[1:-1] without
unescaping, so escaped quotes and backslashes (e.g. "foo\"bar" or "c:\\path")
are left raw; update _parse_scalar to unescape common sequences before returning
(handle at minimum `\"` -> `"` and `\\` -> `\`, and consider `\n`, `\t` if
desired), ensuring it only applies when the value is quoted, and reuse or add a
small helper (or inline logic near the quoted-string branch) so other parsing
functions like _split_flow remain unchanged; alternatively, if you prefer not to
change behavior, add a clear note to the module docstring describing the
limitation of not processing escape sequences for quoted scalars.
plugins/music-catalog-diligence/scripts/test-build-manual-review-queue.py (1)

73-73: 💤 Low value

Unused variable queue_md flagged by static analysis.

The test unpacks queue_md but doesn't use it. Other tests in this file (lines 85, 93) follow the pattern of prefixing unused variables with _. Consider applying the same pattern for consistency.

♻️ Suggested fix
-            code, payload, coverage, queue_md = run_queue(workspace)
+            code, payload, coverage, _queue_md = run_queue(workspace)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/music-catalog-diligence/scripts/test-build-manual-review-queue.py` at
line 73, The test currently unpacks four return values from run_queue(workspace)
into code, payload, coverage, queue_md but never uses queue_md; change the
unpack to use a discarded/underscore-prefixed name (e.g., _queue_md or _ ) to
match the pattern used in other tests and satisfy static analysis. Locate the
run_queue(...) call in the test (the call that assigns code, payload, coverage,
queue_md) and replace queue_md with _queue_md (or _) so the unused value is
clearly ignored while keeping the existing variables (code, payload, coverage)
intact.
plugins/music-catalog-diligence/hooks/hooks.json (1)

22-22: 💤 Low value

Consider extracting the long Stop hook prompt to a separate file.

The inline prompt is ~1400 characters. Extracting it to hooks/completion-gate-prompt.md would improve readability and make the prompt easier to maintain and test. You could then reference it with a file path or load it at runtime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/music-catalog-diligence/hooks/hooks.json` at line 22, The long inline
prompt string assigned to the "prompt" field in hooks.json should be extracted
to a separate file and referenced from hooks.json; create
hooks/completion-gate-prompt.md containing the current prompt text and update
the "prompt" value in plugins/music-catalog-diligence/hooks/hooks.json to load
or point to that file (e.g., by replacing the large inline string with a file
reference or loader call used by your runtime), ensuring the prompt content is
identical and tests still pass; locate the prompt by the "prompt" key in
hooks.json and the completion-gate behavior described there when making the
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/validate.yml:
- Around line 12-16: The workflow uses floating tags for actions
(actions/checkout@v4 and actions/setup-python@v5); replace those with the
corresponding immutable full-length commit SHAs for actions/checkout and
actions/setup-python in the workflow file so CI is pinned to a reproducible
version. Locate the uses lines referencing "actions/checkout" and
"actions/setup-python" and update the ref values to the official full commit
SHAs for their respective releases.

In `@AGENTS.md`:
- Line 118: The checklist currently lists only `.claude-plugin/plugin.json` and
`.codex-plugin/plugin.json`; update the validation line to include
`.cursor-plugin/plugin.json` so it reads that every plugin folder under
`plugins/` contains `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`,
and `.cursor-plugin/plugin.json`, and adjust any surrounding text that
references the "3-platform plugin structure" to reflect the three manifests
(Claude, Codex, Cursor).

In `@plugins/music-catalog-diligence/.cursor-plugin/plugin.json`:
- Line 10: The repository metadata in plugin.json is inconsistent with the
monorepo; update the "repository" value in
plugins/music-catalog-diligence/.cursor-plugin/plugin.json from
"https://github.com/recoupable/music-catalog-diligence" to point to the unified
monorepo "https://github.com/recoupable/skills" so the repository field for the
plugin matches the marketplace definitions and other plugins.

In `@plugins/music-catalog-diligence/hooks/protect-source-files.sh`:
- Around line 43-45: The case pattern `*/deals/*/source/*` misses relative paths
like `deals/abc/source/file.csv`; update the case for `file_path` to include
additional glob variants (e.g., `deals/*/source/*` and `*/deals/*/source/*`) so
both relative and non-relative matches are caught, keeping the same
`reason="Refused write to immutable source file: ${file_path}. "` assignment;
modify the case arm for `file_path` to use a combined pattern (`deals/*/source/*
| */deals/*/source/*)`) to block all variants.

In `@plugins/music-catalog-diligence/references/tooling-landscape.md`:
- Line 56: Update the wording in the table row for "Royalty Exchange" to replace
the awkward phrase "needs standardized royalty history" with "requires
standardized royalty history" so the sentence reads: "Royalty Exchange |
Marketplace underwriting requires standardized royalty history and buyer-facing
materials." Locate the table row containing the "Royalty Exchange" cell and
adjust the phrase accordingly in the tooling-landscape.md content.

In `@plugins/music-catalog-diligence/requirements.txt`:
- Around line 12-13: The requirements list allows pdfplumber to pull in
vulnerable Pillow versions; add an explicit requirement for Pillow pinned to a
patched release (e.g., Pillow>=12.2.0) alongside pdfplumber in requirements.txt
so that installing pdfplumber cannot bring in a vulnerable Pillow, updating the
file entries near the existing pdfplumber and openpyxl lines and optionally add
a comment referencing pdfplumber's transitive dependency to aid future
reviewers.

In `@plugins/music-catalog-diligence/scripts/calculate-nps-nls-bridge.py`:
- Around line 24-28: The loop over adjustments assumes each item is a dict;
before calling adjustment.get(...) validate each entry with
isinstance(adjustment, dict) (use the loop index from the iteration to identify
the offending element), and if the check fails raise a clear exception (e.g.,
ValueError/TypeError) that includes the index and the actual value/type; only
after validation access adjustment.get(...) to set label/amount and append to
rows (variables referenced: adjustments, adjustment, label, amount, normalized,
rows).
- Around line 17-27: Replace floating-point usage with Decimal for monetary
calculations: import Decimal and use it to parse reported =
Decimal(str(data.get("reported_amount", 0))) (with try/except to raise
SystemExit on invalid input), convert each adjustment amount via amount =
Decimal(str(adjustment.get("amount", 0))) inside the loop, keep normalized as a
Decimal and update normalized += amount, and populate rows with Decimal amounts;
ensure JSON serialization later converts Decimal values to strings. Update
handling around reported, adjustments, normalized, rows, and the adjustment loop
to use Decimal and add minimal validation/error handling for bad numeric inputs.

In `@plugins/music-catalog-diligence/scripts/extract-pdf-statement.py`:
- Around line 550-556: The loop currently appends per-file statuses (e.g., in
the except block that calls extract_rows) but the script still returns a global
success exit code even when some files errored; after the per_file processing
(and similarly for the block around lines 576-587), compute whether any entry
has a non-"ok" status (e.g., failures = any(item.get("status") != "ok" for item
in per_file)) and if so call sys.exit(1) (otherwise sys.exit(0)); add imports as
needed and place this check at the end of the script so extraction failures
cause a non-zero exit.
- Around line 373-384: In determine_period, guard access to row with
template.period_index to avoid IndexError on short rows: before using
row[template.period_index] in the "row_quarter", "row_year", and "row_period"
branches, verify template.period_index is not None and within bounds (0 <=
template.period_index < len(row)); if out of range, use an empty string as the
source value so row_quarter/row_year are called with "" (or return the
appropriate ("", "")/("",) fallback) instead of indexing into row directly.
Ensure you update the checks around determine_period, referencing the function
name determine_period and helpers row_quarter, row_year, and the attribute
template.period_index.

In `@plugins/music-catalog-diligence/scripts/normalize-royalty-statement.py`:
- Around line 700-705: The code currently computes rate and leaves status="ok"
even when normalized_rows is empty; change the logic so an empty normalization
is treated as non-OK: first check if not normalized_rows and in that case set
status to "partial" (or another non-OK value), populate missing via
expected_columns_not_found(provider, headers), and skip/avoid relying on
compute_population_rate; otherwise compute_population_rate(normalized_rows) and
apply the PARTIAL_THRESHOLD branch as before (refer to symbols: normalized_rows,
compute_population_rate, PARTIAL_THRESHOLD, status, expected_columns_not_found).

In `@plugins/music-catalog-diligence/scripts/test-normalize-royalty-statement.py`:
- Around line 18-22: write_csv currently assumes rows is non-empty and does
rows[0].keys(), which will IndexError for an empty list; add a guard at the top
of the write_csv function to handle empty rows (e.g., if not rows: raise
ValueError("rows must be non-empty") or return after creating an empty file) so
the function fails fast or produces a predictable empty output; update write_csv
to check `if not rows` before accessing rows[0] (refer to the write_csv function
and its use of rows[0].keys()).

In `@plugins/music-catalog-diligence/scripts/validate-deal-workspace.py`:
- Around line 25-29: The validator currently only catches json.JSONDecodeError
in validate_json_file when calling json.loads(path.read_text(...)) so file read
failures (OSError) or invalid UTF-8 (UnicodeDecodeError) will raise and crash
the script; update validate_json_file to first wrap
path.read_text(encoding="utf-8") in a try/except that catches OSError and
UnicodeDecodeError (in addition to keeping the JSONDecodeError handling for
json.loads) and return a structured error like f"{label} could not be read:
{err}" or f"{label} has invalid encoding: {err}" so all read/parse failures
produce validation errors rather than exceptions.

In `@plugins/music-catalog-diligence/scripts/validate-evidence-ledger.py`:
- Around line 43-47: The duplicate detection logic incorrectly only adds string
evidence_id values to the seen set but checks duplicates for all types; update
the handling in the loop that reads entry.get("evidence_id") so that either (A)
you validate type explicitly (raise or append an error to errors when
evidence_id is not a str) and only perform duplicate logic for valid strings, or
(B) allow any hashable type by adding non-string evidence_id values to seen as
well; modify the block around evidence_id, seen, and errors so duplicate
detection and tracking are consistent (refer to the variables evidence_id, seen,
errors and the entry.get call and adjust to one of the two approaches).

In `@plugins/music-catalog-diligence/skills/royalty-audit/SKILL.md`:
- Around line 21-23: This step currently references an external skill artifact
("skills/catalog-analysis/references/pro-performance-income.md"), creating a
cross-skill dependency; to fix, remove that external path from SKILL.md and
instead point to or include a plugin-level shared reference (e.g., add or
reference
"plugins/music-catalog-diligence/references/pro-performance-income.md") or
duplicate the essential guidance into this skill’s references, then update the
instruction lines that mention decomposing PRO performance income to reference
the new local/shared artifact and leave the output locations
(findings/findings.json and workpapers/) unchanged; search for the exact string
"skills/catalog-analysis/references/pro-performance-income.md" in SKILL.md and
replace it with the new local/shared reference or embedded guidance.

In `@scripts/validate-manifests.py`:
- Line 62: Change the call that reads the skill manifest to specify UTF-8
encoding: replace the plain skill_md.read_text() call with an explicit encoding
parameter (i.e., skill_md.read_text(encoding="utf-8")) so the file is read
consistently across platforms; update any neighboring reads in the same module
using the same pattern if needed.

---

Nitpick comments:
In `@plugins/music-catalog-diligence/hooks/hooks.json`:
- Line 22: The long inline prompt string assigned to the "prompt" field in
hooks.json should be extracted to a separate file and referenced from
hooks.json; create hooks/completion-gate-prompt.md containing the current prompt
text and update the "prompt" value in
plugins/music-catalog-diligence/hooks/hooks.json to load or point to that file
(e.g., by replacing the large inline string with a file reference or loader call
used by your runtime), ensuring the prompt content is identical and tests still
pass; locate the prompt by the "prompt" key in hooks.json and the
completion-gate behavior described there when making the change.

In `@plugins/music-catalog-diligence/scripts/_helpers.py`:
- Around line 35-60: The quoted-string branch in _parse_scalar currently returns
s[1:-1] without unescaping, so escaped quotes and backslashes (e.g. "foo\"bar"
or "c:\\path") are left raw; update _parse_scalar to unescape common sequences
before returning (handle at minimum `\"` -> `"` and `\\` -> `\`, and consider
`\n`, `\t` if desired), ensuring it only applies when the value is quoted, and
reuse or add a small helper (or inline logic near the quoted-string branch) so
other parsing functions like _split_flow remain unchanged; alternatively, if you
prefer not to change behavior, add a clear note to the module docstring
describing the limitation of not processing escape sequences for quoted scalars.

In `@plugins/music-catalog-diligence/scripts/test-build-manual-review-queue.py`:
- Line 73: The test currently unpacks four return values from
run_queue(workspace) into code, payload, coverage, queue_md but never uses
queue_md; change the unpack to use a discarded/underscore-prefixed name (e.g.,
_queue_md or _ ) to match the pattern used in other tests and satisfy static
analysis. Locate the run_queue(...) call in the test (the call that assigns
code, payload, coverage, queue_md) and replace queue_md with _queue_md (or _) so
the unused value is clearly ignored while keeping the existing variables (code,
payload, coverage) intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e0bc9bc6-e7da-432d-a0df-0e9a0aa0d441

📥 Commits

Reviewing files that changed from the base of the PR and between 7993be6 and b18c865.

⛔ Files ignored due to path filters (20)
  • plugins/music-catalog-diligence/fixtures/golden/ascap-performance/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/ascap-performance/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/bmi-performance/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/bmi-performance/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/bmi-real-headers/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/bmi-real-headers/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/curve-income/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/curve-income/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/direct-sync/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/direct-sync/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/distributor-master/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/distributor-master/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/mlc-mechanical/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/mlc-mechanical/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/publisher-admin/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/publisher-admin/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/soundexchange/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/soundexchange/input.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/youtube-content-id/expected-royalty-ledger.csv is excluded by !**/*.csv
  • plugins/music-catalog-diligence/fixtures/golden/youtube-content-id/input.csv is excluded by !**/*.csv
📒 Files selected for processing (106)
  • .agents/plugins/marketplace.json
  • .claude-plugin/marketplace.json
  • .claude-plugin/plugin.json
  • .codex-plugin/plugin.json
  • .cursor-plugin/marketplace.json
  • .github/workflows/validate.yml
  • AGENTS.md
  • CHANGELOG.md
  • README.md
  • contributing.md
  • marketplace.source.json
  • plugins/music-catalog-diligence/.claude-plugin/plugin.json
  • plugins/music-catalog-diligence/.codex-plugin/plugin.json
  • plugins/music-catalog-diligence/.cursor-plugin/plugin.json
  • plugins/music-catalog-diligence/.gitignore
  • plugins/music-catalog-diligence/LICENSE
  • plugins/music-catalog-diligence/README.md
  • plugins/music-catalog-diligence/agents/diligence-qc-reviewer.md
  • plugins/music-catalog-diligence/agents/metadata-reconciler.md
  • plugins/music-catalog-diligence/agents/rights-chain-reviewer.md
  • plugins/music-catalog-diligence/agents/royalty-audit-analyst.md
  • plugins/music-catalog-diligence/agents/valuation-sensitivity-analyst.md
  • plugins/music-catalog-diligence/commands/catalog-analyze.md
  • plugins/music-catalog-diligence/commands/catalog-diligence.md
  • plugins/music-catalog-diligence/commands/catalog-ingest.md
  • plugins/music-catalog-diligence/commands/catalog-kickoff.md
  • plugins/music-catalog-diligence/commands/catalog-package.md
  • plugins/music-catalog-diligence/commands/catalog-qc.md
  • plugins/music-catalog-diligence/evals/README.md
  • plugins/music-catalog-diligence/evals/scenarios/financing-collateral-pack.json
  • plugins/music-catalog-diligence/evals/scenarios/messy-data-room.json
  • plugins/music-catalog-diligence/evals/scenarios/missing-chain-of-title.json
  • plugins/music-catalog-diligence/evals/scenarios/one-song-concentration.json
  • plugins/music-catalog-diligence/evals/scenarios/pro-bonus-spike.json
  • plugins/music-catalog-diligence/evals/scenarios/recoupment-cliff.json
  • plugins/music-catalog-diligence/evals/scenarios/seller-prep-cleanup.json
  • plugins/music-catalog-diligence/fixtures/external-sources.md
  • plugins/music-catalog-diligence/fixtures/golden/bmi-real-headers/expected-status.json
  • plugins/music-catalog-diligence/hooks/hooks.json
  • plugins/music-catalog-diligence/hooks/protect-source-files.sh
  • plugins/music-catalog-diligence/references/deal-workspace.md
  • plugins/music-catalog-diligence/references/diligence-workflow.md
  • plugins/music-catalog-diligence/references/normalization.md
  • plugins/music-catalog-diligence/references/red-flags.md
  • plugins/music-catalog-diligence/references/tooling-landscape.md
  • plugins/music-catalog-diligence/requirements.txt
  • plugins/music-catalog-diligence/scripts/_helpers.py
  • plugins/music-catalog-diligence/scripts/build-diligence-dashboard.py
  • plugins/music-catalog-diligence/scripts/build-file-manifest.py
  • plugins/music-catalog-diligence/scripts/build-manual-review-queue.py
  • plugins/music-catalog-diligence/scripts/calculate-concentration.py
  • plugins/music-catalog-diligence/scripts/calculate-nps-nls-bridge.py
  • plugins/music-catalog-diligence/scripts/dataroom-hygiene-scan.py
  • plugins/music-catalog-diligence/scripts/extract-pdf-statement.py
  • plugins/music-catalog-diligence/scripts/normalize-royalty-statement.py
  • plugins/music-catalog-diligence/scripts/run-diligence-checks.py
  • plugins/music-catalog-diligence/scripts/test-build-manual-review-queue.py
  • plugins/music-catalog-diligence/scripts/test-calculate-concentration.py
  • plugins/music-catalog-diligence/scripts/test-dataroom-hygiene-scan.py
  • plugins/music-catalog-diligence/scripts/test-diligence-readiness.py
  • plugins/music-catalog-diligence/scripts/test-golden-fixtures.py
  • plugins/music-catalog-diligence/scripts/test-helpers.py
  • plugins/music-catalog-diligence/scripts/test-normalize-royalty-statement.py
  • plugins/music-catalog-diligence/scripts/test-validate-deal-workspace.py
  • plugins/music-catalog-diligence/scripts/test-validate-findings-evidence.py
  • plugins/music-catalog-diligence/scripts/test-validate-workspace-consistency.py
  • plugins/music-catalog-diligence/scripts/validate-deal-workspace.py
  • plugins/music-catalog-diligence/scripts/validate-evidence-ledger.py
  • plugins/music-catalog-diligence/scripts/validate-findings-evidence.py
  • plugins/music-catalog-diligence/scripts/validate-normalized-ledger.py
  • plugins/music-catalog-diligence/scripts/validate-workspace-consistency.py
  • plugins/music-catalog-diligence/skills/catalog-analysis/SKILL.md
  • plugins/music-catalog-diligence/skills/catalog-analysis/evals/evals.json
  • plugins/music-catalog-diligence/skills/catalog-analysis/references/output-templates.md
  • plugins/music-catalog-diligence/skills/catalog-analysis/references/pro-performance-income.md
  • plugins/music-catalog-diligence/skills/catalog-analysis/references/valuation-framework.md
  • plugins/music-catalog-diligence/skills/catalog-ingest/SKILL.md
  • plugins/music-catalog-diligence/skills/catalog-ingest/evals/evals.json
  • plugins/music-catalog-diligence/skills/catalog-ingest/references/canonical-schema.md
  • plugins/music-catalog-diligence/skills/catalog-ingest/references/cleaning-rules.md
  • plugins/music-catalog-diligence/skills/catalog-ingest/references/data-room-checklist.md
  • plugins/music-catalog-diligence/skills/diligence-kickoff/SKILL.md
  • plugins/music-catalog-diligence/skills/financing-underwrite/SKILL.md
  • plugins/music-catalog-diligence/skills/financing-underwrite/evals/evals.json
  • plugins/music-catalog-diligence/skills/ic-memo-package/SKILL.md
  • plugins/music-catalog-diligence/skills/post-close-admin/SKILL.md
  • plugins/music-catalog-diligence/skills/rights-diligence/SKILL.md
  • plugins/music-catalog-diligence/skills/rights-diligence/evals/evals.json
  • plugins/music-catalog-diligence/skills/royalty-audit/SKILL.md
  • plugins/music-catalog-diligence/skills/royalty-audit/evals/evals.json
  • plugins/music-catalog-diligence/skills/seller-prep/SKILL.md
  • plugins/music-catalog-diligence/skills/seller-prep/evals/evals.json
  • plugins/music-catalog-diligence/templates/deal-workspace/assumptions.yaml
  • plugins/music-catalog-diligence/templates/deal-workspace/evidence-ledger.json
  • plugins/music-catalog-diligence/templates/deal-workspace/findings.json
  • plugins/music-catalog-diligence/templates/deal-workspace/memos/financing-pack.md
  • plugins/music-catalog-diligence/templates/deal-workspace/memos/ic-memo.md
  • plugins/music-catalog-diligence/templates/deal-workspace/memos/seller-cleanup-report.md
  • plugins/music-catalog-diligence/templates/deal-workspace/missing-files.md
  • scripts/generate-marketplaces.py
  • scripts/validate-manifests.py
  • skills/artist-workspace/SKILL.md
  • skills/getting-started/SKILL.md
  • skills/recoup-api/SKILL.md
  • skills/setup-sandbox/SKILL.md
  • skills/trend-to-song/SKILL.md
💤 Files with no reviewable changes (2)
  • .claude-plugin/plugin.json
  • .codex-plugin/plugin.json

Comment thread .github/workflows/validate.yml
Comment thread AGENTS.md Outdated
Comment thread plugins/music-catalog-diligence/.cursor-plugin/plugin.json Outdated
Comment thread plugins/music-catalog-diligence/hooks/protect-source-files.sh
Comment thread plugins/music-catalog-diligence/references/tooling-landscape.md Outdated
Comment thread plugins/music-catalog-diligence/scripts/validate-deal-workspace.py
Comment thread plugins/music-catalog-diligence/scripts/validate-evidence-ledger.py Outdated
Comment thread plugins/music-catalog-diligence/skills/royalty-audit/SKILL.md
Comment thread scripts/validate-manifests.py Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 issues found across 126 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="plugins/music-catalog-diligence/scripts/validate-evidence-ledger.py">

<violation number="1" location="plugins/music-catalog-diligence/scripts/validate-evidence-ledger.py:28">
P2: Handle non-object top-level JSON before calling `.get()` to avoid validator crashes on malformed ledger shape.</violation>
</file>

<file name="plugins/music-catalog-diligence/scripts/calculate-nps-nls-bridge.py">

<violation number="1" location="plugins/music-catalog-diligence/scripts/calculate-nps-nls-bridge.py:25">
P2: Validate each `adjustments` entry is an object before using `.get`, otherwise malformed input causes an unhandled `AttributeError`.</violation>
</file>

<file name="plugins/music-catalog-diligence/scripts/validate-normalized-ledger.py">

<violation number="1" location="plugins/music-catalog-diligence/scripts/validate-normalized-ledger.py:43">
P2: Blank `ledger_line_id` values are silently accepted, so the validator can pass ledgers with unidentified rows.</violation>
</file>

<file name="plugins/music-catalog-diligence/hooks/protect-source-files.sh">

<violation number="1" location="plugins/music-catalog-diligence/hooks/protect-source-files.sh:44">
P1: The source-protection glob misses repo-relative paths like `deals/<id>/source/...`, allowing writes that should be denied.</violation>
</file>

<file name="plugins/music-catalog-diligence/hooks/hooks.json">

<violation number="1" location="plugins/music-catalog-diligence/hooks/hooks.json:10">
P2: Quote `${CLAUDE_PLUGIN_ROOT}` in this shell-form hook command so the path survives shell tokenization.</violation>
</file>

<file name="plugins/music-catalog-diligence/skills/royalty-audit/SKILL.md">

<violation number="1" location="plugins/music-catalog-diligence/skills/royalty-audit/SKILL.md:22">
P3: Use the correct sibling reference path here; this path won’t resolve from the current skill file.</violation>
</file>

<file name="marketplace.source.json">

<violation number="1" location="marketplace.source.json:2">
P2: Point `$schema` at a real schema file or remove the reference; this path does not exist, so schema validation can't resolve it.</violation>
</file>

<file name="plugins/music-catalog-diligence/commands/catalog-analyze.md">

<violation number="1" location="plugins/music-catalog-diligence/commands/catalog-analyze.md:17">
P2: These helper-script invocations are incomplete; both scripts require a positional input file, so this step will just hit argparse usage errors.</violation>
</file>

<file name="plugins/music-catalog-diligence/skills/catalog-analysis/references/output-templates.md">

<violation number="1" location="plugins/music-catalog-diligence/skills/catalog-analysis/references/output-templates.md:37">
P2: Use the canonical bridge adjustments from `SKILL.md`. This version drops direct-license, spike, and undercollection/missing-registration adjustments, which can understate or double-count the normalized run-rate.</violation>

<violation number="2" location="plugins/music-catalog-diligence/skills/catalog-analysis/references/output-templates.md:70">
P2: Add a separate sensitivity table section; the catalog-analysis skill requires it as a distinct deliverable, and the current template only covers scenarios.</violation>
</file>

<file name="plugins/music-catalog-diligence/references/normalization.md">

<violation number="1" location="plugins/music-catalog-diligence/references/normalization.md:103">
P3: Document `expected-status.json` for partial fixtures; the current fixture layout omits a required file used by the test suite.</violation>
</file>

<file name="plugins/music-catalog-diligence/templates/deal-workspace/evidence-ledger.json">

<violation number="1" location="plugins/music-catalog-diligence/templates/deal-workspace/evidence-ledger.json:4">
P2: Use an empty evidence ledger template instead of seeding a fake row; the placeholder entry is treated as real traceability data and `confidence: "example"` is not a valid label.</violation>
</file>

<file name="plugins/music-catalog-diligence/scripts/normalize-royalty-statement.py">

<violation number="1" location="plugins/music-catalog-diligence/scripts/normalize-royalty-statement.py:703">
P1: Handle the zero-row case as non-OK output. Leaving `status` as `ok` when nothing is normalized lets ingest proceed with an empty ledger.</violation>
</file>

<file name="plugins/music-catalog-diligence/references/deal-workspace.md">

<violation number="1" location="plugins/music-catalog-diligence/references/deal-workspace.md:1">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

This new file exceeds the repository’s <100-line file-size limit and consolidates multiple concerns into one monolithic markdown doc.</violation>
</file>

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.

Comment thread plugins/music-catalog-diligence/hooks/protect-source-files.sh Outdated
Comment thread plugins/music-catalog-diligence/scripts/normalize-royalty-statement.py Outdated
Comment thread plugins/music-catalog-diligence/scripts/validate-evidence-ledger.py
Comment thread plugins/music-catalog-diligence/scripts/calculate-nps-nls-bridge.py
Comment thread plugins/music-catalog-diligence/templates/deal-workspace/evidence-ledger.json Outdated
Comment thread plugins/music-catalog-diligence/references/deal-workspace.md
Comment thread plugins/music-catalog-diligence/skills/royalty-audit/SKILL.md Outdated
Comment thread plugins/music-catalog-diligence/references/normalization.md
…st account.json

PR review surfaced four real issues that would break customers post-merge.
Three are fixed here. The fourth (setup-sandbox vs artist-workspace layout
inconsistency) is a deeper design decision documented as a follow-up.

1. **getting-started — /whoami endpoint doesn't exist.**
   Step 3 originally called `/api/whoami` (returns 404 — the endpoint was
   never built). Replaced with `/api/organizations` as the auth verification
   call: 200 means the key works, response body is reused in Step 4 instead
   of fetching orgs twice.

   The account_id + email come from two sources now:
     - Fresh signup (Path A or B): capture from agents/signup or
       agents/verify response, persist to ~/.config/recoup/account.json.
     - Returning agent: read account.json from disk.
     - Sandbox: RECOUP_ACCOUNT_ID is already injected — wins.
     - None of the above: proceed with "identity unknown" — throwaway
       warning silently skips, the rest of the flow still works.

   Step 5 routing table extended for the "0 orgs + email unknown"
   case (returning agent with no cached identity) — asks the user
   instead of crashing.

2. **create-artist — Bearer-only auth + wrong base URL.**
   The skill required $RECOUP_ACCESS_TOKEN (sandbox-only) and used
   api.recoupable.com (inconsistent with the rest of the marketplace).
   Now uses the same AUTH_HEADER abstraction as getting-started, so it
   accepts either RECOUP_API_KEY (BYOA) or RECOUP_ACCESS_TOKEN (sandbox).
   All ~13 curl invocations updated to recoup-api.vercel.app + $AUTH_HEADER.

3. **chart-metric/README.md — bogus install command.**
   Said `npx skills add recoupable/chartmetric` — no such repo. Replaced
   with the actual install commands across Claude Code, Codex, and the
   Vercel CLI (with `--skill chart-metric` for cherry-pick).

Validator passes. ETA on the fourth issue (setup-sandbox layout): separate
follow-up after a layout decision (single-org vs multi-org sandbox).

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="skills/create-artist/SKILL.md">

<violation number="1" location="skills/create-artist/SKILL.md:18">
P1: Populate `AUTH_HEADER` with the bearer token here; otherwise the access-token path never authenticates the later curl calls.</violation>
</file>

<file name="skills/getting-started/SKILL.md">

<violation number="1" location="skills/getting-started/SKILL.md:163">
P1: Don't source account identity from the persisted cache without validating it against the current auth token; a stale `account.json` can misclassify the active account and route onboarding incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread skills/create-artist/SKILL.md Outdated
Comment thread skills/getting-started/SKILL.md
sidneyswift added a commit to recoupable/docs that referenced this pull request May 12, 2026
…o skill

Two coordinated changes for the upcoming recoupable/skills#23 (unified
marketplace where skills and plugins ship from one repo).

1. Add the short-video skill that just shipped in recoupable/skills#24:
   - New skills/short-video.mdx (card page)
   - New row in skills.mdx 'Doing the work' table
   - Sidebar entry in docs.json

2. Rewrite the Install section of skills.mdx for the post-#23 world:
   - One marketplace serves both skills and plugins (recoupable/skills)
   - Per-runtime install instructions for Claude Code / Cowork / Codex /
     Cursor / npx skills CLI
   - Drop references to the now-merged-in recoupable/plugins and
     recoupable/music-catalog-diligence external repos
   - 'How a plugin is structured' updated to reflect in-tree layout at
     recoupable/skills/plugins/<name>/ with the three per-runtime manifests

3. Update plugins/music-catalog-diligence.mdx install table to match.

Net: 156 nav entries (was 155, +1 for short-video), 0 404s, 0 orphans,
no em-dashes, all install commands point at the unified marketplace.
Five high-leverage fixes from the coderabbitai + cubic-dev-ai reviews
on this PR. Deferred ~27 lower-confidence bot comments for human review.

1. skills/create-artist/SKILL.md:18 - real AUTH_HEADER bug. The Bearer
   token branch self-assigned AUTH_HEADER, so /api calls were never
   authenticated when only RECOUP_ACCESS_TOKEN was set. Now sets
   AUTH_HEADER="Authorization: Bearer $RECOUP_ACCESS_TOKEN".

2. AGENTS.md:118 - validator checklist omitted the Cursor manifest.
   Added .cursor-plugin/plugin.json to keep the docs aligned with the
   3-platform plugin structure.

3. plugins/music-catalog-diligence/.{cursor,claude,codex}-plugin/plugin.json
   - 'repository' field pointed at the old recoupable/music-catalog-diligence
   repo. Now points at recoupable/skills since the plugin lives in-tree.

4. marketplace.source.json:2 - $schema pointed at a non-existent file
   (./scripts/marketplace.source.schema.json), which broke JSON schema
   validation in editors. Removed the dead reference. (A real schema
   can be added later if needed.)

5. plugins/music-catalog-diligence/hooks/hooks.json:10 - bash command
   didn't quote ${CLAUDE_PLUGIN_ROOT}, so paths containing spaces would
   tokenize incorrectly. Now: bash "${CLAUDE_PLUGIN_ROOT}/hooks/...".

validate-manifests.py: all manifests valid.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
skills/create-artist/SKILL.md (1)

10-10: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Cross-skill dependency violates self-contained principle.

This skill has a hard dependency on artist-workspace to scaffold the RECOUP.md file before execution (line 27 lists it as a prerequisite, line 10 describes the workflow dependency). The retrieved learning states: "Skills must be self-contained with no cross-dependencies between skills."

While the dependency is explicit and well-documented, it creates coupling that may complicate skill distribution, testing, and maintenance. Consider either:

  1. Embedding the RECOUP.md scaffolding logic directly in this skill, or
  2. Making the skill gracefully handle missing workspace files (e.g., scaffold on-demand if not present), or
  3. Documenting an exception to the self-contained principle for orchestrator skills in this marketplace.

Based on learnings: Skills must be self-contained with no cross-dependencies between skills.

Also applies to: 27-27

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/create-artist/SKILL.md` at line 10, This skill currently depends on
the external artist-workspace scaffold (RECOUP.md) which violates self-contained
rules; update the create-artist skill to detect a missing RECOUP.md at startup
and scaffold a local RECOUP.md checklist (including frontmatter fields)
on-demand, then drive the 8-step workflow from that checklist and persist
captured values back into the RECOUP.md frontmatter as each step completes so
state can be resumed; specifically add a "ensureRecoupScaffold" step at the
start of the workflow that creates the RECOUP.md scaffold if absent, and update
the code that processes the checklist to write progress into the RECOUP.md
frontmatter rather than assuming artist-workspace exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@skills/create-artist/SKILL.md`:
- Line 10: This skill currently depends on the external artist-workspace
scaffold (RECOUP.md) which violates self-contained rules; update the
create-artist skill to detect a missing RECOUP.md at startup and scaffold a
local RECOUP.md checklist (including frontmatter fields) on-demand, then drive
the 8-step workflow from that checklist and persist captured values back into
the RECOUP.md frontmatter as each step completes so state can be resumed;
specifically add a "ensureRecoupScaffold" step at the start of the workflow that
creates the RECOUP.md scaffold if absent, and update the code that processes the
checklist to write progress into the RECOUP.md frontmatter rather than assuming
artist-workspace exists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ac058d84-33b3-4f8e-a605-e0078025634f

📥 Commits

Reviewing files that changed from the base of the PR and between b18c865 and 54dbcdb.

📒 Files selected for processing (9)
  • AGENTS.md
  • marketplace.source.json
  • plugins/music-catalog-diligence/.claude-plugin/plugin.json
  • plugins/music-catalog-diligence/.codex-plugin/plugin.json
  • plugins/music-catalog-diligence/.cursor-plugin/plugin.json
  • plugins/music-catalog-diligence/hooks/hooks.json
  • skills/chart-metric/README.md
  • skills/create-artist/SKILL.md
  • skills/getting-started/SKILL.md
✅ Files skipped from review due to trivial changes (4)
  • plugins/music-catalog-diligence/.cursor-plugin/plugin.json
  • plugins/music-catalog-diligence/.claude-plugin/plugin.json
  • skills/chart-metric/README.md
  • plugins/music-catalog-diligence/.codex-plugin/plugin.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • plugins/music-catalog-diligence/hooks/hooks.json
  • marketplace.source.json
  • skills/getting-started/SKILL.md

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="AGENTS.md">

<violation number="1" location="AGENTS.md:118">
P2: CI validation still doesn't enforce `.cursor-plugin/plugin.json`, so this checklist item overstates the check and can give false confidence.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Comment thread AGENTS.md
Hardening fixes across the music-catalog-diligence plugin scripts plus a
handful of doc, template, and CI parity fixes flagged by CodeRabbit and
cubic-dev-ai on PR #23.

Hardening
- protect-source-files.sh: extend deny glob to match relative
  (deals/.../source), dot-relative (./deals/.../source), and absolute
  (/abs/deals/.../source) paths so the guard cannot be bypassed.
- calculate-nps-nls-bridge.py: switch monetary math to Decimal,
  reject non-object top-level and non-dict adjustment entries.
- extract-pdf-statement.py: guard period_index against short rows;
  return summary status "partial" and exit 1 when any PDF errored.
- normalize-royalty-statement.py: treat zero normalized rows as
  partial, never ok.
- validate-deal-workspace.py: catch OSError and UnicodeDecodeError so
  unreadable files surface as validation errors instead of crashes.
- validate-evidence-ledger.py: validate non-object top-level JSON and
  require evidence_id to be a string before deduping.
- validate-normalized-ledger.py: flag blank ledger_line_id rows so
  unidentified rows do not pass silently.
- test-normalize-royalty-statement.py: guard write_csv against empty
  rows.
- requirements.txt: pin pillow>=12.2.0 to avoid vulnerable transitive
  versions pulled in by pdfplumber.

Docs and templates
- evidence-ledger.json template: ship empty entries (no fake
  placeholder row with confidence="example").
- output-templates.md: align quality-of-earnings bridge with the
  canonical adjustment ladder from catalog-analysis SKILL.md and add
  the separate sensitivity-table section the skill requires.
- normalization.md: document expected-status.json for partial fixtures.
- tooling-landscape.md: fix awkward "needs standardized" phrasing.
- catalog-analyze.md: show the required positional input args for
  calculate-concentration.py and calculate-nps-nls-bridge.py.
- royalty-audit/SKILL.md and catalog-analysis/SKILL.md: move
  pro-performance-income.md to plugin-level references/ so the two
  skills no longer cross-depend.

Cache safety
- getting-started/SKILL.md: validate the cached account_id against the
  current auth token before using it; discard the cache when the token
  cannot read the account, so onboarding cannot be routed into a
  different account's workspace.

CI parity
- scripts/validate-manifests.py: enforce .cursor-plugin/plugin.json on
  every self-contained plugin so the AGENTS.md checklist matches what CI
  actually checks. Also pass encoding="utf-8" to read_text.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 19 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="skills/getting-started/SKILL.md">

<violation number="1" location="skills/getting-started/SKILL.md:168">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

This change adds more logic to an already oversized, multi-responsibility SKILL.md instead of splitting the concern into a smaller file, violating the under-100-lines/single-responsibility rule.</violation>
</file>

<file name="plugins/music-catalog-diligence/skills/catalog-analysis/references/output-templates.md">

<violation number="1" location="plugins/music-catalog-diligence/skills/catalog-analysis/references/output-templates.md:36">
P2: Custom agent: **Enforce Clear Code Style and Maintainability Practices**

This file exceeds the custom rule’s 100-line limit, so it no longer complies with the maintainability constraint.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Comment thread skills/getting-started/SKILL.md
@sidneyswift
Copy link
Copy Markdown
Contributor Author

Splitting this PR into 4 reviewable units per @sweetmantech's feedback (128 files was too big for one review).

# PR Branch Size Base
1 #25 feat/marketplace-machinery 13 files, +961/-137 main
2 #27 feat/catalog-plugin 112 files, +8394 (subtree import) feat/marketplace-machinery
3 #28 feat/recoup-rename 17 files, +66/-66 (pure rename) feat/catalog-plugin
4 #26 feat/orchestrator 3 files, +298/-86 main (independent)

Each PR has:

  • A focused commit message and PR description
  • An explicit "what to focus on" section
  • A test plan with validators run
  • Evidence checklist (Looms/screenshots — coming as I record them)
  • "Please merge yourself when satisfied" — async review, no thumbs-up needed

PR 1 and PR 4 are independent (off main) — can land in any order. PR 2 stacks on PR 1; PR 3 stacks on PR 2. GitHub will auto-rebase the stack as each lands.

Closing this in favor of the 4-PR stack once you've taken a look.

sidneyswift added a commit that referenced this pull request May 13, 2026
…nding)

Sets up the single-source-of-truth marketplace pattern. After this lands,
adding a new plugin is one entry in marketplace.source.json + a regen.
No end-user behavior change yet — this PR ships the infrastructure only.

What this PR adds
- marketplace.source.json — single source of truth for the marketplace
  + the recoup-skills virtual plugin (the existing 12 broad music skills).
- scripts/generate-marketplaces.py — emits the three platform manifests:
  .claude-plugin/marketplace.json, .agents/plugins/marketplace.json,
  .cursor-plugin/marketplace.json. --check mode detects drift.
- scripts/validate-manifests.py — checks generator parity, plugin source
  paths, .claude/.codex/.cursor plugin manifests on each plugins/ folder,
  and SKILL.md frontmatter (name + description) on every skill.
- .github/workflows/validate.yml — runs both scripts on every PR.
- AGENTS.md, README.md, contributing.md, CHANGELOG.md — describe the
  source-of-truth + generated-files pattern (with recoup branding).
- Removes the now-superseded root .claude-plugin/plugin.json and
  .codex-plugin/plugin.json (the recoup-skills virtual plugin entry
  in the marketplace replaces them).

Branding
- Marketplace name: recoup
- Plugin name: recoup-skills
- Display names: Recoup Skills, developerName: Recoup
- Owner/author: Recoup
- Install path: @recoup
- recoupable.com URLs, agent@recoupable.com, recoupable/skills repo
  path, @recoupable/cli npm package, and LICENSE entity stay unchanged.

After this lands
  /plugin marketplace add recoupable/skills
  /plugin install recoup-skills@recoup

Why this is small enough to review
- 13 files, +961 / -137. All-new infrastructure, zero behavior change
  for end users (no skill paths under skills/ moved).
- Generated files are mechanically derivable from marketplace.source.json.
  Spot-check the source file; trust the generator.

What's intentionally NOT in this PR
- No catalog plugin (separate PR — adds plugins/music-catalog-diligence/
  directory and registers it in marketplace.source.json).
- No getting-started orchestrator rewrite (separate PR).

Test plan
- python3 scripts/generate-marketplaces.py --check → exit 0
- python3 scripts/validate-manifests.py            → exit 0

Replaces #23 (split into 3 PRs; rename baked into each).

Co-authored-by: Cursor <cursoragent@cursor.com>
@sidneyswift
Copy link
Copy Markdown
Contributor Author

Update: split is now 3 PRs, not 4. Baked the recoup rename into each PR instead of separating it.

# PR Branch Size Base
1 #25 feat/marketplace-machinery 13 files, +962/-138 main
2 #27 feat/catalog-plugin 112 files, +8394 (subtree) feat/marketplace-machinery
3 #26 feat/orchestrator 3 files, +299/-87 main (independent)

(Original PR 28 closed — rename now lives in each of the 3 PRs above.)

All 3 are MERGEABLE with CI green. PR 1 and PR 3 are independent (off main); PR 2 stacks on PR 1. GitHub will auto-rebase the stack as each lands.

Closing this in favor of the 3-PR stack once you've taken a look.

sidneyswift added a commit that referenced this pull request May 13, 2026
…nding)

Sets up the single-source-of-truth marketplace pattern. After this lands,
adding a new plugin is one entry in marketplace.source.json + a regen.
No end-user behavior change yet — this PR ships the infrastructure only.

What this PR adds
- marketplace.source.json — single source of truth for the marketplace
  + the recoup-skills virtual plugin (the existing 12 broad music skills).
- scripts/generate-marketplaces.py — emits the three platform manifests:
  .claude-plugin/marketplace.json, .agents/plugins/marketplace.json,
  .cursor-plugin/marketplace.json. --check mode detects drift.
- scripts/validate-manifests.py — checks generator parity, plugin source
  paths, .claude/.codex/.cursor plugin manifests on each plugins/ folder,
  and SKILL.md frontmatter (name + description) on every skill.
- .github/workflows/validate.yml — runs both scripts on every PR.
- AGENTS.md, README.md, contributing.md, CHANGELOG.md — describe the
  source-of-truth + generated-files pattern (with recoup branding).
- Removes the now-superseded root .claude-plugin/plugin.json and
  .codex-plugin/plugin.json (the recoup-skills virtual plugin entry
  in the marketplace replaces them).

Branding
- Marketplace name: recoup
- Plugin name: recoup-skills
- Display names: Recoup Skills, developerName: Recoup
- Owner/author: Recoup
- Install path: @recoup
- recoupable.com URLs, agent@recoupable.com, recoupable/skills repo
  path, @recoupable/cli npm package, and LICENSE entity stay unchanged.

After this lands
  /plugin marketplace add recoupable/skills
  /plugin install recoup-skills@recoup

Why this is small enough to review
- 13 files, +961 / -137. All-new infrastructure, zero behavior change
  for end users (no skill paths under skills/ moved).
- Generated files are mechanically derivable from marketplace.source.json.
  Spot-check the source file; trust the generator.

What's intentionally NOT in this PR
- No catalog plugin (separate PR — adds plugins/music-catalog-diligence/
  directory and registers it in marketplace.source.json).
- No getting-started orchestrator rewrite (separate PR).

Test plan
- python3 scripts/generate-marketplaces.py --check → exit 0
- python3 scripts/validate-manifests.py            → exit 0

Replaces #23 (split into 3 PRs; rename baked into each).

Co-authored-by: Cursor <cursoragent@cursor.com>
sidneyswift added a commit that referenced this pull request May 13, 2026
…nding)

Sets up the single-source-of-truth marketplace pattern. After this lands,
adding a new plugin is one entry in marketplace.source.json + a regen.
No end-user behavior change yet — this PR ships the infrastructure only.

What this PR adds
- marketplace.source.json — single source of truth for the marketplace
  + the recoup-skills virtual plugin (the existing 12 broad music skills).
- scripts/generate-marketplaces.py — emits the three platform manifests:
  .claude-plugin/marketplace.json, .agents/plugins/marketplace.json,
  .cursor-plugin/marketplace.json. --check mode detects drift.
- scripts/validate-manifests.py — checks generator parity, plugin source
  paths, .claude/.codex/.cursor plugin manifests on each plugins/ folder,
  and SKILL.md frontmatter (name + description) on every skill.
- .github/workflows/validate.yml — runs both scripts on every PR.
- AGENTS.md, README.md, contributing.md, CHANGELOG.md — describe the
  source-of-truth + generated-files pattern (with recoup branding).
- Removes the now-superseded root .claude-plugin/plugin.json and
  .codex-plugin/plugin.json (the recoup-skills virtual plugin entry
  in the marketplace replaces them).

Branding
- Marketplace name: recoup
- Plugin name: recoup-skills
- Display names: Recoup Skills, developerName: Recoup
- Owner/author: Recoup
- Install path: @recoup
- recoupable.com URLs, agent@recoupable.com, recoupable/skills repo
  path, @recoupable/cli npm package, and LICENSE entity stay unchanged.

After this lands
  /plugin marketplace add recoupable/skills
  /plugin install recoup-skills@recoup

Why this is small enough to review
- 13 files, +961 / -137. All-new infrastructure, zero behavior change
  for end users (no skill paths under skills/ moved).
- Generated files are mechanically derivable from marketplace.source.json.
  Spot-check the source file; trust the generator.

What's intentionally NOT in this PR
- No catalog plugin (separate PR — adds plugins/music-catalog-diligence/
  directory and registers it in marketplace.source.json).
- No getting-started orchestrator rewrite (separate PR).

Test plan
- python3 scripts/generate-marketplaces.py --check → exit 0
- python3 scripts/validate-manifests.py            → exit 0

Replaces #23 (split into 3 PRs; rename baked into each).

Co-authored-by: Cursor <cursoragent@cursor.com>
sidneyswift added a commit that referenced this pull request May 13, 2026
…nding)

Sets up the single-source-of-truth marketplace pattern. After this lands,
adding a new plugin is one entry in marketplace.source.json + a regen.
No end-user behavior change yet — this PR ships the infrastructure only.

What this PR adds
- marketplace.source.json — single source of truth for the marketplace
  + the recoup-skills virtual plugin (the existing 12 broad music skills).
- scripts/generate-marketplaces.py — emits the three platform manifests:
  .claude-plugin/marketplace.json, .agents/plugins/marketplace.json,
  .cursor-plugin/marketplace.json. --check mode detects drift.
- scripts/validate-manifests.py — checks generator parity, plugin source
  paths, .claude/.codex/.cursor plugin manifests on each plugins/ folder,
  and SKILL.md frontmatter (name + description) on every skill.
- .github/workflows/validate.yml — runs both scripts on every PR.
- AGENTS.md, README.md, contributing.md, CHANGELOG.md — describe the
  source-of-truth + generated-files pattern (with recoup branding).
- Removes the now-superseded root .claude-plugin/plugin.json and
  .codex-plugin/plugin.json (the recoup-skills virtual plugin entry
  in the marketplace replaces them).

Branding
- Marketplace name: recoup
- Plugin name: recoup-skills
- Display names: Recoup Skills, developerName: Recoup
- Owner/author: Recoup
- Install path: @recoup
- recoupable.com URLs, agent@recoupable.com, recoupable/skills repo
  path, @recoupable/cli npm package, and LICENSE entity stay unchanged.

After this lands
  /plugin marketplace add recoupable/skills
  /plugin install recoup-skills@recoup

Why this is small enough to review
- 13 files, +961 / -137. All-new infrastructure, zero behavior change
  for end users (no skill paths under skills/ moved).
- Generated files are mechanically derivable from marketplace.source.json.
  Spot-check the source file; trust the generator.

What's intentionally NOT in this PR
- No catalog plugin (separate PR — adds plugins/music-catalog-diligence/
  directory and registers it in marketplace.source.json).
- No getting-started orchestrator rewrite (separate PR).

Test plan
- python3 scripts/generate-marketplaces.py --check → exit 0
- python3 scripts/validate-manifests.py            → exit 0

Replaces #23 (split into 3 PRs; rename baked into each).

Co-authored-by: Cursor <cursoragent@cursor.com>
sidneyswift added a commit that referenced this pull request May 13, 2026
…nding)

Sets up the single-source-of-truth marketplace pattern. After this lands,
adding a new plugin is one entry in marketplace.source.json + a regen.
No end-user behavior change yet — this PR ships the infrastructure only.

What this PR adds
- marketplace.source.json — single source of truth for the marketplace
  + the recoup-skills virtual plugin (the existing 12 broad music skills).
- scripts/generate-marketplaces.py — emits the three platform manifests:
  .claude-plugin/marketplace.json, .agents/plugins/marketplace.json,
  .cursor-plugin/marketplace.json. --check mode detects drift.
- scripts/validate-manifests.py — checks generator parity, plugin source
  paths, .claude/.codex/.cursor plugin manifests on each plugins/ folder,
  and SKILL.md frontmatter (name + description) on every skill.
- .github/workflows/validate.yml — runs both scripts on every PR.
- AGENTS.md, README.md, contributing.md, CHANGELOG.md — describe the
  source-of-truth + generated-files pattern (with recoup branding).
- Removes the now-superseded root .claude-plugin/plugin.json and
  .codex-plugin/plugin.json (the recoup-skills virtual plugin entry
  in the marketplace replaces them).

Branding
- Marketplace name: recoup
- Plugin name: recoup-skills
- Display names: Recoup Skills, developerName: Recoup
- Owner/author: Recoup
- Install path: @recoup
- recoupable.com URLs, agent@recoupable.com, recoupable/skills repo
  path, @recoupable/cli npm package, and LICENSE entity stay unchanged.

After this lands
  /plugin marketplace add recoupable/skills
  /plugin install recoup-skills@recoup

Why this is small enough to review
- 13 files, +961 / -137. All-new infrastructure, zero behavior change
  for end users (no skill paths under skills/ moved).
- Generated files are mechanically derivable from marketplace.source.json.
  Spot-check the source file; trust the generator.

What's intentionally NOT in this PR
- No catalog plugin (separate PR — adds plugins/music-catalog-diligence/
  directory and registers it in marketplace.source.json).
- No getting-started orchestrator rewrite (separate PR).

Test plan
- python3 scripts/generate-marketplaces.py --check → exit 0
- python3 scripts/validate-manifests.py            → exit 0

Replaces #23 (split into 3 PRs; rename baked into each).

Co-authored-by: Cursor <cursoragent@cursor.com>
@sidneyswift
Copy link
Copy Markdown
Contributor Author

Renumbered for review order — least-code first. Each PR description is now problem-first and quick to read.

Order PR What it solves Files LOC
1/3 #26 New developers/agents don't know where to start. Old getting-started told them how to install but not what to do next. 3 +299/-87
2/3 #25 Skills + plugins live in 3 separate repos with 9 hand-maintained marketplace files. Customers install 3 marketplaces. 12 +705/-168
3/3 #27 Catalog plugin lives in a separate repo. Customers can't install it from the unified marketplace yet. 113 +8403/-2

Order doesn't constrain merging:

Read in order 1→2→3 for the smallest-to-largest review effort.

@sidneyswift
Copy link
Copy Markdown
Contributor Author

Update: PR 26 closed and replaced by #29 (fix-only).

Decision: PR 26 was doing too much. Two scopes mixed in one PR (fix broken stuff + introduce orchestrator pattern with state detection / persona routing / cache safety). Split.

Order PR Scope Files
1/3 #29 Fix 3 broken bits in main skills (recoup research example, chart-metric install, BYOA auth gap) 4
2/3 #25 Marketplace machinery 12
3/3 #27 Catalog plugin (subtree) 113

Closed: #26 (orchestrator) — branch preserved (feat/orchestrator). Will land as a separate follow-up PR after #29 / #25 / #27 merge.

Order doesn't constrain merging:

Read 1 → 2 → 3 for smallest-to-largest review effort.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant