# grok-plugin-json-valid .grok-plugin/plugin.json must be valid JSON with a name Grok's loader accepts | | | |---|---| | **Severity** | error (auto) | | **Autofix** | - | | **Since** | v0.20.0 | | **Repo Types** | grok-marketplace, grok-plugin | | **Category** | [Grok Build](grok.md) | ## Why `.grok-plugin/plugin.json` is the manifest Grok Build reads to register a plugin package and discover the components it provides. While a manifest is optional — plugins containing standard `skills/`, `agents/`, or `hooks/hooks.json` load conventions automatically — including a well-formed `plugin.json` enables you to specify custom paths, component declarations, metadata, and versioning. Validating `plugin.json` ensures your plugin package installs smoothly and registers all intended components: - If a manifest contains invalid JSON or lacks a valid name, Grok may skip the plugin directory during installation. - Declared component paths (`skills`, `commands`, `agents`, `hooks`, `mcpServers`) should resolve to actual files or directories within the plugin so all features are available at runtime. Grok resolves plugin manifests by checking `plugin.json`, `.grok-plugin/plugin.json`, and `.claude-plugin/plugin.json` in order. Skillsaw reports on whichever manifest file Grok discovers. ## Severity Findings distinguish between structural errors that prevent installation and path advisories: **Errors** — issues that prevent Grok from registering the plugin: - Invalid JSON syntax, a leading UTF-8 BOM, or non-finite number tokens (`NaN`, `Infinity`, `-Infinity`). - Duplicate recognized manifest fields or recognized fields inside `author`. - Known fields with values the typed manifest decoder rejects. - Manifest is not a JSON object. - Missing, empty, or non-string `name`. - A `name` that does not match Grok's plugin naming requirements (1-64 characters, lowercase alphanumeric and hyphens, no leading or trailing hyphen). The typed fields use these shapes: | Fields | Accepted values | | --- | --- | | `version`, `description`, `homepage`, `repository`, `license` | String, null, or omitted | | `author` | Object, null, or omitted; its `name`, `email`, `url` are optional strings | | `keywords` | Array of strings; omission defaults to an empty array, but null is invalid | | `skills`, `commands`, `agents` | Path string, array of path strings, null, or omitted | | `hooks`, `mcpServers`, `lspServers` | Path string or inline JSON value; interpreted by the component loader | A malformed directory-path list rejects the manifest as a whole; Grok does not load just the string elements from a mixed list. Component advice is skipped when a typed-field error has already prevented the manifest from loading. **Warnings** — the plugin registers, but declared components may not load: - A declared `skills`, `commands`, `agents`, `hooks`, or `mcpServers` path that resolves outside the plugin package. Contained absolute or parent-normalized spellings remain valid. - A declared path that does not exist on disk. - A path pointing to the wrong resource type (e.g. specifying a file where a directory is expected, or vice versa). - Specifying `hooks` or `mcpServers` as an array (each should be a file path string or an inline object). - Specifying custom component path overrides that omit existing conventional directories (e.g. setting `"skills": ["extra-skills"]` without also listing `"skills"`). **Info** — metadata recommendations for marketplace discovery: - A `version` that is not valid semantic versioning. - A missing `description`. ## What is not reported - **Name vs directory**: the manifest `name` takes precedence, so differences between manifest name and directory name are supported. - **Unknown manifest keys**: custom metadata keys are permitted, including duplicates. Duplicate unknown `author` members and inline JSON object keys are also accepted; this does not permit duplicate recognized struct fields. - **Bare strings for paths**: strings and arrays are both supported for `skills`, `commands`, and `agents`. ## Examples **Bad** — custom skills path omits the existing `skills/` directory: ```json { "name": "tide-charts", "version": "1.1.0", "description": "Shoreline survey windows from NOAA tide predictions.", "skills": ["./extra-skills"] } ``` **Good** — lists both the extra skills directory and the standard `skills/`: ```json { "name": "tide-charts", "version": "1.1.0", "description": "Shoreline survey windows from NOAA tide predictions.", "skills": ["./extra-skills", "./skills"] } ``` ## How to fix - Choose a valid lowercase kebab-case `name` (e.g. `tide-charts`). - When overriding component locations, include the standard directory alongside any extra paths if you want both loaded. - Ensure all declared paths exist relative to the plugin root. - Add a helpful `description` and semantic `version` for marketplace listings. If your project generates component directories during a build step, you can disable path existence checks: ```yaml rules: grok-plugin-json-valid: check-paths-exist: false ``` If you intentionally replace conventional directories with custom ones: ```yaml rules: grok-plugin-json-valid: check-overrides: false ``` Plugin component paths follow canonical containment, independently of the marketplace source grammar. Contained paths such as `nested/../skills` remain valid, and an empty directory-field path names the plugin root. These paths still participate in override coverage; a path outside the plugin or a target of the wrong kind remains a warning. ## Configuration ```yaml rules: grok-plugin-json-valid: enabled: auto # true | false | auto severity: error ``` | Parameter | Description | Default | |-----------|-------------|---------| | `check-paths-exist` | Warn when a manifest path (skills, commands, agents, hooks, mcpServers) names something the plugin does not contain | `true` | | `check-overrides` | Warn when a declared skills, commands or agents path drops components the conventional directory would have loaded | `true` | *Run `skillsaw explain grok-plugin-json-valid` to see this documentation and the rule's effective configuration in your terminal.*