@skill-map/spec 0.38.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +48 -2302
  2. package/README.md +2 -2
  3. package/architecture.md +11 -14
  4. package/cli-contract.md +5 -1
  5. package/conformance/README.md +1 -1
  6. package/conformance/cases/extractor-emits-signal.json +1 -1
  7. package/conformance/cases/kernel-empty-boot.json +1 -1
  8. package/conformance/cases/no-global-scope.json +1 -1
  9. package/conformance/cases/orphan-markdown-fallback.json +1 -1
  10. package/conformance/cases/plugin-missing-ui-rejected.json +1 -1
  11. package/conformance/cases/sidecar-end-to-end.json +1 -1
  12. package/conformance/cases/signal-collision-detection.json +1 -1
  13. package/conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/providers/bad-provider/index.js +4 -0
  14. package/conformance/fixtures/sidecar-example/agent-example.sm +3 -3
  15. package/db-schema.md +19 -5
  16. package/index.json +55 -55
  17. package/package.json +2 -2
  18. package/schemas/annotations.schema.json +2 -2
  19. package/schemas/api/rest-envelope.schema.json +57 -12
  20. package/schemas/bump-report.schema.json +1 -1
  21. package/schemas/conformance-case.schema.json +1 -1
  22. package/schemas/conformance-result.schema.json +1 -1
  23. package/schemas/execution-record.schema.json +1 -1
  24. package/schemas/extensions/action.schema.json +1 -1
  25. package/schemas/extensions/analyzer.schema.json +1 -1
  26. package/schemas/extensions/base.schema.json +1 -1
  27. package/schemas/extensions/extractor.schema.json +1 -1
  28. package/schemas/extensions/formatter.schema.json +1 -1
  29. package/schemas/extensions/hook.schema.json +1 -1
  30. package/schemas/extensions/provider-kind.schema.json +1 -1
  31. package/schemas/extensions/provider.schema.json +80 -2
  32. package/schemas/frontmatter/base.schema.json +2 -7
  33. package/schemas/history-stats.schema.json +1 -1
  34. package/schemas/input-types.schema.json +1 -1
  35. package/schemas/issue.schema.json +1 -1
  36. package/schemas/job.schema.json +1 -1
  37. package/schemas/link.schema.json +1 -1
  38. package/schemas/node.schema.json +1 -1
  39. package/schemas/plugins-doctor.schema.json +1 -1
  40. package/schemas/plugins-registry.schema.json +1 -1
  41. package/schemas/project-config.schema.json +1 -1
  42. package/schemas/refresh-report.schema.json +1 -1
  43. package/schemas/report-base-deterministic.schema.json +1 -1
  44. package/schemas/report-base.schema.json +1 -1
  45. package/schemas/scan-result.schema.json +1 -1
  46. package/schemas/sidecar.schema.json +1 -1
  47. package/schemas/signal.schema.json +1 -1
  48. package/schemas/summaries/agent.schema.json +1 -1
  49. package/schemas/summaries/command.schema.json +1 -1
  50. package/schemas/summaries/hook.schema.json +1 -1
  51. package/schemas/summaries/markdown.schema.json +1 -1
  52. package/schemas/summaries/skill.schema.json +1 -1
  53. package/schemas/user-settings.schema.json +1 -1
  54. package/schemas/view-slots.schema.json +1 -1
  55. package/versioning.md +2 -2
package/README.md CHANGED
@@ -140,7 +140,7 @@ import nodeSchema from '@skill-map/spec/schemas/node.schema.json' with { type: '
140
140
  console.log(specIndex.specPackageVersion); // → "0.2.0" (npm package version; source of truth for `spec` in `sm version`)
141
141
  console.log(specIndex.indexPayloadVersion); // → "0.0.1" (payload shape of `index.json` itself; bumps only when this manifest's structure changes)
142
142
  console.log(specIndex.integrity.algorithm); // → "sha256"
143
- console.log(nodeSchema.$id); // → "https://skill-map.dev/spec/v0/node.schema.json"
143
+ console.log(nodeSchema.$id); // → "https://skill-map.ai/spec/v0/node.schema.json"
144
144
  ```
145
145
 
146
146
  Every JSON Schema is exported individually via `@skill-map/spec/schemas/*.json`. Prose documents ship in the tarball for reference but are not `exports`-surfaced.
@@ -161,7 +161,7 @@ console.log(actual === index.integrity.files[file] ? 'ok' : 'drift');
161
161
 
162
162
  ### JSON Schema Store
163
163
 
164
- The schemas will be registered on JSON Schema Store once the canonical URLs under `skill-map.dev/spec/v0/` are stable (Step 14).
164
+ The schemas will be registered on JSON Schema Store once the canonical URLs under `skill-map.ai/spec/v0/` are stable (Step 14).
165
165
 
166
166
  ## License
167
167
 
package/architecture.md CHANGED
@@ -43,7 +43,7 @@ Any conforming implementation, reference or third-party, MUST respect these boun
43
43
 
44
44
  A skill-map project sees its filesystem through exactly one **active provider lens** at any time. The lens is the provider whose extractors, classifiers, and resolution rules apply to the whole project during a scan. All other enabled providers stay registered but their provider-specific extractors are skipped.
45
45
 
46
- The lens is project-scope state. It lives in `.skill-map/settings.json` as the `activeProvider` key (see [`project-config.schema.json`](./schemas/project-config.schema.json#/properties/activeProvider)). When absent, the kernel auto-detects on first scan from filesystem heuristics (`.claude/``claude`, `.codex/` or root `AGENTS.md` → `openai`, `.cursor/` `cursor`, etc.) and persists the result; if the heuristic is ambiguous or yields no result, the CLI and UI prompt the user to pick one of the enabled providers. Google's Antigravity CLI (which replaced the retired Gemini CLI on 2026-05-19) has no vendor-specific filesystem marker, the `antigravity` lens is set manually via `sm config set activeProvider antigravity`.
46
+ The lens is project-scope state. It lives in `.skill-map/settings.json` as the `activeProvider` key (see [`project-config.schema.json`](./schemas/project-config.schema.json#/properties/activeProvider)). When absent, the kernel auto-detects on first scan from filesystem markers and persists the result; if the heuristic is ambiguous or yields no result, the CLI and UI prompt the user to pick one of the enabled providers. **The marker set is provider-owned**: each Provider declares its own detection markers in its manifest `detect.markers` block (see [`provider.schema.json`](./schemas/extensions/provider.schema.json#/properties/detect)), e.g. `claude``.claude/`, `openai` → `.codex/` or root `AGENTS.md`, `agent-skills` → `.agents/`. There is no central hardcoded detection table; the detectable set derives from the registered Providers, so adding a Provider with a marker makes it auto-detectable without touching the resolver. When several markers match, the resolver returns the full candidate list in Provider iteration order and the first match is the default suggestion. A Provider with no `detect` block is never auto-suggested but can still be selected manually, Google's Antigravity CLI (which replaced the retired Gemini CLI on 2026-05-19) adopted the open-standard `.agents/` rather than a vendor-specific marker, so a Google project auto-detects as the universal `agent-skills` lens and the `antigravity` lens is set manually via `sm config set activeProvider antigravity`.
47
47
 
48
48
  ### Consequence: one graph per project at a time
49
49
 
@@ -271,7 +271,9 @@ Each `kinds[*].ui` entry declares how the UI renders nodes of that kind:
271
271
 
272
272
  The `ui` block is required (not optional) by design: making it optional would force the UI to invent visuals for missing entries, silently collapsing unknown kinds to a default rendering and hiding manifest gaps. Forcing the Provider to declare presentation up-front means the UI never guesses.
273
273
 
274
- The kernel ships every Provider's `ui` block to the BFF at boot; the BFF aggregates them into a `kindRegistry` map and embeds it in every payload-bearing REST envelope (see [`cli-contract.md` §Server](./cli-contract.md#server)). The UI consumes `kindRegistry` directly, built-in and user-plugin kinds render identically.
274
+ The kernel ships every Provider's per-kind `ui` block to the BFF at boot; the BFF aggregates them into a `kindRegistry` map and embeds it in every payload-bearing REST envelope (see [`cli-contract.md` §Server](./cli-contract.md#server)). The UI consumes `kindRegistry` directly, built-in and user-plugin kinds render identically.
275
+
276
+ Each Provider ALSO declares a top-level `presentation` block (`provider.schema.json#/properties/presentation`: `label`, `color`, optional `colorDark` / `icon` / `emoji` / `hideChip`) describing the Provider's own identity, distinct from its kinds' visuals. (It is named `presentation`, not `ui`, because the shared extension `ui` key is the view-contributions map declared only by extractor / analyzer kinds.) The BFF aggregates these into a sibling `providerRegistry` map (keyed by Provider id) embedded on the same envelopes. The UI consumes `providerRegistry` to render the active-lens dropdown, the topbar lens chip, and the per-node provider chip on cards from the real registered-Provider set, never a hardcoded list. `hideChip: true` (set by the universal `markdown` fallback) suppresses only the per-card chip; the Provider still appears in the lens surfaces. Unlike kind colors (normalised across Providers so every `agent` paints the same), Provider colors are deliberately distinct so the chip tells the user at a glance which platform a node came from.
275
277
 
276
278
  ### Provider · dispatch order and the universal markdown fallback
277
279
 
@@ -652,22 +654,17 @@ Two columns on `scan_nodes` source from the sidecar's `annotations:` block when
652
654
 
653
655
  A `scan_nodes.annotations_json` column carries the full parsed `annotations:` block; `sidecar_present` and `sidecar_status` carry the drift-detection state. The full sidecar overlay (parsed `annotations`, `status`, `present`) is exposed on `Node.sidecar` so REST and UI consumers see it as part of the canonical wire shape.
654
656
 
655
- ### Tags · dual-source
656
-
657
- Skill-map's tag system is **dual-source** by design:
657
+ ### Tags
658
658
 
659
- - **Author tags** live in `frontmatter.tags` (in the `.md`). Universal optional field declared on [`schemas/frontmatter/base.schema.json`](./schemas/frontmatter/base.schema.json) so every Provider's per-kind schema accepts it without each having to redeclare. These represent intrinsic categories the file's author wrote into the frontmatter (vendor-supplied or your own writing).
660
- - **User tags** live in `sidecar.annotations.tags` (in the `.sm`). Curated annotation field declared on [`schemas/annotations.schema.json`](./schemas/annotations.schema.json). These represent the post-hoc tags whoever curates the project assigned to the node from their sidecar.
659
+ Tags are a **skill-map concept**, not a vendor field: no agent format (Claude, Cursor, Obsidian, the Agent Skills open standard, …) carries `tags` in its frontmatter, so skill-map keeps them where it owns the surface, the `.sm` sidecar.
661
660
 
662
- The two surfaces are **not aliases**. They capture different intent layers and both are first-class:
661
+ - **Tags** live in `sidecar.annotations.tags` (in the `.sm`). Curated annotation field declared on [`schemas/annotations.schema.json`](./schemas/annotations.schema.json). These are the tags whoever curates the project assigned to the node from their sidecar.
663
662
 
664
- - Search and listings (`sm list --tag <name>`, UI faceted search) match the **union**: a hit on either source returns the node.
665
- - The optional `--tag-source author|user` flag filters one source.
666
- - The UI distinguishes them visually so the attribution stays explicit (different chip style; author chips render first, user chips after).
663
+ Search and listings (`sm list --tag <name>`, UI faceted search) match this field: a hit returns the node. The UI renders them as chips on the node card and in the inspector.
667
664
 
668
- Persistence layer projects rows into a normalized [`scan_node_tags`](./db-schema.md#scan_node_tags) table at write time, one row per `(node_path, tag, source)` triple, so SQL queries can index on `(tag)` for `O(log n)` lookup. Replace-all per scan keeps the table in sync with the live frontmatter + sidecar state; deleting a tag from either source removes its row on the next scan.
665
+ Persistence layer projects rows into a normalized [`scan_node_tags`](./db-schema.md#scan_node_tags) table at write time, one row per `(node_path, tag)` pair, so SQL queries can index on `(tag)` for `O(log n)` lookup. Replace-all per scan keeps the table in sync with the live sidecar state; deleting a tag from a sidecar removes its row on the next scan.
669
666
 
670
- The wire shape (`/api/nodes` and `/api/nodes/:pathB64`) projects `node.tags = { byAuthor: string[], byUser: string[] }` so consumers see the split with attribution. The kernel `Node` interface (TypeScript) does NOT carry `tags`, consumers that walk the canonical sources read `node.frontmatter.tags` and `node.sidecar.annotations.tags` directly (consistent with the post-decision-#2 posture of "no Node-level denormalisations").
667
+ The wire shape (`/api/nodes` and `/api/nodes/:pathB64`) projects `node.tags = string[]`. The kernel `Node` interface (TypeScript) does NOT carry `tags`, consumers that walk the canonical source read `node.sidecar.annotations.tags` directly (consistent with the post-decision-#2 posture of "no Node-level denormalisations").
671
668
 
672
669
  ### Stability
673
670
 
@@ -806,7 +803,7 @@ Endpoints under `/api/contributions/*`:
806
803
 
807
804
  Plus catalog embedding into every payload-bearing envelope:
808
805
 
809
- - `kindRegistry` and `contributionsRegistry` are siblings on the envelope (see schema). Built once per server boot, embedded into list (`nodes` / `links` / `issues` / `plugins`), single (`node`), and value (`config`) envelopes. Sentinel envelopes (`health` / `scan` / `graph`) and action-result envelopes (`sidecar.bumped`) and the catalog envelopes themselves (`annotations.registered` / `contributions.registered`) carry neither.
806
+ - `kindRegistry`, `providerRegistry`, and `contributionsRegistry` are siblings on the envelope (see schema). Built once per server boot, embedded into list (`nodes` / `links` / `issues` / `plugins`), single (`node`), and value (`config`) envelopes. Sentinel envelopes (`health` / `scan` / `graph`) and action-result envelopes (`sidecar.bumped`) and the catalog envelopes themselves (`annotations.registered` / `contributions.registered`) carry none of them. `providerRegistry` is the static boot catalog of registered Providers' identity; the dynamic active lens (current value + filesystem-detected candidates) is served separately by `GET /api/active-provider`.
810
807
 
811
808
  Plus per-node embedding on node responses:
812
809
 
package/cli-contract.md CHANGED
@@ -82,7 +82,7 @@ The project sees its filesystem through exactly one **active provider lens** at
82
82
 
83
83
  CLI surfaces:
84
84
 
85
- - **Auto-detect on first scan**: when `activeProvider` is absent, `sm scan` and `sm watch` run a filesystem heuristic (`.claude/` → `claude`, `.codex/` or root `AGENTS.md` → `openai`, `.cursor/` → `cursor`, etc.). On unambiguous match, the result is persisted to `settings.json` and the scan proceeds; on no match, the CLI exits non-zero with a "no provider detected, set `activeProvider` in settings or install a provider plugin" message. On ambiguous match (multiple providers detected), the CLI prompts the user interactively (or fails with exit code 2 under `--yes` if no default is configured). Google's Antigravity CLI does not have a vendor-specific filesystem marker (it adopted the open-standard `.agents/` layout); the `antigravity` lens is set manually via `sm config set activeProvider antigravity`.
85
+ - **Auto-detect on first scan**: when `activeProvider` is absent, `sm scan` and `sm watch` run a filesystem heuristic driven by each Provider's manifest `detect.markers` (e.g. `.claude/` → `claude`, `.codex/` or root `AGENTS.md` → `openai`, `.agents/` → `agent-skills`). The marker set is provider-owned, not a central hardcoded table, so the detectable set derives from the registered Providers. On unambiguous match, the result is persisted to `settings.json` and the scan proceeds; on no match, the CLI exits non-zero with a "no provider detected, set `activeProvider` in settings or install a provider plugin" message. On ambiguous match (multiple providers detected), the CLI prompts the user interactively (or fails with exit code 2 under `--yes` if no default is configured). Google's Antigravity CLI does not declare a vendor-specific marker (it adopted the open-standard `.agents/` layout, which auto-detects as the universal `agent-skills` lens); the `antigravity` lens is set manually via `sm config set activeProvider antigravity`.
86
86
  - **Manual override**: `sm config set activeProvider <id>` switches the lens. The verb drops the `scan_*` zone atomically (see [`db-schema.md`](./db-schema.md#zones)) and triggers an immediate rescan under the new lens. `state_*` and `config_*` zones survive.
87
87
  - **No per-scan flag**: there is no `sm scan --provider=<id>` flag. The lens is a project-level decision, not a per-invocation parameter. The drop+rescan cost makes per-invocation switching the wrong default UX.
88
88
 
@@ -285,6 +285,8 @@ The watcher subscribes to the same roots that `sm scan` walks and respects `.ski
285
285
 
286
286
  **Node cap** (`--max-nodes <N>`): on `sm scan` and `sm watch` (alias `sm scan --watch`), a hard cap on the number of files the walker accepts after `.skillmapignore` filtering, before extractors run. Default comes from `scan.maxNodes` (default 256). The flag is a full override of the setting and is **bidirectional**: it can raise the cap (`--max-nodes 1000` on a 312-file repo) or lower it (`--max-nodes 100` cuts deeper than the default). When the walker reaches the cap, additional files are dropped in stable provider-walker order and the scan is marked oversized in `scan_meta` (columns `recommended_node_limit` and `override_max_nodes`), the resulting `ScanResult` envelope carries `recommendedNodeLimit` and `overrideMaxNodes` so the UI raises a persistent banner pointing at the `.skillmapignore` editor in Settings → Project. The CLI prints a human-mode notice naming both escapes: edit `.skillmapignore` (preferred, trims permanently) or re-run with `--max-nodes <N>` (force, graph quality may degrade past the recommended limit). `sm refresh` operates on a single already-classified node, so the cap does not apply there. Validation: integer ≥ 1, anything else exits `2` operational.
287
287
 
288
+ **Schema-drift rebuild (pre-1.0)**: before persisting, `sm scan` and `sm watch` compare `scan_meta.scanned_by_version` against the running CLI. A minor or major difference means the local cache predates a schema change, so the DB is deleted and rebuilt from scratch by this run (`.sm` sidecars are untouched, they are the source of truth). On an interactive terminal the rebuild is confirmed first; `--yes` (and every non-interactive caller: piped stdin, CI, the BFF, the watcher) rebuilds without prompting. Declining aborts the scan (exit `2`) without deleting anything. Patch-level differences are compatible and never trigger a rebuild. Read-only verbs keep the version-skew advisory instead of rebuilding. See [`db-schema.md` §Schema drift (pre-1.0)](./db-schema.md#schema-drift-pre-10).
289
+
288
290
  Exit: 0 on clean (or clean watcher shutdown), 1 if error-severity issues exist (one-shot scan only, the watcher does not flip exit code based on per-batch issues), 2 on operational error.
289
291
 
290
292
  ---
@@ -581,6 +583,8 @@ List endpoints conform to [`schemas/api/rest-envelope.schema.json`](schemas/api/
581
583
 
582
584
  **`kindRegistry` envelope field.** Every payload-bearing variant of the REST envelope (`nodes` / `links` / `issues` / `plugins` lists, the `node` single, the `config` value envelope) embeds a required `kindRegistry: { [kindName]: { providerId, label, color, colorDark?, emoji?, icon? } }` field. Sentinel envelopes (`health`, `scan`, `graph`) are exempt, they carry no payload at the wire level. The BFF assembles the registry once at boot from EVERY built-in Provider's `kinds[*].ui` block (regardless of the boot-time enabled verdict, their module code is statically imported by `built-in-bundles.ts` and always in memory) PLUS every drop-in user Provider that loaded successfully at boot (see [`architecture.md` §Provider · `ui` presentation](architecture.md#provider--ui-presentation)). The registry is then attached to every applicable response. Built-ins are listed unconditionally because a user re-enabling one mid-session expects its kinds to render on the next scan; the runtime enabled/disabled axis is enforced at SCAN-TIME by `composeScanExtensions` reading the fresh resolver, not by hiding kinds from the registry. Drop-ins that loaded as `disabled` carry `startsAsDisabled: true` on `GET /api/plugins` and need `sm serve` restart to register, their module code was never imported. The UI consumes `kindRegistry` directly to render kind palettes, list rows, and inspector headers, built-in and user-plugin kinds render identically. A kind appearing in a response payload (e.g. `node.kind`) without a matching `kindRegistry` entry is a contract violation; the kernel rejects Providers without a `ui` block at load time so the registry is always complete for whatever kinds appear in the response.
583
585
 
586
+ **`providerRegistry` envelope field.** The same payload-bearing envelopes also embed a required `providerRegistry: { [providerId]: { label, color, colorDark?, emoji?, icon?, hideChip? } }` field (sibling of `kindRegistry`). Sentinel envelopes (`health`, `scan`, `graph`), action-result envelopes (`sidecar.bumped`), and the catalog envelopes (`annotations.registered`, `contributions.registered`) are exempt. Same boot-time assembly discipline as `kindRegistry`: assembled once from EVERY built-in Provider's top-level `presentation` block (regardless of enabled verdict) PLUS every drop-in user Provider that loaded at boot. The UI consumes `providerRegistry` to render the active-lens dropdown, the topbar lens chip, and the per-node provider chip from the real registered-Provider set, never a hardcoded list; `hideChip: true` (the universal `markdown` fallback) suppresses only the per-card chip. This is the static boot catalog of Provider identity; the dynamic active lens (current value + filesystem-detected candidates) is served separately by `GET /api/active-provider`.
587
+
584
588
  **`contributionsRegistry` envelope field.** Same payload-bearing envelopes also embed `contributionsRegistry: { "<pluginId>/<extensionId>/<contributionId>": { pluginId, extensionId, contributionId, slot, label?, tooltip?, icon?, emptyText?, emitWhenEmpty } }`. Same boot-time assembly discipline as `kindRegistry`: ALL built-in declarations are listed regardless of enabled state (so re-enabling a built-in mid-session renders correctly on the next scan), plus drop-in user plugins that loaded at boot. The `slot` value comes from the closed catalog in `spec/schemas/view-slots.schema.json`. A view contribution emitted by an extension whose qualified id is missing from the registry is dropped by the UI's slot host (mirrors the kindRegistry contract, `startsAsDisabled` drop-ins illustrate the absence path).
585
589
 
586
590
  **Error envelope** (mirrors `§Machine-readable output analyzers`):
@@ -51,7 +51,7 @@ Fixtures are read-only inputs. Cases declare what to invoke and what to assert.
51
51
 
52
52
  ## Case format
53
53
 
54
- Cases are validated against [`conformance-case.schema.json`](../schemas/conformance-case.schema.json). That file is the normative shape; this section is the human-readable walkthrough. Include `"$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json"` in every case file for IDE support.
54
+ Cases are validated against [`conformance-case.schema.json`](../schemas/conformance-case.schema.json). That file is the normative shape; this section is the human-readable walkthrough. Include `"$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json"` in every case file for IDE support.
55
55
 
56
56
  A case is a JSON document with this shape:
57
57
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
2
+ "$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
3
3
  "id": "extractor-emits-signal",
4
4
  "description": "Signal IR resolver phase, end-to-end. A body that contains a single `[text](path)` markdown link MUST flow through the Signal IR resolver (Phase 2 of the active-lens migration): `core/markdown-link` emits a single-candidate Signal, the resolver materialises the winning candidate as a Link, and the result lands in `scan.links` with the same shape a direct `emitLink` call would have produced. Locks the contract that the Signal IR path coexists with the direct-emit path and produces indistinguishable Link rows.",
5
5
  "fixture": "signal-ir-single-signal",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
2
+ "$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
3
3
  "id": "kernel-empty-boot",
4
4
  "description": "With every Provider, extractor, and analyzer disabled, scanning an empty scope MUST return a valid, zero-filled ScanResult. Enforces the kernel boot invariant from architecture.md.",
5
5
  "setup": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
2
+ "$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
3
3
  "id": "no-global-scope",
4
4
  "description": "Skill-map operates exclusively on the project scope. Implementations MUST NOT expose a `-g/--global` flag (the historical opt-in for a global / user scope) on any verb. Passing the flag to any verb MUST be rejected as an unknown option (exit `2`, usage error) without writing any state. Guards the principle declared in `cli-contract.md` §Scope is always project-local.",
5
5
  "invoke": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
2
+ "$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
3
3
  "id": "orphan-markdown-fallback",
4
4
  "description": "spec 0.18.0 universal markdown fallback. A `.md` file no vendor-specific Provider classifies (e.g. `ARCHITECTURE.md` at the project root) MUST be picked up by the built-in `core/markdown` Provider, classified as kind `markdown`, and attributed to the `markdown` provider id. The orchestrator's path-dedup ensures vendor Providers retain priority on files inside their territory (`.claude/agents/reviewer.md` here stays with `claude` as `agent`). Locks the contract that markdown is provider-agnostic and the kernel emits no privileged kinds.",
5
5
  "fixture": "orphan-markdown",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
2
+ "$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
3
3
  "id": "plugin-missing-ui-rejected",
4
4
  "description": "A drop-in Provider plugin whose `kinds[*]` entry omits the required `ui` block (Step 14.5.d) MUST be rejected by the loader with a clear `missing required property 'ui'` diagnostic on stderr, AND `sm scan` MUST exit cleanly with the rest of the pipeline (built-in Claude Provider) still running. Locks the contract that one bad plugin does not take down the scan.",
5
5
  "fixture": "plugin-missing-ui",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
2
+ "$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
3
3
  "id": "sidecar-end-to-end",
4
4
  "description": "Step 9.6.6 — co-located `.sm` sidecar end-to-end. Scanning a fixture that carries a stale sidecar (wrong `identity.{bodyHash,frontmatterHash}`) plus an orphan sidecar (no sibling `.md`) MUST surface `sidecar.status` on the node and emit both `annotation-stale` (per stale node) and `annotation-orphan` (per orphan `.sm`) issues from the built-in core analyzers.",
5
5
  "fixture": "sidecar-end-to-end",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
2
+ "$schema": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
3
3
  "id": "signal-collision-detection",
4
4
  "description": "Signal IR resolver phase, range-overlap collision. A body that contains `[@./api.md](./api.md)` triggers a cross-extractor range overlap: `core/markdown-link` matches the whole bracketed-and-parenthesised span; `claude/at-directive` matches the `@./api.md` token INSIDE the bracket text. The two byte ranges overlap (the at-directive range is a strict subset of the markdown-link range). The kernel resolver picks ONE winner per the four-step tiebreak (`kind-priority` -> `higher-confidence` -> `longer-range` -> `earlier-declaration`); markdown-link wins on confidence (1.0 vs 0.85). The resolver materialises the winner as a Link, marks the loser's `resolution.outcome === 'rejected'` with `rejectedBy` naming the winner, and the built-in `core/signal-collision` analyzer surfaces the rejection as ONE `warn` issue attached to the source node. Locks the contract that range-overlap collisions surface to the operator instead of being silently merged.",
5
5
  "fixture": "signal-ir-collision",
@@ -10,6 +10,10 @@
10
10
  export default {
11
11
  version: '0.1.0',
12
12
  description: 'provider whose markdown kind is missing the ui block',
13
+ // Provider-level `presentation` is present and valid, so the loader
14
+ // gets past manifest validation and fails specifically on the KIND's
15
+ // missing `ui` block (the focus of this case).
16
+ presentation: { label: 'Bad', color: '#000000' },
13
17
  async *walk() {},
14
18
  classify() {
15
19
  return 'markdown';
@@ -1,7 +1,7 @@
1
1
  # Sample sidecar matching agent-example.md.
2
2
  # Validates against:
3
- # - https://skill-map.dev/spec/v0/sidecar.schema.json (root shape)
4
- # - https://skill-map.dev/spec/v0/annotations.schema.json (annotations block)
3
+ # - https://skill-map.ai/spec/v0/sidecar.schema.json (root shape)
4
+ # - https://skill-map.ai/spec/v0/annotations.schema.json (annotations block)
5
5
  # Hashes are sha256 over the kernel's canonical forms (body bytes; canonical YAML
6
6
  # of the frontmatter via `js-yaml` dump with sortKeys+noCompatMode). Regenerate
7
7
  # when agent-example.md changes (the fixture is meant to be drift-free).
@@ -31,7 +31,7 @@ annotations:
31
31
  - typescript
32
32
  - quality
33
33
  hidden: false
34
- docsUrl: https://skill-map.dev/examples/code-reviewer
34
+ docsUrl: https://skill-map.ai/examples/code-reviewer
35
35
 
36
36
  settings: {}
37
37
 
package/db-schema.md CHANGED
@@ -246,19 +246,18 @@ NOT analogous to `state_plugin_kvs` (which is plugin-managed). Belongs to the `s
246
246
 
247
247
  ### `scan_node_tags`
248
248
 
249
- Tags · dual-source. One row per `(node_path, tag, source)` triple, projected at persist time from BOTH `frontmatter.tags` (with `source='author'`) and `sidecar.annotations.tags` (with `source='user'`). Drives `sm list --tag <name>` and the UI's tag-faceted search; the `(tag)` index keeps "find all nodes with tag X" `O(log n)`.
249
+ Tags. One row per `(node_path, tag)` pair, projected at persist time from `sidecar.annotations.tags`. Tags are a skill-map concept (no vendor carries `tags` in frontmatter), so the sidecar is the single source. Drives `sm list --tag <name>` and the UI's tag-faceted search; the `(tag)` index keeps "find all nodes with tag X" `O(log n)`.
250
250
 
251
251
  | Column | Type | Constraint |
252
252
  |---|---|---|
253
253
  | `node_path` | TEXT | NOT NULL | FK semantically to `scan_nodes.path`; orphan-swept on persist when the parent node disappears. |
254
254
  | `tag` | TEXT | NOT NULL | Free-form; case-preserving. Empty strings rejected upstream by the schema's `minLength: 1` on each item. |
255
- | `source` | TEXT | NOT NULL CHECK (source IN ('author','user')) | Hard split: `'author'` = `frontmatter.tags`, `'user'` = `sidecar.annotations.tags`. The same tag string MAY appear under both sources for the same node (the PK accepts the pair); `sm list --tag X` returns the node once via DISTINCT, the UI renders both chips with their attribution. |
256
255
 
257
- Primary key: `(node_path, tag, source)`. Indexes: `ix_scan_node_tags_tag` (search by tag), `ix_scan_node_tags_node_path` (per-node lookup, e.g. inspector projection).
256
+ Primary key: `(node_path, tag)`. Indexes: `ix_scan_node_tags_tag` (search by tag), `ix_scan_node_tags_node_path` (per-node lookup, e.g. inspector projection).
258
257
 
259
- **Persistence, replace-all per scan.** Every persisted scan rebuilds the table for the live node set: rows whose `node_path` is NOT in `livePaths` are dropped (orphan sweep, same as the contributions table); rows for nodes in the live set are wiped and re-inserted from the projected source state. Cached nodes' tag rows are projected from the cached `node.frontmatter.tags` / `node.sidecar.annotations.tags` (both already in memory), so the rebuild is cheap regardless of cache hit / miss. Storage is small, a 50-node project with avg 3 tags/node is ~150 rows ≈ 7.5 KB.
258
+ **Persistence, replace-all per scan.** Every persisted scan rebuilds the table for the live node set: rows whose `node_path` is NOT in `livePaths` are dropped (orphan sweep, same as the contributions table); rows for nodes in the live set are wiped and re-inserted from the projected sidecar state. Cached nodes' tag rows are projected from the cached `node.sidecar.annotations.tags` (already in memory), so the rebuild is cheap regardless of cache hit / miss. Storage is small, a 50-node project with avg 3 tags/node is ~150 rows ≈ 7.5 KB.
260
259
 
261
- The wire shape on `/api/nodes` joins this table to project `node.tags = { byAuthor: string[], byUser: string[] }`. The kernel `Node` interface (TypeScript) does NOT carry `tags`, consumers walking the canonical sources read `node.frontmatter.tags` and `node.sidecar.annotations.tags` directly (consistent with the post-decision-#2 posture).
260
+ The wire shape on `/api/nodes` joins this table to project `node.tags = string[]`. The kernel `Node` interface (TypeScript) does NOT carry `tags`, consumers walking the canonical source read `node.sidecar.annotations.tags` directly (consistent with the post-decision-#2 posture).
262
261
 
263
262
  ---
264
263
 
@@ -464,6 +463,21 @@ The kernel ALSO maintains `PRAGMA user_version` (or the engine equivalent) as a
464
463
 
465
464
  ---
466
465
 
466
+ ## Schema drift (pre-1.0)
467
+
468
+ The project DB is a derived cache: every `scan_*` row is regenerable, and the operator's authored data lives in `.sm` sidecars, not in the DB. While the kernel stays in `0.Y.Z` (see [`versioning.md` §Pre-1.0](./versioning.md#pre-10)) it does NOT ship incremental migrations to carry an existing DB across a schema change. Instead, a write-side open (`sm scan`, `sm watch`, and the BFF watcher) compares `scan_meta.scanned_by_version` against the running CLI version:
469
+
470
+ - **Same `major.minor`** (patch differences ignored): the cache is compatible. The open proceeds untouched.
471
+ - **Any minor or major difference**: the on-disk schema is treated as drifted. The entire DB file (plus its `-wal` / `-shm` sidecars) is deleted and recreated from the current `001_initial.sql`; the scan then repopulates it. No backup is written (the cache is derived). `state_*` and `config_*` are wiped along with `scan_*`; pre-1.0 they are accepted as transient. `.sm` sidecars are never touched.
472
+
473
+ The rebuild is confirmed interactively on a TTY `sm scan` unless `--yes` is passed; non-interactive callers (piped stdin, CI, the BFF scan route, the watcher) rebuild without prompting. Declining the prompt aborts the scan (exit `2`) without deleting anything.
474
+
475
+ Read-side verbs (`sm check`, `sm list`, `sm show`, ...) do NOT rebuild. They keep the version-skew advisory (warn on an older DB, refuse on a newer or different-major DB) so a read never silently discards the cache.
476
+
477
+ This is a pre-1.0 affordance. The first `1.0.0` replaces it with real up-only migrations (see §Migrations): drift detection by version becomes drift repair by migration, and `state_*` / `config_*` stop being disposable.
478
+
479
+ ---
480
+
467
481
  ## Plugin storage
468
482
 
469
483
  Two modes declared in `plugin.json` (see [`schemas/plugins-registry.schema.json`](./schemas/plugins-registry.schema.json)).
package/index.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "indexPayloadVersion": "0.0.1",
3
3
  "dialect": "https://json-schema.org/draft/2020-12/schema",
4
- "canonicalUrlPrefix": "https://skill-map.dev/spec/v0",
4
+ "canonicalUrlPrefix": "https://skill-map.ai/spec/v0",
5
5
  "schemas": {
6
6
  "topLevel": [
7
7
  {
@@ -174,85 +174,85 @@
174
174
  }
175
175
  ]
176
176
  },
177
- "specPackageVersion": "0.38.0",
177
+ "specPackageVersion": "0.40.0",
178
178
  "integrity": {
179
179
  "algorithm": "sha256",
180
180
  "files": {
181
- "CHANGELOG.md": "ecd667be3c62b547ac786dc864763778d7591ff43ccdf5c80d40647d299f3498",
182
- "README.md": "1c4b0ea58c4324f301043e9f5c36976a382d0bd2bc405a2e4e18463b0c50d946",
183
- "architecture.md": "b9fba6c60ecd32ad2440c804dc9d47b7211873add6dea73401e13dc26bfee277",
184
- "cli-contract.md": "d7d16ff61e53ba282660111c01b4d92c756c4c429944701bf79035d62408c972",
185
- "conformance/README.md": "6871dde25b5770ed945284c9e0f749e0768ec3f5ba4966bdb215985789e43887",
186
- "conformance/cases/extractor-emits-signal.json": "34b4808c232d66a0eea0f5db7632a746681432b4f0995b6bf39e8d675538451c",
187
- "conformance/cases/kernel-empty-boot.json": "2a5be9c93143d07a16d998df09dcc8fa4ea2d2f9a0bff6417573ed5a770352c1",
188
- "conformance/cases/no-global-scope.json": "1284763988026d924c0bd78ba8a9f417dc88f5b7e9f4c2b642ae0c447758bfd4",
189
- "conformance/cases/orphan-markdown-fallback.json": "8ef6e49b7e6532bd845d9f54974a16e537cf98d355f0c5e4f4fb06abac3adcc5",
190
- "conformance/cases/plugin-missing-ui-rejected.json": "59a571a2e80c2bac2050eacbe740f4f3f125849dd242954508f011304cc3e036",
191
- "conformance/cases/sidecar-end-to-end.json": "dbb3640f95769a36b881855a261f918481edadea13a7eb0765c6090f2417a142",
192
- "conformance/cases/signal-collision-detection.json": "38c6d553c6f82c1b624fb8a8e9b4fc72034fc47bc70f7f011b3b9136817e7388",
181
+ "CHANGELOG.md": "bf36e063acb6ee636f39cd461c461a4cb9c2cc20d4097f8d1fffc803d99277df",
182
+ "README.md": "936d8e20cd46dc535ab46f19812749df2ee9b81dda3062cda2995bdc292a7a7f",
183
+ "architecture.md": "870446e462a0c06162528bbd496a2095f6d7e6aec620427a76648337dd524003",
184
+ "cli-contract.md": "aacf84d3314df36f127696b36bc0bdd47111c5c09d57b51d8e3859ea263ec9da",
185
+ "conformance/README.md": "0c69bd9becf511ada9175b1e428ba183e31d1c8a49ff09eedf4c950bb831ec4d",
186
+ "conformance/cases/extractor-emits-signal.json": "0115c7bb62a7a705f72e9d8048b3f0396e5caaeb3d04dea204415e279e58479d",
187
+ "conformance/cases/kernel-empty-boot.json": "9b51b85ff62479cd0eee37cad260245208d94f6d79644f7ee40945a934960913",
188
+ "conformance/cases/no-global-scope.json": "1c83343422144be2ad9e3d27d2062e61af87c7c1c1f3b051b6b9f687d845ac7b",
189
+ "conformance/cases/orphan-markdown-fallback.json": "506119323ddde85c1fb4c986c7f6f40a345d44adb06de8d84002591df0e479ee",
190
+ "conformance/cases/plugin-missing-ui-rejected.json": "7c910b74e6f718ab5c1a590cd3544602f056559251d18995a26bca0a0648a2fa",
191
+ "conformance/cases/sidecar-end-to-end.json": "2de448c52a93139143e5290df2842d898b3984c91fbee315d7a26157efd9b123",
192
+ "conformance/cases/signal-collision-detection.json": "c5e39a406ded6928a14c1a22b84f7b3cd49805bec56bd65de83130d9e419c09e",
193
193
  "conformance/coverage.md": "106468a6d9a65e5fdefbf75c8de4abecf35d5c08f2b6c44423741c60b723baea",
194
194
  "conformance/fixtures/orphan-markdown/.claude/agents/reviewer.md": "7f062731106f2d9811e4fffcf6ab44b8dfff4cfb16536a469514cc0664e832bf",
195
195
  "conformance/fixtures/orphan-markdown/ARCHITECTURE.md": "ec903666440bae65da3796b1158c92cfcdce22e0e09c3b20bb690176881a6ac4",
196
196
  "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/kinds/markdown/kind.json": "6676a89bae5197e23cf50f1c11d596db558ac80f7334a7208fe57d8b92422251",
197
197
  "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/kinds/markdown/schema.json": "42795e7f1759fa25115a426edf5cd1b0c91b091b408aeee3f4f9fbc8f89f32bc",
198
198
  "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/plugin.json": "15164a6bc9e3ad21cefa532af3d4edff1b10cf6140d7f576332dc38800512e35",
199
- "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/providers/bad-provider/index.js": "6eac0555de4194c3266c2abef89e39d833159990e1822ae1d4895df67c31d18f",
199
+ "conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/providers/bad-provider/index.js": "df0d9f200e401b6b13115d6e97e5a00a78074229bd86c22ec5321accf5673c01",
200
200
  "conformance/fixtures/plugin-missing-ui/notes/example.md": "55767f0aa1b6774546a99f28c58e7b732aa9cfa5dfce8d0326470f7f622f577e",
201
201
  "conformance/fixtures/preamble-v1.txt": "1e0aeef224b64477bdc13a949c3ad402e68249caf499ecdba1302371677c068b",
202
202
  "conformance/fixtures/sidecar-end-to-end/.claude/agents/orphan.sm": "3102ff10a0f08f60c014f82409d45ad4faf2cefa04d652a87676d3557ad64944",
203
203
  "conformance/fixtures/sidecar-end-to-end/.claude/agents/stale.md": "cb3a95777cba530d47e6040c5601b6dcd34b5fc653dd69f183369eb6bdd956b5",
204
204
  "conformance/fixtures/sidecar-end-to-end/.claude/agents/stale.sm": "cb04f7f3103b4218b09fd4da92f7ea429588b04c1dac6a9547ce362263b11224",
205
205
  "conformance/fixtures/sidecar-example/agent-example.md": "741131403e8c9580d0b7a8c2446cb4502d01f80053b7a2092663de92431aaa82",
206
- "conformance/fixtures/sidecar-example/agent-example.sm": "8329950d49c69a1199bbe6c06e32b8513973e64207b0db8756b67301e6a1f1e2",
206
+ "conformance/fixtures/sidecar-example/agent-example.sm": "fba04f4d81c6c3308316dca9bb5cdd72471052df577ed939c1c1915deeb5dd0f",
207
207
  "conformance/fixtures/signal-ir-collision/.claude/agents/api.md": "7bdd260d82c2bf1ffc3324820e1b806684674981f9234f7c9f4f6aa61dd1cec5",
208
208
  "conformance/fixtures/signal-ir-collision/.claude/agents/architect.md": "acc46b5b2dff73d98a354e4d53b5041164595deae466a4e2ce41d7c5a72f28fb",
209
209
  "conformance/fixtures/signal-ir-single-signal/source.md": "1eda417b4c6eed372b66870e385c8d8cd631372b77cab7e996bb711e22218f89",
210
210
  "conformance/fixtures/signal-ir-single-signal/target.md": "527137f2b4f46c0034b0edc8932cf8613d2bf22ffaaf78f01085c82a3baaebe3",
211
- "db-schema.md": "840ed078fa86e8793738748b5f651b068b93162c942db1f341b0d61f00d18893",
211
+ "db-schema.md": "f05c72ea74f8b32cc9909a02db1b8c93aefdf10ee804892449cab4d72a158ce9",
212
212
  "interfaces/security-scanner.md": "e8049712b9cf7a07c786bf19f8f775f8ef9638f063f7fba5c7a8b1431b92f38e",
213
213
  "job-events.md": "9d5b35d4c451a7f8eef9915d85316d924ac52f1c026a316cdda5f1099d496854",
214
214
  "job-lifecycle.md": "9c429121f98a07c8795f8979ed1abc5e5334e3f89db51585a8da55c527ef855b",
215
215
  "plugin-author-guide.md": "f0039397cd19d1f0a02c4e0691f213514216188d001cf56f287e69f6631fd39e",
216
216
  "plugin-kv-api.md": "1acc69ed82433a74e35ada61d63a6d7379fb61046ff83de1e0facbe884c64704",
217
217
  "prompt-preamble.md": "9dd4f6d1bc6a425f8782fcee10cbe75909e8d64e28781fda56c2fae909b02f40",
218
- "schemas/annotations.schema.json": "e39990d47f53e25a1b3a5587a5714486d0b819b8eeaac10d42783a675296aee1",
219
- "schemas/api/rest-envelope.schema.json": "926c63af10574599da5583ed067788b4a72be427788f0aa11b61022fb9649461",
220
- "schemas/bump-report.schema.json": "2e6daff2435ef1a4af6c2c911fd3ce2a30ace40c8910dd6f675dd187fd40a99b",
221
- "schemas/conformance-case.schema.json": "f6d4c9fb92e79cb516eeeb9d042223572a3bd5ff8e7871a0becce13916f20cf6",
222
- "schemas/conformance-result.schema.json": "426998e4f5cb079778ca7d0233634667d4fbc5a7e399cc41211fabd768db8ee0",
223
- "schemas/execution-record.schema.json": "0d61e33f2dc1aaa4cc7337b5eac4ea8b9034022ce24bae9156c3c9f33204c250",
224
- "schemas/extensions/action.schema.json": "9f6c2427ce3f0d6fa329adf0f13129821116ab79a1d2a53f96464513ff044ebe",
225
- "schemas/extensions/analyzer.schema.json": "f9bed3ba1305b2b64da277dccfbe760f7c058c4bb62a2d845af9c75787f159f6",
226
- "schemas/extensions/base.schema.json": "679d256a317f5be7f80a80dd3ec0c9098ad7d2f7b20c99c70fc70d6a1eb738a6",
227
- "schemas/extensions/extractor.schema.json": "5994088bf669321d2a7b8262c07cc94e05e5e2f49a235ae5389b7c66ecc1b2e1",
228
- "schemas/extensions/formatter.schema.json": "d6d417df20260e5ddfe71f104b11a45873869706f86372c3c3c78c583e06e8d5",
229
- "schemas/extensions/hook.schema.json": "76bf2c07f9e689b3fd1c67cbad4516a4df10604f07103759e82670e5213ddcdf",
230
- "schemas/extensions/provider-kind.schema.json": "add3c5648721e67887eb971a76b39319628effac6315cffd51f7dcf679810740",
231
- "schemas/extensions/provider.schema.json": "ebf137271d46f7100c8c520b6aa1851b131a3192a2dea43a17fe82b790d263fb",
232
- "schemas/frontmatter/base.schema.json": "df0056a9478514a0db7a705e59868fa4f67673ac1cc9c9da979de4237cdd62a1",
233
- "schemas/history-stats.schema.json": "5170dec0299f3d04382a38079a27b1f26300a6b95fdb1ea0fae11050ad9f0574",
234
- "schemas/input-types.schema.json": "c713b768d0b0e3d0c764afb401189f7fb624a82b4e988b73aab015cf9c67c01f",
235
- "schemas/issue.schema.json": "fa3344e75f1c3a5304291ca355bb973046552a68871ad6eb4edafca1cd9e1be8",
236
- "schemas/job.schema.json": "e43e1761c99920beffe1de12ef8f32fe29f97838bd8686742b637c19c4dbb395",
237
- "schemas/link.schema.json": "8a01925a9a7c00bbe41cdcbf8eea9269955570d41484da93d4193232a7aa9070",
238
- "schemas/node.schema.json": "4d7c107ed9cd2f1b7cc4d716c547c06a00ed776bd6092d3979cac634cb5326a5",
239
- "schemas/plugins-doctor.schema.json": "bb03eedf5b462b661938a44fe48635705ec13e30a2381ba122c60412416b507d",
240
- "schemas/plugins-registry.schema.json": "bca763ec61419e001a5c0a4b00a2da77996bfd8113be3fcf8aaa2fa70ff65fef",
241
- "schemas/project-config.schema.json": "253991718f714bf9409279410067b9c0c0da71e32a1b889d2f30559a0030c369",
242
- "schemas/refresh-report.schema.json": "54519b8caf86ba84c182f9565be9b5084bc1631ae05e9217ee18f34c0039fff3",
243
- "schemas/report-base-deterministic.schema.json": "9d318d0181d121097c906ef3af1c52d71c782740bd04cf23418d7627ce2c3ed5",
244
- "schemas/report-base.schema.json": "a1021e9a59b4df9f99cd92454d797e88469766e7d49f52d231c4645ffdfdad8f",
245
- "schemas/scan-result.schema.json": "2ac5edeb607e0f7c26036c65066effefcbaa5a6d8534b2f42fa4e44a3964a9f6",
246
- "schemas/sidecar.schema.json": "8856c387477340efbdd0a585d74bfb07a99ba15b9ce593cc67d9efebc67c6bfc",
247
- "schemas/signal.schema.json": "7a9d36f13ee6fa269da7ab97e45d9831d10e0570e3f61005617128b423a4d4d8",
248
- "schemas/summaries/agent.schema.json": "bf540f9a804f2b43756ab33b7deb0462620d26e88cc9379c75a5f87d3b1b47d8",
249
- "schemas/summaries/command.schema.json": "c26f6965f77c5058608feb5e7b9f807395de8e015b0dea5efcdb44cb1820551a",
250
- "schemas/summaries/hook.schema.json": "58420ec485e152fdd21fa3d87337ad74b0d81a48d3b83dd072d4a2d196f78573",
251
- "schemas/summaries/markdown.schema.json": "f7b2b5ae9e4836c94bb6a84edc730412f19296a6ef13552016690d7ba6f5391d",
252
- "schemas/summaries/skill.schema.json": "a2e23e35fe1545fb7bb8a6bb87dcad2248afa5a0f23aebc089eb5464201f4654",
253
- "schemas/user-settings.schema.json": "969638f7235b2de2bbe38f291e3f576fc54f2f2f22e30b37d1578fd9e8538b51",
254
- "schemas/view-slots.schema.json": "b151740016585ab2ba6cde376b071fc79ef1a1b484032216d841afeb593d06fd",
255
- "versioning.md": "bab36cda6deb3edc29d7d40d97399ea4a213551257b0dd3321ddf95e2a60bff2"
218
+ "schemas/annotations.schema.json": "8c639b149cad675fdd4e7d6be2b47e920cfdd24087b41361d6e1b8280f646322",
219
+ "schemas/api/rest-envelope.schema.json": "19cd02c96faa12b59768cd9e2e74b8830a07fbcba104de797345b6a61c0f44c3",
220
+ "schemas/bump-report.schema.json": "c763e1f89f2665c479d6a4985c1d324c65e5278331ebab82220287a07e4c4429",
221
+ "schemas/conformance-case.schema.json": "958b316d646d0c64a715a7a28cee66d2c2d2498a60dbfc5ae8970687c2a96954",
222
+ "schemas/conformance-result.schema.json": "14f983a8f4e62cd4ff964688c9b2b026a3bee3a0b762b64091c8c34db5b75777",
223
+ "schemas/execution-record.schema.json": "db0eb16153493ad9f13ea0ecede44191e4a8536979adffd17ca278ddf8786c77",
224
+ "schemas/extensions/action.schema.json": "dc4f52d23c163c6239a487fa1c1ad9c09685cf38833d3962c604d5872716cff9",
225
+ "schemas/extensions/analyzer.schema.json": "8def4a5ca4934197c34abde97da70704b2751041a443c859eddd4b783e2fe1db",
226
+ "schemas/extensions/base.schema.json": "ee0f54acc769cc8e5295d703e69fd806f041b326a774dc8aaffab3380ed6906b",
227
+ "schemas/extensions/extractor.schema.json": "ee44bf562b19318c93116c574a811857cdef1f4119326a9a604fa408889dd230",
228
+ "schemas/extensions/formatter.schema.json": "880dc379ad545a62404403533a01eda5171edba0390561fc46ec6e986e0b9bd3",
229
+ "schemas/extensions/hook.schema.json": "f56aef59e9986ffdf7d86aa2e048dccccf217000a358b8c64737cbd911c48dad",
230
+ "schemas/extensions/provider-kind.schema.json": "499b2418bbe6d8a84a1608e26c56b52c2652a30ce314bc2989094418797dc1e6",
231
+ "schemas/extensions/provider.schema.json": "e536c3376ee5a04b6d4e971b6133a5af36e6f7e05973d88bb7236d4ab908830d",
232
+ "schemas/frontmatter/base.schema.json": "cff81510ed94824dfd12ab8b30ce9fbac65e42d61ae0edf3fbb6bbb6bb8bcb8c",
233
+ "schemas/history-stats.schema.json": "436aa0ffe744bdb699000447e86b45724fbd2cc4642781074eb1527522b9058c",
234
+ "schemas/input-types.schema.json": "cc9739aedcfdc72c1fa1285547e1392f9582169d578d72737918099acc721de0",
235
+ "schemas/issue.schema.json": "d173aa5c5312b3d2a2cd249f55c10943c8f3cd5799e4645ae3c66316221e12d1",
236
+ "schemas/job.schema.json": "dbcedf137de03fde38f74686f594e600c627bf808f2aad23511a26617a663a02",
237
+ "schemas/link.schema.json": "10f700feb3e23d89453d4d11cbe559bcc0b31f6edf08fffbe9e6773e58120512",
238
+ "schemas/node.schema.json": "14ed2e4c44d01e3f662e240219819895cca06dead374a5cadccfd423c520ed69",
239
+ "schemas/plugins-doctor.schema.json": "51e9087f4e4a20352dfba1c26e40e45eee5620e65db817241960e41fd5710d1c",
240
+ "schemas/plugins-registry.schema.json": "6d850d06cdf70e233f20d0d7968bb0c34306f11f30ce2505cec173cd9fa784e5",
241
+ "schemas/project-config.schema.json": "1403813ed7796d300634dc31aec9c2f0897da364febd5debcfa8af37da31ad81",
242
+ "schemas/refresh-report.schema.json": "47184d4f6b15e9b7671dc178b3b3886a64422da198898508ecdb2cb27876db04",
243
+ "schemas/report-base-deterministic.schema.json": "59785fe6f3ceb34814bbbd03d10fa7336a32835ce598946f2923d469b32aa32a",
244
+ "schemas/report-base.schema.json": "e4d25f055e24f18ae0f77c24661c1bddc87ff2e43b001b6a827fcb14f9753f44",
245
+ "schemas/scan-result.schema.json": "f9fafd6052c2a780cb5977a4bdd45d4890874443ae6551627c2e37f49500f14b",
246
+ "schemas/sidecar.schema.json": "f23dfe3ba7f71a1af2cc5cd26b57d5e057e56438655f750c1895d35061efe80a",
247
+ "schemas/signal.schema.json": "3f93a3641fbcf95586c52b97f15292cb1fffecef31db8aed642cd1574c2f3a0b",
248
+ "schemas/summaries/agent.schema.json": "5b26b95fb082b73d302c8aa6489ab09488a155ccfbb8943dfc47079509d35122",
249
+ "schemas/summaries/command.schema.json": "7f522c682d0fdf5a40172c7fc8fcd23e60a0ab0253354146525bd3a3d417f1f8",
250
+ "schemas/summaries/hook.schema.json": "6a1ceecda7a7173dfcd8b5f705d84be1792c4bb5a2269ff666088128c02c888a",
251
+ "schemas/summaries/markdown.schema.json": "369d75a18710eb6c7ee4220b2899767ddbc07dada24f81b611827fe2e3a2977a",
252
+ "schemas/summaries/skill.schema.json": "85d68056054bade62391948cc038fcfa70cdcf465e2b295f69cd520bbdba0134",
253
+ "schemas/user-settings.schema.json": "b94c5235c8723a8ee023ec71b4ffd7094100cbaeccbb648712ebc331fc879ef5",
254
+ "schemas/view-slots.schema.json": "f78d0c5f0414f01dc045680b655b3d636373048eae4b75cc9dbd0fe0babd60bc",
255
+ "versioning.md": "28a13f165f837921fe5066f4bfce61012cd9f1b7c451f88eeb67252e39a0981a"
256
256
  }
257
257
  }
258
258
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@skill-map/spec",
3
- "version": "0.38.0",
3
+ "version": "0.40.0",
4
4
  "description": "JSON Schemas, prose contracts, and conformance suite for the skill-map specification.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
- "homepage": "https://skill-map.dev",
7
+ "homepage": "https://skill-map.ai",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/crystian/skill-map.git",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://skill-map.dev/spec/v0/annotations.schema.json",
3
+ "$id": "https://skill-map.ai/spec/v0/annotations.schema.json",
4
4
  "title": "Annotations",
5
5
  "description": "Catalog of conventional annotation fields skill-map ships out of the box, written into the `annotations:` block of a sidecar (`<basename>.sm`). Every field is OPTIONAL, a sidecar with an empty `annotations: {}` is valid. Schema is `additionalProperties: true` so users / plugins can add custom keys without coordination; the built-in `unknown-field` analyzer emits a warning on unrecognized keys (typo guard). The curated catalog is the load-bearing 10 fields below, versioning + supersession (`version`, `stability`, `supersedes`, `supersededBy`), provenance (`authors`, `license`, `source`, `sourceVersion`), taxonomy (`tags`), docs (`docsUrl`). The activity timestamp lives in the reserved `audit:` block (`audit.lastBumpedAt`), not in `annotations:`. Plugins that want first-class custom keys with their own validation declare `annotationContributions` in their manifest (see Step 9.6.6).",
6
6
  "type": "object",
@@ -49,7 +49,7 @@
49
49
  "tags": {
50
50
  "type": "array",
51
51
  "items": { "type": "string", "minLength": 1 },
52
- "description": "**User-supplied** taxonomy tags. Skill-map's tag system is dual-source: this field carries the user's post-hoc tags (curator's view of the node from the `.sm` sidecar); `frontmatter.tags` carries the author's tags (intrinsic categories written in the `.md`). Both surfaces are first-class, `sm list --tag <name>` and UI faceted search match the union and the UI distinguishes them visually (`sm list --tag-source author|user` filters one source). Empty array and missing field are equivalent."
52
+ "description": "Taxonomy tags for this node. Tags are a **skill-map concept**, not a vendor field: no agent format carries `tags` in frontmatter, so they live here in the `.sm` sidecar. Written by whoever curates the project. `sm list --tag <name>` and the UI's faceted search match this field; the UI renders them as chips on the node card and inspector. Empty array and missing field are equivalent."
53
53
  },
54
54
  "docsUrl": {
55
55
  "type": "string",