diff --git a/.agents/skills/scaffold-plugin/SKILL.md b/.agents/skills/scaffold-plugin/SKILL.md index d686ef9..7e92767 100644 --- a/.agents/skills/scaffold-plugin/SKILL.md +++ b/.agents/skills/scaffold-plugin/SKILL.md @@ -48,6 +48,7 @@ plugins/{plugin-name}/ │ └── plugin.json ├── .cursor-plugin/ │ └── plugin.json +├── plugin.json (Agent Plugins manifest) ├── skills/ (empty, ready for skills) └── README.md ``` @@ -91,7 +92,28 @@ Create `plugins/{plugin-name}/.cursor-plugin/plugin.json`. The `name`, `descript } ``` -### 5. Create README.md +### 5. Create Agent Plugins plugin.json + +Create `plugins/{plugin-name}/plugin.json` following the [Agent Plugins](https://agent-plugins.org) 1.0.0 spec. The `name`, `description`, and `version` must match `.claude-plugin/plugin.json` exactly, and it must satisfy `schemas/agent-plugins/1.0.0/plugin.schema.json`. Skills are discovered from the fixed `skills/` location, so do not declare component paths. + +```json +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "{plugin-name}", + "version": "0.0.1", + "description": "{description}", + "author": { + "name": "TrogonStack", + "url": "https://github.com/TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/{plugin-name}", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": ["trogonstack", "{topic}"] +} +``` + +### 6. Create README.md ````markdown # {plugin-name} @@ -103,7 +125,7 @@ claude plugin install {plugin-name}@trogonstack ``` ```` -### 6. Register in Marketplaces +### 7. Register in Marketplaces Add an entry to `.claude-plugin/marketplace.json` in the `plugins` array: @@ -126,7 +148,7 @@ Add an entry to `.cursor-plugin/marketplace.json` in the `plugins` array, with t } ``` -### 7. Register in Release Please Config +### 8. Register in Release Please Config Add the package to `.github/release-please-config.json` in the `packages` object: @@ -136,7 +158,7 @@ Add the package to `.github/release-please-config.json` in the `packages` object } ``` -### 8. Register in Release Please Manifest +### 9. Register in Release Please Manifest Add the initial version to `.github/release-please-manifest.json`: @@ -146,7 +168,7 @@ Add the initial version to `.github/release-please-manifest.json`: It must be `0.0.1`. -### 9. Commit +### 10. Commit Use conventional commit format: @@ -159,6 +181,7 @@ 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}/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 @@ -166,4 +189,4 @@ feat({plugin-name}): scaffold plugin for {short purpose} - [ ] `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 both plugin.json files, both marketplace.json files, and README.md +- [ ] Description is consistent across all three plugin.json files, both marketplace.json files, and README.md diff --git a/.github/release-please-config.json b/.github/release-please-config.json index 372031b..c390924 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -14,6 +14,11 @@ "type": "json", "path": ".cursor-plugin/plugin.json", "jsonpath": "$.version" + }, + { + "type": "json", + "path": "plugin.json", + "jsonpath": "$.version" } ], "changelog-sections": [ diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml index 7cd5dad..61f6ba2 100644 --- a/.github/workflows/validate-plugins.yml +++ b/.github/workflows/validate-plugins.yml @@ -6,7 +6,7 @@ on: - "plugins/**" - ".claude-plugin/marketplace.json" - ".cursor-plugin/marketplace.json" - - "schemas/cursor-plugin/**" + - "schemas/**" - ".github/release-please-config.json" - ".github/release-please-manifest.json" - "scripts/validate-plugins.mjs" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 22ab4a0..c8e1788 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` and `.cursor-plugin/plugin.json` is automatically updated when a release is published. +The version in `.claude-plugin/plugin.json`, `.cursor-plugin/plugin.json`, and `plugin.json` is automatically updated when a release is published. diff --git a/README.md b/README.md index 4e04bb2..3db2386 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ claude plugin install {plugin-name}@trogonstack 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. +Each plugin also ships a root `plugin.json` following the [Agent Plugins](https://agent-plugins.org) 1.0.0 spec, for any client that supports it. + On other Cursor plans, copy a plugin into the local plugins directory and restart Cursor: ```bash diff --git a/plugins/trogonstack-ask/plugin.json b/plugins/trogonstack-ask/plugin.json new file mode 100644 index 0000000..ab8e4e4 --- /dev/null +++ b/plugins/trogonstack-ask/plugin.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-ask", + "version": "0.2.1", + "description": "Structured question-asking skill for gathering requirements and context through deliberate, one-at-a-time questions", + "author": { + "name": "TrogonStack", + "url": "https://github.com/TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-ask", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "requirements", + "questions" + ] +} diff --git a/plugins/trogonstack-datadog/plugin.json b/plugins/trogonstack-datadog/plugin.json new file mode 100644 index 0000000..1f16254 --- /dev/null +++ b/plugins/trogonstack-datadog/plugin.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-datadog", + "version": "0.4.0", + "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", + "author": { + "name": "TrogonStack", + "url": "https://github.com/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" + ] +} diff --git a/plugins/trogonstack-diataxis/plugin.json b/plugins/trogonstack-diataxis/plugin.json new file mode 100644 index 0000000..4cbc9ec --- /dev/null +++ b/plugins/trogonstack-diataxis/plugin.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-diataxis", + "version": "0.1.0", + "description": "Documentation skills following the Diataxis framework for organizing and generating docs into tutorials, how-to guides, reference, and explanation sections", + "author": { + "name": "TrogonStack", + "url": "https://github.com/TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-diataxis", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "documentation", + "diataxis" + ] +} diff --git a/plugins/trogonstack-eda/plugin.json b/plugins/trogonstack-eda/plugin.json new file mode 100644 index 0000000..c6ad430 --- /dev/null +++ b/plugins/trogonstack-eda/plugin.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-eda", + "version": "0.1.2", + "description": "Event-driven architecture skills for designing event definitions, schemas, contracts, and catalogs following good practices for domain and integration events", + "author": { + "name": "TrogonStack", + "url": "https://github.com/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" + ] +} diff --git a/plugins/trogonstack-elixir/plugin.json b/plugins/trogonstack-elixir/plugin.json new file mode 100644 index 0000000..27651c0 --- /dev/null +++ b/plugins/trogonstack-elixir/plugin.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-elixir", + "version": "0.1.0", + "description": "Elixir skills for designing and reviewing OTP processes such as GenServers", + "author": { + "name": "TrogonStack", + "url": "https://github.com/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" + ] +} diff --git a/plugins/trogonstack-eventmodeling/plugin.json b/plugins/trogonstack-eventmodeling/plugin.json new file mode 100644 index 0000000..5188142 --- /dev/null +++ b/plugins/trogonstack-eventmodeling/plugin.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-eventmodeling", + "version": "0.1.2", + "description": "Event Modeling skills for brainstorming, designing, slicing, and validating software systems following the Event Modeling methodology", + "author": { + "name": "TrogonStack", + "url": "https://github.com/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" + ] +} diff --git a/plugins/trogonstack-gh/plugin.json b/plugins/trogonstack-gh/plugin.json new file mode 100644 index 0000000..f72c0ea --- /dev/null +++ b/plugins/trogonstack-gh/plugin.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-gh", + "version": "0.0.2", + "description": "GitHub workflow skills for enriching PR descriptions, automating code review context, and streamlining collaboration through the gh CLI", + "author": { + "name": "TrogonStack", + "url": "https://github.com/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" + ] +} diff --git a/plugins/trogonstack-nats/plugin.json b/plugins/trogonstack-nats/plugin.json new file mode 100644 index 0000000..3444d33 --- /dev/null +++ b/plugins/trogonstack-nats/plugin.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-nats", + "version": "0.1.3", + "description": "NATS messaging skills for designing subject hierarchies with naming conventions and wildcard patterns", + "author": { + "name": "TrogonStack", + "url": "https://github.com/TrogonStack" + }, + "homepage": "https://github.com/TrogonStack/agentskills/tree/main/plugins/trogonstack-nats", + "repository": "https://github.com/TrogonStack/agentskills", + "license": "MIT", + "keywords": [ + "trogonstack", + "nats", + "messaging" + ] +} diff --git a/plugins/trogonstack-otel/plugin.json b/plugins/trogonstack-otel/plugin.json new file mode 100644 index 0000000..019c94d --- /dev/null +++ b/plugins/trogonstack-otel/plugin.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-otel", + "version": "0.1.2", + "description": "OpenTelemetry skills for naming metrics and spans following OTel Semantic Conventions", + "author": { + "name": "TrogonStack", + "url": "https://github.com/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" + ] +} diff --git a/plugins/trogonstack-product-requirements/plugin.json b/plugins/trogonstack-product-requirements/plugin.json new file mode 100644 index 0000000..7bd0b51 --- /dev/null +++ b/plugins/trogonstack-product-requirements/plugin.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "trogonstack-product-requirements", + "version": "0.1.1", + "description": "Skills for writing and reviewing Product Requirements Documents (PRDs) and Feature Requirements Documents (FRDs)", + "author": { + "name": "TrogonStack", + "url": "https://github.com/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" + ] +} diff --git a/schemas/agent-plugins/1.0.0/plugin.schema.json b/schemas/agent-plugins/1.0.0/plugin.schema.json new file mode 100644 index 0000000..8fed0e1 --- /dev/null +++ b/schemas/agent-plugins/1.0.0/plugin.schema.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "title": "Agent Plugins Manifest", + "description": "Machine-readable schema for plugin.json in Agent Plugins 1.0.0. The Agent Plugins specification defines additional semantic and operational requirements.", + "type": "object", + "properties": { + "$schema": { + "const": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "description": "Canonical identifier of the plugin manifest schema for the Agent Plugins version targeted by this document." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "pattern": "^(?!.*(?:--|\\.\\.))[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$", + "description": "Human-readable plugin name." + }, + "version": { + "type": "string" + }, + "description": { + "type": "string" + }, + "author": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "homepage": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "license": { + "type": "string" + }, + "keywords": { + "type": "array", + "items": { + "type": "string" + } + }, + "extensions": { + "type": "object", + "description": "Client-specific manifest data keyed by reverse-domain extension namespace. Agent Plugins assigns no semantics to namespace object contents.", + "additionalProperties": { + "type": "object" + } + } + }, + "required": ["$schema", "name"], + "additionalProperties": false +} diff --git a/scripts/validate-plugins.mjs b/scripts/validate-plugins.mjs index 53e45ce..12d76fc 100644 --- a/scripts/validate-plugins.mjs +++ b/scripts/validate-plugins.mjs @@ -8,6 +8,7 @@ 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 agentPluginsSchemaPath = join(repoRoot, "schemas", "agent-plugins", "1.0.0", "plugin.schema.json"); const configPath = join(repoRoot, ".github", "release-please-config.json"); const manifestPath = join(repoRoot, ".github", "release-please-manifest.json"); @@ -46,9 +47,10 @@ const pluginDirs = readdirSync(pluginsDir).filter((entry) => { const expectedPath = (name) => `plugins/${name}`; -let Ajv, addFormats; +let Ajv, Ajv2020, addFormats; try { ({ default: Ajv } = await import("ajv")); + ({ default: Ajv2020 } = await import("ajv/dist/2020.js")); ({ default: addFormats } = await import("ajv-formats")); } catch { console.error("Missing dependencies: run `npm install --no-save ajv@8 ajv-formats@3` first."); @@ -62,6 +64,9 @@ const validateCursorPlugin = ajv.compile( const validateCursorMarketplace = ajv.compile( readJson(join(cursorSchemasDir, "marketplace.schema.json")) ); +const ajv2020 = new Ajv2020({ allErrors: true, strict: false }); +addFormats(ajv2020); +const validateAgentPlugin = ajv2020.compile(readJson(agentPluginsSchemaPath)); const schemaErrors = (validate) => (validate.errors ?? []).map((e) => `${e.instancePath || "/"} ${e.message}`).join("; "); @@ -75,7 +80,7 @@ if (marketplace && cursorMarketplace && marketplace.name !== cursorMarketplace.n } const extraFilePaths = new Set((config?.["extra-files"] ?? []).map((f) => f.path)); -for (const path of [".claude-plugin/plugin.json", ".cursor-plugin/plugin.json"]) { +for (const path of [".claude-plugin/plugin.json", ".cursor-plugin/plugin.json", "plugin.json"]) { if (!extraFilePaths.has(path)) { fail(`release-please-config.json extra-files is missing "${path}", its version would drift on release`); } @@ -138,6 +143,28 @@ for (const name of pluginDirs) { } } + const agentPluginJsonPath = join(pluginsDir, name, "plugin.json"); + if (!existsSync(agentPluginJsonPath)) { + fail(`plugins/${name}: missing plugin.json (Agent Plugins manifest)`); + } else { + const agentPluginJson = readJson(agentPluginJsonPath); + if (agentPluginJson) { + if (!validateAgentPlugin(agentPluginJson)) { + fail(`plugins/${name}/plugin.json: ${schemaErrors(validateAgentPlugin)}`); + } + for (const field of ["name", "version", "description"]) { + if (agentPluginJson[field] !== pluginJson[field]) { + fail( + `plugins/${name}: plugin.json ${field} "${agentPluginJson[field]}" does not match .claude-plugin/plugin.json ${field} "${pluginJson[field]}"` + ); + } + } + } + } + if (!existsSync(join(pluginsDir, name, "skills"))) { + fail(`plugins/${name}: missing skills/ directory, the fixed Agent Plugins skills location`); + } + const cmp = cursorMarketplaceByName.get(name); if (!cmp) { fail(`plugins/${name}: not listed in .cursor-plugin/marketplace.json`);