From 4f8d90e567bb7a84e50e02690ac76431bcfa24c8 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Sat, 10 Oct 2026 19:55:43 -0400 Subject: [PATCH 1/2] feat: publish plugins to Cursor alongside Claude Code Signed-off-by: Yordis Prieto --- .agents/skills/scaffold-plugin/SKILL.md | 51 ++++- .cursor-plugin/marketplace.json | 61 ++++++ .github/release-please-config.json | 5 + .github/workflows/validate-plugins.yml | 7 + CONTRIBUTING.md | 2 +- README.md | 2 + .../.cursor-plugin/plugin.json | 23 ++ .../.cursor-plugin/plugin.json | 25 +++ .../.cursor-plugin/plugin.json | 23 ++ .../.cursor-plugin/plugin.json | 25 +++ .../.cursor-plugin/plugin.json | 25 +++ .../.cursor-plugin/plugin.json | 25 +++ .../trogonstack-gh/.cursor-plugin/plugin.json | 25 +++ .../.cursor-plugin/plugin.json | 23 ++ .../.cursor-plugin/plugin.json | 25 +++ .../.cursor-plugin/plugin.json | 25 +++ schemas/cursor-plugin/marketplace.schema.json | 115 ++++++++++ schemas/cursor-plugin/plugin.schema.json | 196 ++++++++++++++++++ scripts/validate-plugins.mjs | 91 ++++++++ 19 files changed, 766 insertions(+), 8 deletions(-) create mode 100644 .cursor-plugin/marketplace.json create mode 100644 plugins/trogonstack-ask/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-datadog/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-diataxis/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-eda/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-elixir/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-eventmodeling/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-gh/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-nats/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-otel/.cursor-plugin/plugin.json create mode 100644 plugins/trogonstack-product-requirements/.cursor-plugin/plugin.json create mode 100644 schemas/cursor-plugin/marketplace.schema.json create mode 100644 schemas/cursor-plugin/plugin.schema.json diff --git a/.agents/skills/scaffold-plugin/SKILL.md b/.agents/skills/scaffold-plugin/SKILL.md index 40bdd5f..d686ef9 100644 --- a/.agents/skills/scaffold-plugin/SKILL.md +++ b/.agents/skills/scaffold-plugin/SKILL.md @@ -46,6 +46,8 @@ Ask for a one-line description if not already provided. plugins/{plugin-name}/ ├── .claude-plugin/ │ └── plugin.json +├── .cursor-plugin/ +│ └── plugin.json ├── skills/ (empty, ready for skills) └── README.md ``` @@ -66,7 +68,30 @@ Do NOT create a CHANGELOG.md — release-please manages that automatically. } ``` -### 4. Create README.md +### 4. Create Cursor plugin.json + +Create `plugins/{plugin-name}/.cursor-plugin/plugin.json`. The `name`, `description`, and `version` must match `.claude-plugin/plugin.json` exactly. The file must satisfy `schemas/cursor-plugin/plugin.schema.json`, which rejects unknown fields such as `author.url`. + +```json +{ + "name": "{plugin-name}", + "displayName": "TrogonStack {Human Name}", + "description": "{description}", + "version": "0.0.1", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/{plugin-name}", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": ["trogonstack", "{topic}"], + "category": "developer-tools", + "tags": ["{topic}"], + "skills": "./skills/" +} +``` + +### 5. Create README.md ````markdown # {plugin-name} @@ -78,7 +103,7 @@ claude plugin install {plugin-name}@trogonstack ``` ```` -### 5. Register in Marketplace +### 6. Register in Marketplaces Add an entry to `.claude-plugin/marketplace.json` in the `plugins` array: @@ -91,7 +116,17 @@ Add an entry to `.claude-plugin/marketplace.json` in the `plugins` array: } ``` -### 6. Register in Release Please Config +Add an entry to `.cursor-plugin/marketplace.json` in the `plugins` array, with the same description as the Claude marketplace entry: + +```json +{ + "name": "{plugin-name}", + "source": "plugins/{plugin-name}", + "description": "{description}" +} +``` + +### 7. Register in Release Please Config Add the package to `.github/release-please-config.json` in the `packages` object: @@ -101,7 +136,7 @@ Add the package to `.github/release-please-config.json` in the `packages` object } ``` -### 7. Register in Release Please Manifest +### 8. Register in Release Please Manifest Add the initial version to `.github/release-please-manifest.json`: @@ -111,7 +146,7 @@ Add the initial version to `.github/release-please-manifest.json`: It must be `0.0.1`. -### 8. Commit +### 9. Commit Use conventional commit format: @@ -123,10 +158,12 @@ feat({plugin-name}): scaffold plugin for {short purpose} - [ ] Plugin directory exists at `plugins/{plugin-name}/` - [ ] `plugins/{plugin-name}/.claude-plugin/plugin.json` exists with correct name, description, version `0.0.1`, and author +- [ ] `plugins/{plugin-name}/.cursor-plugin/plugin.json` exists with name, description, and version matching the Claude manifest - [ ] `plugins/{plugin-name}/README.md` exists with install command - [ ] `plugins/{plugin-name}/skills/` directory exists (empty) - [ ] No CHANGELOG.md was created -- [ ] `.claude-plugin/marketplace.json` has the new plugin entry +- [ ] `.claude-plugin/marketplace.json` and `.cursor-plugin/marketplace.json` have the new plugin entry +- [ ] `node scripts/validate-plugins.mjs` passes - [ ] `.github/release-please-config.json` has the new package - [ ] `.github/release-please-manifest.json` has the new version entry at `0.0.1` -- [ ] Description is consistent across plugin.json, marketplace.json, and README.md +- [ ] Description is consistent across both plugin.json files, both marketplace.json files, and README.md diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json new file mode 100644 index 0000000..9747c8c --- /dev/null +++ b/.cursor-plugin/marketplace.json @@ -0,0 +1,61 @@ +{ + "name": "trogonstack", + "owner": { + "name": "TrogonStack" + }, + "metadata": { + "description": "Plugins by TrogonStack for Cursor" + }, + "plugins": [ + { + "name": "trogonstack-diataxis", + "source": "plugins/trogonstack-diataxis", + "description": "Documentation skills following the Diataxis framework for organizing and generating docs into tutorials, how-to guides, reference, and explanation sections" + }, + { + "name": "trogonstack-gh", + "source": "plugins/trogonstack-gh", + "description": "GitHub workflow skills for enriching PR descriptions, automating code review context, and streamlining collaboration through the gh CLI" + }, + { + "name": "trogonstack-nats", + "source": "plugins/trogonstack-nats", + "description": "NATS messaging skills for designing subject hierarchies with naming conventions and wildcard patterns" + }, + { + "name": "trogonstack-datadog", + "source": "plugins/trogonstack-datadog", + "description": "Datadog observability skills for designing dashboards with proper widget selection, layout patterns, and template variables using the pup CLI, and for checking metrics against Datadog's no-cost metrics" + }, + { + "name": "trogonstack-ask", + "source": "plugins/trogonstack-ask", + "description": "Structured question-asking skill for gathering requirements and context through deliberate, one-at-a-time questions" + }, + { + "name": "trogonstack-otel", + "source": "plugins/trogonstack-otel", + "description": "OpenTelemetry skills for naming metrics and spans following OTel Semantic Conventions" + }, + { + "name": "trogonstack-eventmodeling", + "source": "plugins/trogonstack-eventmodeling", + "description": "Event Modeling skills for brainstorming, designing, slicing, and validating software systems following the Event Modeling methodology" + }, + { + "name": "trogonstack-eda", + "source": "plugins/trogonstack-eda", + "description": "Event-driven architecture skills for designing event names, schemas, contracts, and catalogs following good practices for domain and integration events" + }, + { + "name": "trogonstack-product-requirements", + "source": "plugins/trogonstack-product-requirements", + "description": "Skills for writing and reviewing Product Requirements Documents (PRDs) and Feature Requirements Documents (FRDs)" + }, + { + "name": "trogonstack-elixir", + "source": "plugins/trogonstack-elixir", + "description": "Elixir skills for designing and reviewing OTP processes such as GenServers" + } + ] +} diff --git a/.github/release-please-config.json b/.github/release-please-config.json index 32473e3..372031b 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -9,6 +9,11 @@ "type": "json", "path": ".claude-plugin/plugin.json", "jsonpath": "$.version" + }, + { + "type": "json", + "path": ".cursor-plugin/plugin.json", + "jsonpath": "$.version" } ], "changelog-sections": [ diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml index 1ae553e..7cd5dad 100644 --- a/.github/workflows/validate-plugins.yml +++ b/.github/workflows/validate-plugins.yml @@ -5,6 +5,8 @@ on: paths: - "plugins/**" - ".claude-plugin/marketplace.json" + - ".cursor-plugin/marketplace.json" + - "schemas/cursor-plugin/**" - ".github/release-please-config.json" - ".github/release-please-manifest.json" - "scripts/validate-plugins.mjs" @@ -18,5 +20,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 + with: + node-version: 24 + - name: Install schema validator + run: npm install --no-save ajv@8 ajv-formats@3 - name: Validate plugin registrations run: node scripts/validate-plugins.mjs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1ed79f..22ab4a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,4 +26,4 @@ Releases are automated via release-please: 2. Release-please creates/updates a "Release PR" with changelog and version bump 3. Merge the Release PR to publish a new version -The version in `.claude-plugin/plugin.json` is automatically updated when a release is published. +The version in `.claude-plugin/plugin.json` and `.cursor-plugin/plugin.json` is automatically updated when a release is published. diff --git a/README.md b/README.md index ae7204f..4a4d9b3 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ claude plugin marketplace add TrogonStack/agentskills claude plugin install {plugin-name}@trogonstack ``` +In Cursor, import `https://github.com/TrogonStack/agentskills` as a team marketplace from **Dashboard > Plugins & MCPs > Team Marketplaces > Add Marketplace > Import from Repo**, then install plugins from **Customize** in the sidebar. + See all available plugins under [plugins](./plugins) directory. ## Contributing diff --git a/plugins/trogonstack-ask/.cursor-plugin/plugin.json b/plugins/trogonstack-ask/.cursor-plugin/plugin.json new file mode 100644 index 0000000..97b6843 --- /dev/null +++ b/plugins/trogonstack-ask/.cursor-plugin/plugin.json @@ -0,0 +1,23 @@ +{ + "name": "trogonstack-ask", + "displayName": "TrogonStack Ask", + "description": "Structured question-asking skill for gathering requirements and context through deliberate, one-at-a-time questions", + "version": "0.2.1", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-ask", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "requirements", + "questions" + ], + "category": "developer-tools", + "tags": [ + "requirements", + "questions" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-datadog/.cursor-plugin/plugin.json b/plugins/trogonstack-datadog/.cursor-plugin/plugin.json new file mode 100644 index 0000000..b94c5a8 --- /dev/null +++ b/plugins/trogonstack-datadog/.cursor-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "trogonstack-datadog", + "displayName": "TrogonStack Datadog", + "description": "Datadog observability skills for designing, redesigning, and auditing dashboards with proper widget selection, layout patterns, template variables, and operational readiness validation using the pup CLI, and for checking metrics against Datadog's no-cost metrics before creating custom ones", + "version": "0.4.0", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-datadog", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "datadog", + "observability", + "dashboards" + ], + "category": "developer-tools", + "tags": [ + "datadog", + "observability", + "dashboards" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-diataxis/.cursor-plugin/plugin.json b/plugins/trogonstack-diataxis/.cursor-plugin/plugin.json new file mode 100644 index 0000000..9c6ef5c --- /dev/null +++ b/plugins/trogonstack-diataxis/.cursor-plugin/plugin.json @@ -0,0 +1,23 @@ +{ + "name": "trogonstack-diataxis", + "displayName": "TrogonStack Diátaxis", + "description": "Documentation skills following the Diataxis framework for organizing and generating docs into tutorials, how-to guides, reference, and explanation sections", + "version": "0.1.0", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-diataxis", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "documentation", + "diataxis" + ], + "category": "developer-tools", + "tags": [ + "documentation", + "diataxis" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-eda/.cursor-plugin/plugin.json b/plugins/trogonstack-eda/.cursor-plugin/plugin.json new file mode 100644 index 0000000..9f5f18e --- /dev/null +++ b/plugins/trogonstack-eda/.cursor-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "trogonstack-eda", + "displayName": "TrogonStack Event-Driven Architecture", + "description": "Event-driven architecture skills for designing event definitions, schemas, contracts, and catalogs following good practices for domain and integration events", + "version": "0.1.2", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-eda", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "event-driven-architecture", + "events", + "schemas" + ], + "category": "developer-tools", + "tags": [ + "event-driven-architecture", + "events", + "schemas" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-elixir/.cursor-plugin/plugin.json b/plugins/trogonstack-elixir/.cursor-plugin/plugin.json new file mode 100644 index 0000000..e652b98 --- /dev/null +++ b/plugins/trogonstack-elixir/.cursor-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "trogonstack-elixir", + "displayName": "TrogonStack Elixir", + "description": "Elixir skills for designing and reviewing OTP processes such as GenServers", + "version": "0.1.0", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-elixir", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "elixir", + "otp", + "genserver" + ], + "category": "developer-tools", + "tags": [ + "elixir", + "otp", + "genserver" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-eventmodeling/.cursor-plugin/plugin.json b/plugins/trogonstack-eventmodeling/.cursor-plugin/plugin.json new file mode 100644 index 0000000..76d25e8 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/.cursor-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "trogonstack-eventmodeling", + "displayName": "TrogonStack Event Modeling", + "description": "Event Modeling skills for brainstorming, designing, slicing, and validating software systems following the Event Modeling methodology", + "version": "0.1.2", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-eventmodeling", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "event-modeling", + "event-sourcing", + "design" + ], + "category": "developer-tools", + "tags": [ + "event-modeling", + "event-sourcing", + "design" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-gh/.cursor-plugin/plugin.json b/plugins/trogonstack-gh/.cursor-plugin/plugin.json new file mode 100644 index 0000000..eff90dd --- /dev/null +++ b/plugins/trogonstack-gh/.cursor-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "trogonstack-gh", + "displayName": "TrogonStack GitHub", + "description": "GitHub workflow skills for enriching PR descriptions, automating code review context, and streamlining collaboration through the gh CLI", + "version": "0.0.2", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-gh", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "github", + "pull-requests", + "code-review" + ], + "category": "developer-tools", + "tags": [ + "github", + "pull-requests", + "code-review" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-nats/.cursor-plugin/plugin.json b/plugins/trogonstack-nats/.cursor-plugin/plugin.json new file mode 100644 index 0000000..621b71d --- /dev/null +++ b/plugins/trogonstack-nats/.cursor-plugin/plugin.json @@ -0,0 +1,23 @@ +{ + "name": "trogonstack-nats", + "displayName": "TrogonStack NATS", + "description": "NATS messaging skills for designing subject hierarchies with naming conventions and wildcard patterns", + "version": "0.1.3", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-nats", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "nats", + "messaging" + ], + "category": "developer-tools", + "tags": [ + "nats", + "messaging" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-otel/.cursor-plugin/plugin.json b/plugins/trogonstack-otel/.cursor-plugin/plugin.json new file mode 100644 index 0000000..210c90f --- /dev/null +++ b/plugins/trogonstack-otel/.cursor-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "trogonstack-otel", + "displayName": "TrogonStack OpenTelemetry", + "description": "OpenTelemetry skills for naming metrics and spans following OTel Semantic Conventions", + "version": "0.1.2", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-otel", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "opentelemetry", + "observability", + "semantic-conventions" + ], + "category": "developer-tools", + "tags": [ + "opentelemetry", + "observability", + "semantic-conventions" + ], + "skills": "./skills/" +} diff --git a/plugins/trogonstack-product-requirements/.cursor-plugin/plugin.json b/plugins/trogonstack-product-requirements/.cursor-plugin/plugin.json new file mode 100644 index 0000000..74b5fca --- /dev/null +++ b/plugins/trogonstack-product-requirements/.cursor-plugin/plugin.json @@ -0,0 +1,25 @@ +{ + "name": "trogonstack-product-requirements", + "displayName": "TrogonStack Product Requirements", + "description": "Skills for writing and reviewing Product Requirements Documents (PRDs) and Feature Requirements Documents (FRDs)", + "version": "0.1.1", + "author": { + "name": "TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-product-requirements", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "prd", + "frd", + "product" + ], + "category": "developer-tools", + "tags": [ + "prd", + "frd", + "product" + ], + "skills": "./skills/" +} diff --git a/schemas/cursor-plugin/marketplace.schema.json b/schemas/cursor-plugin/marketplace.schema.json new file mode 100644 index 0000000..8d69bb1 --- /dev/null +++ b/schemas/cursor-plugin/marketplace.schema.json @@ -0,0 +1,115 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://cursor.com/schemas/cursor-plugin/marketplace.json", + "title": "Cursor Plugin Marketplace", + "description": "Schema for .cursor-plugin/marketplace.json — defines a marketplace that indexes one or more Cursor plugins.", + "type": "object", + "required": ["name", "plugins"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Unique identifier for the marketplace." + }, + "owner": { + "$ref": "#/$defs/owner", + "description": "The marketplace owner or organisation." + }, + "metadata": { + "type": "object", + "additionalProperties": true, + "properties": { + "description": { + "type": "string", + "description": "Short description of the marketplace." + } + }, + "description": "Arbitrary metadata about the marketplace." + }, + "plugins": { + "type": "array", + "items": { "$ref": "#/$defs/pluginEntry" }, + "description": "List of plugins available in the marketplace." + } + }, + "$defs": { + "owner": { + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Owner or organisation name." + }, + "email": { + "type": "string", + "format": "email", + "description": "Contact email address." + } + } + }, + "pluginEntry": { + "type": "object", + "required": ["name", "source"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "pattern": "^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$", + "description": "Plugin identifier matching the plugin's name in its plugin.json." + }, + "source": { + "type": "string", + "minLength": 1, + "description": "Path to the plugin directory (relative to the marketplace root) or a remote URL." + }, + "description": { + "type": "string", + "description": "Short description of the plugin." + }, + "minClientVersions": { + "$ref": "#/$defs/minClientVersions", + "description": "Minimum client versions required to install the plugin, keyed by client identifier." + } + } + }, + "minClientVersions": { + "type": "object", + "minProperties": 1, + "properties": { + "cursor": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Minimum Cursor version required to install the plugin (e.g. \"3.13.0\"), or \"never\" to hide it from Cursor entirely." + }, + "grokbot": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Minimum Grok Bot version required to install the plugin (e.g. \"0.49.0\"), or \"never\" to hide it from Grok Bot entirely." + }, + "sand": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Deprecated client id for Grok Bot. Same meaning as grokbot." + } + }, + "additionalProperties": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Minimum version required for another client identifier, or \"never\" to hide the plugin from that client." + } + }, + "clientVersionRequirement": { + "description": "A minimum semantic version, or the literal \"never\" when that client must not list or install the plugin.", + "oneOf": [ + { "$ref": "#/$defs/semver" }, + { "const": "never" } + ] + }, + "semver": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$", + "description": "Strict semantic version \"X.Y.Z\" with an optional prerelease suffix." + } + } +} diff --git a/schemas/cursor-plugin/plugin.schema.json b/schemas/cursor-plugin/plugin.schema.json new file mode 100644 index 0000000..02903d1 --- /dev/null +++ b/schemas/cursor-plugin/plugin.schema.json @@ -0,0 +1,196 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://cursor.com/schemas/cursor-plugin/plugin.json", + "title": "Cursor Plugin Manifest", + "description": "Schema for .cursor-plugin/plugin.json — defines a single Cursor plugin's metadata, components, and configuration.", + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "pattern": "^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$", + "description": "Unique plugin identifier in kebab-case (lowercase alphanumeric with hyphens and periods)." + }, + "displayName": { + "type": "string", + "description": "Human-readable display name for the plugin." + }, + "description": { + "type": "string", + "description": "Short description of what the plugin does." + }, + "version": { + "type": "string", + "description": "Semantic version of the plugin (e.g. \"1.2.3\")." + }, + "minClientVersions": { + "$ref": "#/$defs/minClientVersions", + "description": "Minimum client versions required to install the plugin, keyed by client identifier." + }, + "author": { + "$ref": "#/$defs/author", + "description": "The plugin author." + }, + "publisher": { + "type": "string", + "minLength": 1, + "description": "Publisher or organisation name." + }, + "homepage": { + "type": "string", + "format": "uri", + "description": "URL to the plugin's homepage." + }, + "repository": { + "type": "string", + "format": "uri", + "description": "URL to the plugin's source code repository." + }, + "license": { + "type": "string", + "description": "SPDX license identifier (e.g. \"MIT\", \"Apache-2.0\")." + }, + "logo": { + "type": "string", + "description": "Path to a logo image (relative to the plugin root) or an absolute URL." + }, + "keywords": { + "type": "array", + "items": { "type": "string" }, + "description": "Keywords for discovery and search." + }, + "category": { + "type": "string", + "description": "Plugin category for marketplace classification." + }, + "tags": { + "type": "array", + "items": { "type": "string" }, + "description": "Tags for filtering and discovery." + }, + "commands": { + "$ref": "#/$defs/stringOrStringArray", + "description": "Glob pattern(s) or path(s) to command files." + }, + "agents": { + "$ref": "#/$defs/stringOrStringArray", + "description": "Glob pattern(s) or path(s) to agent definition files." + }, + "skills": { + "$ref": "#/$defs/stringOrStringArray", + "description": "Glob pattern(s) or path(s) to skill files." + }, + "rules": { + "$ref": "#/$defs/stringOrStringArray", + "description": "Glob pattern(s) or path(s) to rule files." + }, + "hooks": { + "oneOf": [ + { "type": "string" }, + { "type": "object" } + ], + "description": "Path to a hooks configuration file, or an inline hooks object." + }, + "variables": { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "const": "object" + }, + "properties": { + "type": "object" + }, + "required": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + } + }, + "description": "JSON Schema for user-configured plugin variables." + }, + "mcpServers": { + "$ref": "#/$defs/mcpServers", + "description": "MCP server configuration — a path, an inline config object, or an array of either." + } + }, + "$defs": { + "author": { + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Author name." + }, + "email": { + "type": "string", + "format": "email", + "description": "Author email address." + } + } + }, + "minClientVersions": { + "type": "object", + "minProperties": 1, + "properties": { + "cursor": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Minimum Cursor version required to install the plugin (e.g. \"3.13.0\"), or \"never\" to hide it from Cursor entirely." + }, + "grokbot": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Minimum Grok Bot version required to install the plugin (e.g. \"0.49.0\"), or \"never\" to hide it from Grok Bot entirely." + }, + "sand": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Deprecated client id for Grok Bot. Same meaning as grokbot." + } + }, + "additionalProperties": { + "$ref": "#/$defs/clientVersionRequirement", + "description": "Minimum version required for another client identifier, or \"never\" to hide the plugin from that client." + } + }, + "clientVersionRequirement": { + "description": "A minimum semantic version, or the literal \"never\" when that client must not list or install the plugin.", + "oneOf": [ + { "$ref": "#/$defs/semver" }, + { "const": "never" } + ] + }, + "semver": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$", + "description": "Strict semantic version \"X.Y.Z\" with an optional prerelease suffix." + }, + "stringOrStringArray": { + "oneOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" } + } + ] + }, + "mcpServers": { + "oneOf": [ + { "type": "string" }, + { "type": "object" }, + { + "type": "array", + "items": { + "oneOf": [ + { "type": "string" }, + { "type": "object" } + ] + } + } + ] + } + } +} diff --git a/scripts/validate-plugins.mjs b/scripts/validate-plugins.mjs index 8ada032..53e45ce 100644 --- a/scripts/validate-plugins.mjs +++ b/scripts/validate-plugins.mjs @@ -6,6 +6,8 @@ import { fileURLToPath } from "node:url"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const pluginsDir = join(repoRoot, "plugins"); const marketplacePath = join(repoRoot, ".claude-plugin", "marketplace.json"); +const cursorMarketplacePath = join(repoRoot, ".cursor-plugin", "marketplace.json"); +const cursorSchemasDir = join(repoRoot, "schemas", "cursor-plugin"); const configPath = join(repoRoot, ".github", "release-please-config.json"); const manifestPath = join(repoRoot, ".github", "release-please-manifest.json"); @@ -24,12 +26,16 @@ const readJson = (path) => { const semverRe = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/; const marketplace = readJson(marketplacePath); +const cursorMarketplace = readJson(cursorMarketplacePath); const config = readJson(configPath); const manifest = readJson(manifestPath); const marketplaceByName = new Map( (marketplace?.plugins ?? []).map((p) => [p.name, p]) ); +const cursorMarketplaceByName = new Map( + (cursorMarketplace?.plugins ?? []).map((p) => [p.name, p]) +); const configPackages = config?.packages ?? {}; const manifestPackages = manifest ?? {}; @@ -40,6 +46,41 @@ const pluginDirs = readdirSync(pluginsDir).filter((entry) => { const expectedPath = (name) => `plugins/${name}`; +let Ajv, addFormats; +try { + ({ default: Ajv } = await import("ajv")); + ({ default: addFormats } = await import("ajv-formats")); +} catch { + console.error("Missing dependencies: run `npm install --no-save ajv@8 ajv-formats@3` first."); + process.exit(1); +} +const ajv = new Ajv({ allErrors: true, strict: false }); +addFormats(ajv); +const validateCursorPlugin = ajv.compile( + readJson(join(cursorSchemasDir, "plugin.schema.json")) +); +const validateCursorMarketplace = ajv.compile( + readJson(join(cursorSchemasDir, "marketplace.schema.json")) +); +const schemaErrors = (validate) => + (validate.errors ?? []).map((e) => `${e.instancePath || "/"} ${e.message}`).join("; "); + +if (cursorMarketplace && !validateCursorMarketplace(cursorMarketplace)) { + fail(`.cursor-plugin/marketplace.json: ${schemaErrors(validateCursorMarketplace)}`); +} +if (marketplace && cursorMarketplace && marketplace.name !== cursorMarketplace.name) { + fail( + `.cursor-plugin/marketplace.json name "${cursorMarketplace.name}" does not match .claude-plugin/marketplace.json name "${marketplace.name}"` + ); +} + +const extraFilePaths = new Set((config?.["extra-files"] ?? []).map((f) => f.path)); +for (const path of [".claude-plugin/plugin.json", ".cursor-plugin/plugin.json"]) { + if (!extraFilePaths.has(path)) { + fail(`release-please-config.json extra-files is missing "${path}", its version would drift on release`); + } +} + for (const name of pluginDirs) { const pluginJsonPath = join(pluginsDir, name, ".claude-plugin", "plugin.json"); if (!existsSync(pluginJsonPath)) { @@ -69,6 +110,50 @@ for (const name of pluginDirs) { ); } + const cursorPluginJsonPath = join(pluginsDir, name, ".cursor-plugin", "plugin.json"); + if (!existsSync(cursorPluginJsonPath)) { + fail(`plugins/${name}: missing .cursor-plugin/plugin.json`); + } else { + const cursorPluginJson = readJson(cursorPluginJsonPath); + if (cursorPluginJson) { + if (!validateCursorPlugin(cursorPluginJson)) { + fail(`plugins/${name}/.cursor-plugin/plugin.json: ${schemaErrors(validateCursorPlugin)}`); + } + for (const field of ["name", "version", "description"]) { + if (cursorPluginJson[field] !== pluginJson[field]) { + fail( + `plugins/${name}: .cursor-plugin/plugin.json ${field} "${cursorPluginJson[field]}" does not match .claude-plugin/plugin.json ${field} "${pluginJson[field]}"` + ); + } + } + const skillPaths = [cursorPluginJson.skills ?? []].flat(); + if (skillPaths.length === 0) { + fail(`plugins/${name}: .cursor-plugin/plugin.json does not declare "skills"`); + } + for (const skillPath of skillPaths) { + if (!existsSync(join(pluginsDir, name, skillPath))) { + fail(`plugins/${name}: .cursor-plugin/plugin.json skills path "${skillPath}" does not exist`); + } + } + } + } + + const cmp = cursorMarketplaceByName.get(name); + if (!cmp) { + fail(`plugins/${name}: not listed in .cursor-plugin/marketplace.json`); + } else { + if (cmp.source !== `plugins/${name}`) { + fail( + `plugins/${name}: .cursor-plugin/marketplace.json source "${cmp.source}" should be "plugins/${name}"` + ); + } + if (mp && cmp.description !== mp.description) { + fail( + `plugins/${name}: .cursor-plugin/marketplace.json description does not match .claude-plugin/marketplace.json` + ); + } + } + const key = expectedPath(name); if (!configPackages[key]) { fail(`plugins/${name}: missing entry "${key}" in release-please-config.json packages`); @@ -95,6 +180,12 @@ for (const mp of marketplace?.plugins ?? []) { } } +for (const cmp of cursorMarketplace?.plugins ?? []) { + if (!pluginSet.has(cmp.name)) { + fail(`.cursor-plugin/marketplace.json references "${cmp.name}" but plugins/${cmp.name} does not exist`); + } +} + for (const key of Object.keys(configPackages)) { const name = key.replace(/^plugins\//, ""); if (!pluginSet.has(name)) { From d7b527d1f24f8ed00799c5c8faa214b93e49b489 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Sat, 10 Oct 2026 20:01:05 -0400 Subject: [PATCH 2/2] docs: cover Cursor installs outside team plans Signed-off-by: Yordis Prieto --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a4d9b3..4e04bb2 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,15 @@ claude plugin marketplace add TrogonStack/agentskills claude plugin install {plugin-name}@trogonstack ``` -In Cursor, import `https://github.com/TrogonStack/agentskills` as a team marketplace from **Dashboard > Plugins & MCPs > Team Marketplaces > Add Marketplace > Import from Repo**, then install plugins from **Customize** in the sidebar. +In Cursor on a Teams or Enterprise plan, import `https://github.com/TrogonStack/agentskills` as a team marketplace from **Dashboard > Plugins & MCPs > Team Marketplaces > Add Marketplace > Import from Repo**, then install plugins from **Customize** in the sidebar. + +On other Cursor plans, copy a plugin into the local plugins directory and restart Cursor: + +```bash +git clone https://github.com/TrogonStack/agentskills +mkdir -p ~/.cursor/plugins/local +cp -R agentskills/plugins/{plugin-name} ~/.cursor/plugins/local/ +``` See all available plugins under [plugins](./plugins) directory.