# grok-marketplace-index-parity plugin-index.json must agree with its marketplace catalog | | | |---|---| | **Severity** | warning (auto) | | **Autofix** | - | | **Since** | v0.20.0 | | **Repo Types** | grok-marketplace | | **Category** | [Grok Build](grok.md) | ## Why In Grok Build marketplaces, `.grok-plugin/plugin-index.json` acts as the display catalog alongside `marketplace.json`. When users run `grok plugin list --available`, Grok uses this index to display plugin summaries, available skills, commands, and version info. Keeping `plugin-index.json` in sync with `marketplace.json` ensures that what users see in the marketplace browser reflects the declared plugins: - For remote Git repository plugins, Grok matches the `sha` between `marketplace.json` and `plugin-index.json` to verify component details. If these commit hashes drift, component listings may be omitted from display. - For local plugin sources, keeping component listings updated ensures the displayed skills match what the plugin actually provides on disk. This rule checks that `plugin-index.json` accurately reflects the contents of `marketplace.json`. If a repository does not include `plugin-index.json`, this rule simply stands down, as the index file is optional. Display parity is separate from installation validation. Grok still displays a remote plugin and its matching index metadata when its source `path` contains an invalid subdirectory. Keep that entry in the index and correct the source path using the [`grok-marketplace-json-valid`](grok-marketplace-json-valid.md) finding; removing the index entry would omit metadata for a visible plugin. ## Severity Findings carry **Warning** severity because they describe missing or inaccurate browser metadata. They do not establish whether a source can be installed. ## What it checks Skillsaw reports parity discrepancies across the index and catalog: - Literal catalog entry names present in one file but missing from the other. A local plugin's manifest name controls its listing name, but does not substitute for the catalog entry's index lookup key. An empty catalog entry name uses the empty string key; diagnostics display that key as `""`. - For remote sources, commit `sha` strings that differ between the catalog and index, including differences in case or whitespace. The display reader compares the stored strings exactly; installer normalization is separate. Local display lookup ignores an optional index `sha` and still compares the skills. - For local plugins: skills listed in the index that do not match the skills present in the plugin source on disk. Skills match by either their `SKILL.md` frontmatter `name` or their directory name. Additional checks: - Syntax and typed index errors: version must be integer `1`; omitted `plugins` defaults to an empty map. Each entry requires `components`, whose six optional categories are arrays of items with a string `name` and optional string or null `description`. A typed defect discards the whole index, so it produces one index warning before any drift comparison. - Grok's accepted positional struct arrays and unknown metadata stay valid. Recognized struct fields cannot repeat; plugin-map duplicates keep the last entry after decoding every value. A UTF-8 BOM is rejected by this reader. - Placement and selection: Grok prefers `.grok-plugin/plugin-index.json`, then falls back to `.claude-plugin/plugin-index.json` when the preferred file is absent. A present broken preferred file stops fallback. A legal shadowed copy stays in the lint tree without a placement warning. Root-level indexes are unsupported. ## Examples **Bad** — the index commit `sha` has drifted from the catalog entry: ```json { "version": 1, "plugins": { "annotations": { "sha": "aa11bb22cc33dd44ee5566ff77889900abcdef12", "version": "0.2.0", "components": {} } } } ``` **Good** — matching commit `sha` and accurate component details: ```json { "version": 1, "plugins": { "annotations": { "sha": "1f9d0c73a86b24e5107cad3f88b90250e6c147da", "version": "0.2.0", "components": { "skills": [ {"name": "chart-legend", "description": "Build a chart's legend from its layers."} ] } } } } ``` ## How to fix - Regenerate `plugin-index.json` whenever updating plugins in `marketplace.json`. - Key each index entry by the exact corresponding catalog entry `name`, even when the local plugin manifest has a different name. Remove unused alias keys; they do not supply that catalog entry's components. - Place `plugin-index.json` in `.grok-plugin/`, or use the supported `.claude-plugin/` fallback when the preferred index is absent. - Remove entries from `plugin-index.json` when removing plugins from `marketplace.json`. If your workflow generates index components during a separate packaging or CI step, you can disable component-level checks while preserving catalog `sha` validation: ```yaml rules: grok-marketplace-index-parity: check-components: false ``` ## Configuration ```yaml rules: grok-marketplace-index-parity: enabled: auto # true | false | auto severity: warning ``` | Parameter | Description | Default | |-----------|-------------|---------| | `check-components` | Compare the skills the index lists for a local source against the skills that plugin ships | `true` | *Run `skillsaw explain grok-marketplace-index-parity` to see this documentation and the rule's effective configuration in your terminal.*