diff --git a/.github/skills/add-community-extension/SKILL.md b/.github/skills/add-community-extension/SKILL.md index 4d56eaa9d0..179c11b3e2 100644 --- a/.github/skills/add-community-extension/SKILL.md +++ b/.github/skills/add-community-extension/SKILL.md @@ -70,6 +70,8 @@ Use the existing entries as the format template. Required fields: "documentation": "", "changelog": "", "license": "", + "category": "", + "effect": "", "requires": { "speckit_version": "" }, @@ -87,6 +89,9 @@ Use the existing entries as the format template. Required fields: } ``` +**Category** — free-form string; common values: `docs`, `code`, `process`, `integration`, `visibility` +**Effect** — one of: `read-only`, `read-write` + If the extension has optional tool dependencies, add a `"tools"` array inside `"requires"`: ```json @@ -113,8 +118,8 @@ Determine the category and effect from the extension's behavior: | | | `` | | []() | ``` -**Category** — one of: `docs`, `code`, `process`, `integration`, `visibility` -**Effect** — `Read-only` (produces reports only) or `Read+Write` (modifies project files) +**Category** — free-form; common values: `docs`, `code`, `process`, `integration`, `visibility` +**Effect** — write canonical values `read-only` or `read-write` in `extension.yml` and `catalog.community.json`; use `Read-only`/`Read+Write` only for the docs table display ### 6. Commit, push, and open PR diff --git a/docs/community/extensions.md b/docs/community/extensions.md index 8d41db95c6..517c32290f 100644 --- a/docs/community/extensions.md +++ b/docs/community/extensions.md @@ -7,7 +7,7 @@ The following community-contributed extensions are available in [`catalog.community.json`](https://github.com/github/spec-kit/blob/main/extensions/catalog.community.json): -**Categories:** +**Categories** (common values, but any string is allowed): - `docs` — reads, validates, or generates spec artifacts - `code` — reviews, validates, or modifies source code @@ -15,10 +15,13 @@ The following community-contributed extensions are available in [`catalog.commun - `integration` — syncs with external platforms - `visibility` — reports on project health or progress -**Effect:** +**Effect** (canonical `extension.yml`/catalog values): -- `Read-only` — produces reports without modifying files -- `Read+Write` — modifies files, creates artifacts, or updates specs +- `read-only` — produces reports without modifying files (displayed as `Read-only` in the table) +- `read-write` — modifies files, creates artifacts, or updates specs (displayed as `Read+Write` in the table) + +> [!TIP] +> Extension authors can declare `category` and `effect` in their `extension.yml` under the `extension:` block. These fields are also available in `catalog.community.json` for tooling and the CLI (`specify extension info`). | Extension | Purpose | Category | Effect | URL | |-----------|---------|----------|--------|-----| diff --git a/extensions/catalog.community.json b/extensions/catalog.community.json index 07fb7ef55d..b3ff5e3b3c 100644 --- a/extensions/catalog.community.json +++ b/extensions/catalog.community.json @@ -15,6 +15,8 @@ "documentation": "https://github.com/mnriem/spec-kit-extensions/blob/main/aide/README.md", "changelog": "https://github.com/mnriem/spec-kit-extensions/blob/main/aide/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.2.0" }, @@ -48,6 +50,8 @@ "documentation": "https://github.com/xymelon/spec-kit-agent-assign/blob/main/README.md", "changelog": "https://github.com/xymelon/spec-kit-agent-assign/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -80,6 +84,8 @@ "documentation": "https://github.com/bigsmartben/spec-kit-agent-governance/blob/main/README.md", "changelog": "https://github.com/bigsmartben/spec-kit-agent-governance/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.0", "tools": [ @@ -117,6 +123,8 @@ "documentation": "https://github.com/pragya247/spec-kit-orchestrator/blob/main/README.md", "changelog": "https://github.com/pragya247/spec-kit-orchestrator/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.6.1" }, @@ -149,6 +157,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-api-evolve/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-api-evolve/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -186,6 +196,8 @@ "documentation": "https://github.com/bigsmartben/spec-kit-arch/blob/main/README.md", "changelog": "https://github.com/bigsmartben/spec-kit-arch/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.10.dev0" }, @@ -217,6 +229,8 @@ "documentation": "https://github.com/UmmeHabiba1312/spec-kit-architect-preview/blob/main/README.md", "changelog": "https://github.com/UmmeHabiba1312/spec-kit-architect-preview/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -249,6 +263,8 @@ "documentation": "https://github.com/DyanGalih/spec-kit-architecture-guard/blob/main/docs/architecture-overview.md", "changelog": "https://github.com/DyanGalih/spec-kit-architecture-guard/releases", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -283,6 +299,8 @@ "documentation": "https://github.com/stn1slv/spec-kit-archive/blob/main/README.md", "changelog": "https://github.com/stn1slv/spec-kit-archive/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -314,6 +332,8 @@ "documentation": "https://github.com/pragya247/spec-kit-azure-devops/blob/main/README.md", "changelog": "https://github.com/pragya247/spec-kit-azure-devops/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -353,6 +373,8 @@ "documentation": "https://github.com/chordpli/spec-kit-blueprint/blob/main/README.md", "changelog": "https://github.com/chordpli/spec-kit-blueprint/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.2.0" }, @@ -385,6 +407,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-branch-convention/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-branch-convention/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -417,6 +441,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-brownfield/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-brownfield/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -438,7 +464,7 @@ "updated_at": "2026-04-10T00:00:00Z" }, "brownkit": { - "name": "BrownKit \u2014 Brownfield Discovery for Spec-Kit", + "name": "BrownKit — Brownfield Discovery for Spec-Kit", "id": "brownkit", "description": "Evidence-driven capability discovery, security and QA risk assessment for existing codebases.", "author": "Maksim Shautsou", @@ -449,6 +475,8 @@ "documentation": "https://github.com/MaksimShevtsov/BrownKit/blob/main/README.md", "changelog": "https://github.com/MaksimShevtsov/BrownKit/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -481,6 +509,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-bugfix/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-bugfix/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -513,6 +543,8 @@ "documentation": "https://github.com/maximiliamus/spec-kit-canon/blob/master/README.md", "changelog": "https://github.com/maximiliamus/spec-kit-canon/blob/master/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.3" }, @@ -548,6 +580,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-catalog-ci/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-catalog-ci/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-only", "requires": { "speckit_version": ">=0.4.0" }, @@ -580,6 +614,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-changelog/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-changelog/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-only", "requires": { "speckit_version": ">=0.4.0" }, @@ -612,6 +648,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-ci-guard/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-ci-guard/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-only", "requires": { "speckit_version": ">=0.4.0" }, @@ -645,6 +683,8 @@ "documentation": "https://github.com/aaronrsun/spec-kit-checkpoint/blob/main/README.md", "changelog": "https://github.com/aaronrsun/spec-kit-checkpoint/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -674,6 +714,8 @@ "documentation": "https://github.com/dsrednicki/spec-kit-cleanup/blob/main/README.md", "changelog": "https://github.com/dsrednicki/spec-kit-cleanup/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -706,6 +748,8 @@ "documentation": "https://github.com/twbrandon7/spec-kit-conduct-ext/blob/main/README.md", "changelog": "https://github.com/twbrandon7/spec-kit-conduct-ext/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.1" }, @@ -736,6 +780,8 @@ "documentation": "https://github.com/arunt14/spec-kit-critique/blob/main/README.md", "changelog": "https://github.com/arunt14/spec-kit-critique/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -766,6 +812,8 @@ "documentation": "https://github.com/aaronrsun/spec-kit-confluence/blob/main/README.md", "changelog": "https://github.com/aaronrsun/spec-kit-confluence/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -794,6 +842,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-cost/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-cost/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.0" }, @@ -826,6 +876,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-diagram-/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-diagram-/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-only", "requires": { "speckit_version": ">=0.4.0" }, @@ -858,6 +910,8 @@ "documentation": "https://github.com/raccioly/docguard/blob/main/extensions/spec-kit-docguard/README.md", "changelog": "https://github.com/raccioly/docguard/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -900,6 +954,8 @@ "documentation": "https://github.com/KhawarHabibKhan/spec-kit-doctor/blob/main/README.md", "changelog": "https://github.com/KhawarHabibKhan/spec-kit-doctor/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -931,6 +987,8 @@ "documentation": "https://github.com/mnriem/spec-kit-extensions/blob/main/extensify/README.md", "changelog": "https://github.com/mnriem/spec-kit-extensions/blob/main/extensify/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.0" }, @@ -962,6 +1020,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-fix-findings/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-fix-findings/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -994,6 +1054,8 @@ "documentation": "https://github.com/speckit-community/spec-kit-fixit/blob/main/README.md", "changelog": "https://github.com/speckit-community/spec-kit-fixit/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1025,6 +1087,8 @@ "documentation": "https://github.com/sharathsatish/spec-kit-fleet/blob/main/README.md", "changelog": "https://github.com/sharathsatish/spec-kit-fleet/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1055,6 +1119,8 @@ "homepage": "https://github.com/RogerBestMsft/spec-kit-FxToNet", "documentation": "https://github.com/RogerBestMsft/spec-kit-FxToNet/blob/main/README.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -1094,6 +1160,8 @@ "documentation": "https://github.com/Fatima367/spec-kit-github-issues/blob/main/README.md", "changelog": "https://github.com/Fatima367/spec-kit-github-issues/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -1134,6 +1202,8 @@ "documentation": "https://github.com/aaronrsun/spec-kit-issue/blob/main/README.md", "changelog": "https://github.com/aaronrsun/spec-kit-issue/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1166,6 +1236,8 @@ "documentation": "https://github.com/imviancagrace/spec-kit-iterate/blob/main/README.md", "changelog": "https://github.com/imviancagrace/spec-kit-iterate/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1196,6 +1268,8 @@ "documentation": "https://github.com/mbachorik/spec-kit-jira/blob/main/README.md", "changelog": "https://github.com/mbachorik/spec-kit-jira/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1227,6 +1301,8 @@ "documentation": "https://github.com/imviancagrace/spec-kit-learn/blob/main/README.md", "changelog": "https://github.com/imviancagrace/spec-kit-learn/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1258,6 +1334,8 @@ "documentation": "https://github.com/ashbrener/spec-kit-linear/blob/main/README.md", "changelog": "https://github.com/ashbrener/spec-kit-linear/releases", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1291,6 +1369,8 @@ "documentation": "https://github.com/BenBtg/spec-kit-m365/blob/main/README.md", "changelog": "https://github.com/BenBtg/spec-kit-m365/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -1329,6 +1409,8 @@ "documentation": "https://github.com/GenieRobot/spec-kit-maqa-ext/blob/main/README.md", "changelog": "https://github.com/GenieRobot/spec-kit-maqa-ext/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -1362,6 +1444,8 @@ "documentation": "https://github.com/GenieRobot/spec-kit-maqa-azure-devops/blob/main/README.md", "changelog": "https://github.com/GenieRobot/spec-kit-maqa-azure-devops/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -1394,6 +1478,8 @@ "documentation": "https://github.com/GenieRobot/spec-kit-maqa-ci/blob/main/README.md", "changelog": "https://github.com/GenieRobot/spec-kit-maqa-ci/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -1427,6 +1513,8 @@ "documentation": "https://github.com/GenieRobot/spec-kit-maqa-github-projects/blob/main/README.md", "changelog": "https://github.com/GenieRobot/spec-kit-maqa-github-projects/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -1459,6 +1547,8 @@ "documentation": "https://github.com/GenieRobot/spec-kit-maqa-jira/blob/main/README.md", "changelog": "https://github.com/GenieRobot/spec-kit-maqa-jira/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -1491,6 +1581,8 @@ "documentation": "https://github.com/GenieRobot/spec-kit-maqa-linear/blob/main/README.md", "changelog": "https://github.com/GenieRobot/spec-kit-maqa-linear/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -1523,6 +1615,8 @@ "documentation": "https://github.com/GenieRobot/spec-kit-maqa-trello/blob/main/README.md", "changelog": "https://github.com/GenieRobot/spec-kit-maqa-trello/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-write", "requires": { "speckit_version": ">=0.3.0" }, @@ -1555,6 +1649,8 @@ "documentation": "https://github.com/BenBtg/spec-kit-markitdown/blob/main/README.md", "changelog": "https://github.com/BenBtg/spec-kit-markitdown/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -1592,6 +1688,8 @@ "repository": "https://github.com/AI-MDE/spec-kit-mde", "homepage": "https://github.com/AI-MDE/spec-kit-mde", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1623,6 +1721,8 @@ "documentation": "https://github.com/KevinBrown5280/spec-kit-memory-loader/blob/main/README.md", "changelog": "https://github.com/KevinBrown5280/spec-kit-memory-loader/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-only", "requires": { "speckit_version": ">=0.6.0" }, @@ -1654,6 +1754,8 @@ "documentation": "https://github.com/DyanGalih/spec-kit-memory-hub/blob/main/README.md", "changelog": "https://github.com/DyanGalih/spec-kit-memory-hub/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.2.0" }, @@ -1687,6 +1789,8 @@ "documentation": "https://github.com/RbBtSn0w/spec-kit-extensions/blob/main/memorylint/README.md", "changelog": "https://github.com/RbBtSn0w/spec-kit-extensions/blob/main/memorylint/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.5.1" }, @@ -1719,6 +1823,8 @@ "documentation": "https://github.com/formin/multi-model-review/blob/main/README.md", "changelog": "https://github.com/formin/multi-model-review/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.2.0", "tools": [ @@ -1769,6 +1875,8 @@ "documentation": "https://github.com/teeyo/spec-kit-multi-sites/blob/main/README.md", "changelog": "https://github.com/teeyo/spec-kit-multi-sites/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1800,6 +1908,8 @@ "documentation": "https://github.com/dmux/spec-kit-onboard/blob/main/README.md", "changelog": "https://github.com/dmux/spec-kit-onboard/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1833,6 +1943,8 @@ "documentation": "https://github.com/sakitA/spec-kit-optimize/blob/main/README.md", "changelog": "https://github.com/sakitA/spec-kit-optimize/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -1865,6 +1977,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-orchestrator/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-orchestrator/releases", "license": "MIT", + "category": "process", + "effect": "read-only", "requires": { "speckit_version": ">=0.4.0" }, @@ -1897,6 +2011,8 @@ "documentation": "https://github.com/luno/spec-kit-plan-review-gate/blob/main/README.md", "changelog": "https://github.com/luno/spec-kit-plan-review-gate/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -1928,6 +2044,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-pr-bridge-/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-pr-bridge-/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-only", "requires": { "speckit_version": ">=0.4.0" }, @@ -1960,6 +2078,8 @@ "documentation": "https://github.com/mnriem/spec-kit-extensions/blob/main/presetify/README.md", "changelog": "https://github.com/mnriem/spec-kit-extensions/blob/main/presetify/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.2.0" }, @@ -1991,6 +2111,8 @@ "documentation": "https://github.com/bigsmartben/spec-kit-preview/blob/main/README.md", "changelog": "https://github.com/bigsmartben/spec-kit-preview/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.10.dev0" }, @@ -2022,6 +2144,8 @@ "documentation": "https://github.com/d0whc3r/spec-kit-product/wiki", "changelog": "https://github.com/d0whc3r/spec-kit-product/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.2.0" }, @@ -2064,6 +2188,8 @@ "documentation": "https://github.com/VaiYav/speckit-product-forge/blob/main/README.md", "changelog": "https://github.com/VaiYav/speckit-product-forge/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2096,6 +2222,8 @@ "documentation": "https://github.com/arunt14/spec-kit-qa/blob/main/README.md", "changelog": "https://github.com/arunt14/spec-kit-qa/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -2126,6 +2254,8 @@ "documentation": "https://github.com/Sertxito/spec-kit-extension-rag-azure-builder#readme", "changelog": "https://github.com/Sertxito/spec-kit-extension-rag-azure-builder/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.0" }, @@ -2158,6 +2288,8 @@ "documentation": "https://github.com/Rubiss-Projects/spec-kit-ralph/blob/main/README.md", "changelog": "https://github.com/Rubiss-Projects/spec-kit-ralph/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -2199,6 +2331,8 @@ "documentation": "https://github.com/stn1slv/spec-kit-reconcile/blob/main/README.md", "changelog": "https://github.com/stn1slv/spec-kit-reconcile/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2230,6 +2364,8 @@ "documentation": "https://github.com/ashbrener/spec-kit-red-team/blob/main/README.md", "changelog": "https://github.com/ashbrener/spec-kit-red-team/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2262,6 +2398,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-refine/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-refine/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -2294,6 +2432,8 @@ "documentation": "https://github.com/liuyiyu/spec-kit-repoindex/tree/main/docs", "changelog": "https://github.com/liuyiyu/spec-kit-repoindex/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -2331,6 +2471,8 @@ "documentation": "https://github.com/LoogacyStudio/spec-kit-reqnroll-bdd#readme", "changelog": "https://github.com/LoogacyStudio/spec-kit-reqnroll-bdd/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.0", "tools": [ @@ -2369,6 +2511,8 @@ "documentation": "https://github.com/arunt14/spec-kit-retro/blob/main/README.md", "changelog": "https://github.com/arunt14/spec-kit-retro/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2399,6 +2543,8 @@ "documentation": "https://github.com/emi-dm/spec-kit-retrospective/blob/main/README.md", "changelog": "https://github.com/emi-dm/spec-kit-retrospective/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2431,6 +2577,8 @@ "documentation": "https://github.com/ismaelJimenez/spec-kit-review/blob/main/README.md", "changelog": "https://github.com/ismaelJimenez/spec-kit-review/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -2465,6 +2613,8 @@ "documentation": "https://github.com/chordpli/spec-kit-ripple/blob/main/README.md", "changelog": "https://github.com/chordpli/spec-kit-ripple/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.2.0" }, @@ -2497,6 +2647,8 @@ "documentation": "https://github.com/jfranc38/spec-kit-schedule/blob/main/README.md", "changelog": "https://github.com/jfranc38/spec-kit-schedule/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -2529,6 +2681,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-scope-/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-scope-/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-only", "requires": { "speckit_version": ">=0.4.0" }, @@ -2562,6 +2716,8 @@ "documentation": "https://github.com/DyanGalih/spec-kit-security-review/blob/main/README.md", "changelog": "https://github.com/DyanGalih/spec-kit-security-review/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2594,6 +2750,8 @@ "documentation": "https://ysumanth06.github.io/spec-kit-sf/introduction.html", "changelog": "https://github.com/ysumanth06/spec-kit-sf/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0", "tools": [ @@ -2638,6 +2796,8 @@ "documentation": "https://github.com/arunt14/spec-kit-ship/blob/main/README.md", "changelog": "https://github.com/arunt14/spec-kit-ship/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2668,6 +2828,8 @@ "documentation": "https://github.com/KevinBrown5280/spec-kit-spec-reference-loader/blob/main/README.md", "changelog": "https://github.com/KevinBrown5280/spec-kit-spec-reference-loader/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-only", "requires": { "speckit_version": ">=0.6.0" }, @@ -2699,6 +2861,8 @@ "documentation": "https://github.com/aeltayeb/spec-kit-spec-validate/blob/main/README.md", "changelog": "https://github.com/aeltayeb/spec-kit-spec-validate/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.5.0" }, @@ -2731,6 +2895,8 @@ "documentation": "https://github.com/Azure-Samples/Spec2Cloud/blob/main/spec-kit/README.md", "changelog": "https://github.com/Azure-Samples/Spec2Cloud/blob/main/spec-kit/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -2763,6 +2929,8 @@ "documentation": "https://github.com/lihan3238/speckit-superpowers-bridge#readme", "changelog": "https://github.com/lihan3238/speckit-superpowers-bridge/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.10", "tools": [ @@ -2812,6 +2980,8 @@ "documentation": "https://github.com/mvanhorn/speckit-utils/blob/main/README.md", "changelog": "https://github.com/mvanhorn/speckit-utils/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -2844,6 +3014,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-spectest/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-spectest/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -2877,6 +3049,8 @@ "documentation": "https://github.com/jwill824/spec-kit-squad/blob/main/README.md", "changelog": "https://github.com/jwill824/spec-kit-squad/blob/main/docs/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.8.11", "tools": [ @@ -2916,6 +3090,8 @@ "documentation": "https://github.com/arunt14/spec-kit-staff-review/blob/main/README.md", "changelog": "https://github.com/arunt14/spec-kit-staff-review/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -2946,6 +3122,8 @@ "documentation": "https://github.com/KhawarHabibKhan/spec-kit-status/blob/main/README.md", "changelog": "https://github.com/KhawarHabibKhan/spec-kit-status/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -2978,6 +3156,8 @@ "documentation": "https://github.com/Open-Agent-Tools/spec-kit-status/blob/main/README.md", "changelog": "https://github.com/Open-Agent-Tools/spec-kit-status/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -3008,6 +3188,8 @@ "documentation": "https://github.com/RbBtSn0w/spec-kit-extensions/blob/main/superpowers-bridge/README.md", "changelog": "https://github.com/RbBtSn0w/spec-kit-extensions/blob/main/superpowers-bridge/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.3", "tools": [ @@ -3051,6 +3233,8 @@ "documentation": "https://github.com/WangX0111/superspec/blob/main/README.md", "changelog": "https://github.com/WangX0111/superspec/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -3084,6 +3268,8 @@ "documentation": "https://github.com/bgervin/spec-kit-sync/blob/main/README.md", "changelog": "https://github.com/bgervin/spec-kit-sync/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -3116,6 +3302,8 @@ "documentation": "https://github.com/tarunkumarbhati/spec-kit-team-assign/blob/main/README.md", "changelog": "https://github.com/tarunkumarbhati/spec-kit-team-assign/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -3147,6 +3335,8 @@ "documentation": "https://github.com/teeyo/spec-kit-time-machine", "changelog": "https://github.com/teeyo/spec-kit-time-machine/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -3184,6 +3374,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-tinyspec/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-tinyspec/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -3216,6 +3408,8 @@ "documentation": "https://github.com/NaviaSamal/spec-kit-threatmodel/blob/main/README.md", "changelog": "https://github.com/NaviaSamal/spec-kit-threatmodel/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-only", "requires": { "speckit_version": ">=0.6.0" }, @@ -3248,6 +3442,8 @@ "documentation": "https://github.com/coderandhiker/spec-kit-token-analyzer/blob/main/README.md", "changelog": "https://github.com/coderandhiker/spec-kit-token-analyzer/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-only", "requires": { "speckit_version": ">=0.2.0" }, @@ -3279,6 +3475,8 @@ "documentation": "https://github.com/tinesoft/spec-kit-token-budget/blob/main/README.md", "changelog": "https://github.com/tinesoft/spec-kit-token-budget/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -3321,6 +3519,8 @@ "documentation": "https://github.com/leocamello/spec-kit-v-model/blob/main/README.md", "changelog": "https://github.com/leocamello/spec-kit-v-model/blob/main/CHANGELOG.md", "license": "MIT", + "category": "docs", + "effect": "read-write", "requires": { "speckit_version": ">=0.1.0" }, @@ -3353,6 +3553,8 @@ "documentation": "https://github.com/ismaelJimenez/spec-kit-verify/blob/main/README.md", "changelog": "https://github.com/ismaelJimenez/spec-kit-verify/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -3385,6 +3587,8 @@ "documentation": "https://github.com/datastone-inc/spec-kit-verify-tasks/blob/main/README.md", "changelog": "https://github.com/datastone-inc/spec-kit-verify-tasks/blob/main/CHANGELOG.md", "license": "MIT", + "category": "code", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0" }, @@ -3416,6 +3620,8 @@ "documentation": "https://github.com/KevinBrown5280/spec-kit-version-guard/blob/main/README.md", "changelog": "https://github.com/KevinBrown5280/spec-kit-version-guard/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-only", "requires": { "speckit_version": ">=0.2.0" }, @@ -3445,6 +3651,8 @@ "homepage": "https://github.com/DevAbdullah90/spec-kit-whatif", "documentation": "https://github.com/DevAbdullah90/spec-kit-whatif/blob/main/README.md", "license": "MIT", + "category": "visibility", + "effect": "read-only", "requires": { "speckit_version": ">=0.6.0" }, @@ -3475,6 +3683,8 @@ "documentation": "https://github.com/TortoiseWolfe/spec-kit-extension-wireframe/blob/main/README.md", "changelog": "https://github.com/TortoiseWolfe/spec-kit-extension-wireframe/blob/main/CHANGELOG.md", "license": "MIT", + "category": "visibility", + "effect": "read-write", "requires": { "speckit_version": ">=0.6.0" }, @@ -3510,6 +3720,8 @@ "documentation": "https://github.com/sakitA/spec-kit-workiq/blob/main/README.md", "changelog": "https://github.com/sakitA/spec-kit-workiq/blob/main/CHANGELOG.md", "license": "MIT", + "category": "integration", + "effect": "read-only", "requires": { "speckit_version": ">=0.1.0", "tools": [ @@ -3554,6 +3766,8 @@ "documentation": "https://github.com/Quratulain-bilal/spec-kit-worktree/blob/main/README.md", "changelog": "https://github.com/Quratulain-bilal/spec-kit-worktree/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -3586,6 +3800,8 @@ "documentation": "https://github.com/dango85/spec-kit-worktree-parallel/blob/main/README.md", "changelog": "https://github.com/dango85/spec-kit-worktree-parallel/blob/main/CHANGELOG.md", "license": "MIT", + "category": "process", + "effect": "read-write", "requires": { "speckit_version": ">=0.4.0" }, @@ -3607,4 +3823,4 @@ "updated_at": "2026-04-13T00:00:00Z" } } -} \ No newline at end of file +} diff --git a/extensions/template/extension.yml b/extensions/template/extension.yml index b907e0c786..a23bdc87da 100644 --- a/extensions/template/extension.yml +++ b/extensions/template/extension.yml @@ -13,6 +13,14 @@ extension: # CUSTOMIZE: Brief description (under 200 characters) description: "Brief description of what your extension does" + # CUSTOMIZE: Extension category — describes what the extension operates on + # Common values: docs, code, process, integration, visibility + # category: "process" + + # CUSTOMIZE: Extension effect — whether it modifies project files + # One of: read-only | read-write + # effect: "read-write" + # CUSTOMIZE: Your name or organization name author: "Your Name" diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 23d31cb0cf..96a65e5e9f 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1983,7 +1983,11 @@ def extension_info( author = ext_manifest.data.get("extension", {}).get("author") if author: console.print(f"[dim]Author:[/dim] {author}") - console.print() + if ext_manifest.category: + console.print(f"[dim]Category:[/dim] {ext_manifest.category}") + if ext_manifest.effect: + console.print(f"[dim]Effect:[/dim] {ext_manifest.effect}") + console.print() if ext_manifest.commands: console.print("[bold]Commands:[/bold]") @@ -2033,6 +2037,12 @@ def _print_extension_info(ext_info: dict, manager): console.print(f"[dim]Author:[/dim] {ext_info.get('author', 'Unknown')}") console.print(f"[dim]License:[/dim] {ext_info.get('license', 'Unknown')}") + # Category and Effect + if ext_info.get('category'): + console.print(f"[dim]Category:[/dim] {ext_info['category']}") + if ext_info.get('effect'): + console.print(f"[dim]Effect:[/dim] {ext_info['effect']}") + # Source catalog if ext_info.get("_catalog_name"): install_allowed = ext_info.get("_install_allowed", True) diff --git a/src/specify_cli/extensions.py b/src/specify_cli/extensions.py index adbbedcb94..daf009e4b0 100644 --- a/src/specify_cli/extensions.py +++ b/src/specify_cli/extensions.py @@ -41,6 +41,8 @@ }) EXTENSION_COMMAND_NAME_PATTERN = re.compile(r"^speckit\.([a-z0-9-]+)\.([a-z0-9-]+)$") +VALID_EFFECTS = frozenset({"read-only", "read-write"}) + DEFAULT_HOOK_PRIORITY = 10 REINSTALL_COMMAND = "uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git" @@ -201,6 +203,21 @@ def _validate(self): except pkg_version.InvalidVersion: raise ValidationError(f"Invalid version: {ext['version']}") + # Validate optional category field (free-form string) + if "category" in ext: + if not isinstance(ext["category"], str) or not ext["category"].strip(): + raise ValidationError( + "Invalid extension.category: must be a non-empty string" + ) + + # Validate optional effect field + if "effect" in ext: + if not isinstance(ext["effect"], str) or ext["effect"] not in VALID_EFFECTS: + raise ValidationError( + f"Invalid extension.effect '{ext.get('effect')}': " + f"must be one of {sorted(VALID_EFFECTS)}" + ) + # Validate requires section requires = self.data["requires"] if "speckit_version" not in requires: @@ -374,6 +391,16 @@ def description(self) -> str: """Get extension description.""" return self.data["extension"]["description"] + @property + def category(self) -> Optional[str]: + """Get extension category (free-form; common values: docs, code, process, integration, visibility).""" + return self.data["extension"].get("category") + + @property + def effect(self) -> Optional[str]: + """Get extension effect (read-only, read-write).""" + return self.data["extension"].get("effect") + @property def requires_speckit_version(self) -> str: """Get required spec-kit version range.""" diff --git a/tests/test_extensions.py b/tests/test_extensions.py index dd231de311..d8cd0bcbe6 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -24,6 +24,7 @@ CatalogEntry, CORE_COMMAND_NAMES, DEFAULT_HOOK_PRIORITY, + VALID_EFFECTS, ExtensionManifest, ExtensionRegistry, ExtensionManager, @@ -300,6 +301,69 @@ def test_invalid_version(self, temp_dir, valid_manifest_data): with pytest.raises(ValidationError, match="Invalid version"): ExtensionManifest(manifest_path) + def test_valid_category(self, temp_dir, valid_manifest_data): + """Test manifest with various category values (free-form string).""" + import yaml + + for category in ("docs", "code", "process", "integration", "visibility", "custom-category"): + valid_manifest_data["extension"]["category"] = category + manifest_path = temp_dir / "extension.yml" + with open(manifest_path, 'w') as f: + yaml.dump(valid_manifest_data, f) + manifest = ExtensionManifest(manifest_path) + assert manifest.category == category + + def test_valid_effect(self, temp_dir, valid_manifest_data): + """Test manifest with valid effect values.""" + import yaml + + for effect in sorted(VALID_EFFECTS): + valid_manifest_data["extension"]["effect"] = effect + manifest_path = temp_dir / "extension.yml" + with open(manifest_path, 'w') as f: + yaml.dump(valid_manifest_data, f) + manifest = ExtensionManifest(manifest_path) + assert manifest.effect == effect + + def test_invalid_category(self, temp_dir, valid_manifest_data): + """Test manifest with empty category raises ValidationError.""" + import yaml + + valid_manifest_data["extension"]["category"] = "" + manifest_path = temp_dir / "extension.yml" + with open(manifest_path, 'w') as f: + yaml.dump(valid_manifest_data, f) + + with pytest.raises(ValidationError, match="Invalid extension.category"): + ExtensionManifest(manifest_path) + + def test_invalid_effect(self, temp_dir, valid_manifest_data): + """Test manifest with invalid effect raises ValidationError.""" + import yaml + + valid_manifest_data["extension"]["effect"] = "write-only" + manifest_path = temp_dir / "extension.yml" + with open(manifest_path, 'w') as f: + yaml.dump(valid_manifest_data, f) + + with pytest.raises(ValidationError, match="Invalid extension.effect"): + ExtensionManifest(manifest_path) + + def test_category_and_effect_optional(self, temp_dir, valid_manifest_data): + """Test that omitting category and effect still passes validation.""" + import yaml + + # Ensure no category/effect in data + valid_manifest_data["extension"].pop("category", None) + valid_manifest_data["extension"].pop("effect", None) + manifest_path = temp_dir / "extension.yml" + with open(manifest_path, 'w') as f: + yaml.dump(valid_manifest_data, f) + + manifest = ExtensionManifest(manifest_path) + assert manifest.category is None + assert manifest.effect is None + def test_invalid_command_name(self, temp_dir, valid_manifest_data): """Test manifest with command name that cannot be auto-corrected raises ValidationError.""" import yaml