# description
Two shapes in one file: (1) the per-plugin manifest that authors ship as `plugin.json` (see `$defs/PluginManifest`); (2) the aggregate registry the implementation produces on disk (`<cwd>/.skill-map/plugins.json`), which lists all discovered plugins with their compat status. Both shapes are normative. camelCase keys throughout.

# $defs.PluginManifest.description
Plugin manifest written as `<plugin>/plugin.json`. The plugin id comes from the directory name (structure-as-truth, per `architecture.md` §Plugin discovery), it is NOT a manifest field. Manifests carrying an `id` key are rejected as `invalid-manifest`.

# $defs.PluginManifest.properties.specCompat.description
Semver range this plugin is compatible with (e.g. `^1.0.0`, `>=0.3.0 <0.4.0`). Checked via `semver.satisfies(specVersion, this)` at load time.

# $defs.PluginManifest.properties.catalogCompat.description
Required semver range against the kernel's view-slots + input-types catalog version (e.g. `^1.0.0`). Independent from `specCompat` because the catalog evolves on its own cadence (new slots ship as minor bumps; rename/remove ships as catalog-major bumps that trigger `sm plugins upgrade`). Mismatch surfaces as `incompatible-catalog` plugin status.

# $defs.PluginManifest.properties.description.description
Required short description shown in `sm plugins list` and the UI. English-only per AGENTS.md.

# $defs.PluginManifest.properties.order.description
Optional visual ordering hint, inspector-only. The inspector renders one collapsible section per plugin (grouping the plugin's `inspector.body.panel.*` contributions); sections are sorted ASC by this value (default 100), tie-break by plugin id. Does NOT affect extension execution order, which is governed by `phase` (analyzers) and registration order.

# $defs.PluginManifest.properties.storage.description
Persistence declaration for this plugin. Absent = plugin does not persist state.

# $defs.PluginManifest.properties.storage.properties.mode.description
Shared `state_plugin_kvs` table, scoped by plugin id. The only storage mode.

# $defs.PluginManifest.properties.storage.properties.schema.description
Optional. JSON Schema (path relative to plugin root) that validates the value on every `ctx.store.set(key, value)`. Absent = permissive (no validation, status quo). The kernel AJV-compiles the schema at load time; a missing or unparseable schema file surfaces as `load-error`.

# $defs.DiscoveredPlugin.properties.id.description
Plugin id, derived from the plugin directory name (structure-as-truth). The kernel computes this at discovery; it is NOT a manifest field.

# $defs.DiscoveredPlugin.properties.status.description
Resolved state after discovery. `disabled` = user-disabled via config; `id-collision` = two plugin directories with the same name reachable from different roots (project + --plugin-dir combinations), both blocked, no precedence; `incompatible-catalog` = manifest's `catalogCompat` does not satisfy the kernel's catalog version (resolved via `sm plugins upgrade`); others = automatic.

# $defs.DiscoveredPlugin.properties.statusReason.description
Human-readable detail when status is anything other than `enabled`.