@skill-map/spec 0.39.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.
- package/CHANGELOG.md +37 -2315
- package/README.md +2 -2
- package/architecture.md +6 -11
- package/cli-contract.md +2 -0
- package/conformance/README.md +1 -1
- package/conformance/cases/extractor-emits-signal.json +1 -1
- package/conformance/cases/kernel-empty-boot.json +1 -1
- package/conformance/cases/no-global-scope.json +1 -1
- package/conformance/cases/orphan-markdown-fallback.json +1 -1
- package/conformance/cases/plugin-missing-ui-rejected.json +1 -1
- package/conformance/cases/sidecar-end-to-end.json +1 -1
- package/conformance/cases/signal-collision-detection.json +1 -1
- package/conformance/fixtures/sidecar-example/agent-example.sm +3 -3
- package/db-schema.md +19 -5
- package/index.json +54 -54
- package/package.json +2 -2
- package/schemas/annotations.schema.json +2 -2
- package/schemas/api/rest-envelope.schema.json +1 -1
- package/schemas/bump-report.schema.json +1 -1
- package/schemas/conformance-case.schema.json +1 -1
- package/schemas/conformance-result.schema.json +1 -1
- package/schemas/execution-record.schema.json +1 -1
- package/schemas/extensions/action.schema.json +1 -1
- package/schemas/extensions/analyzer.schema.json +1 -1
- package/schemas/extensions/base.schema.json +1 -1
- package/schemas/extensions/extractor.schema.json +1 -1
- package/schemas/extensions/formatter.schema.json +1 -1
- package/schemas/extensions/hook.schema.json +1 -1
- package/schemas/extensions/provider-kind.schema.json +1 -1
- package/schemas/extensions/provider.schema.json +1 -1
- package/schemas/frontmatter/base.schema.json +2 -7
- package/schemas/history-stats.schema.json +1 -1
- package/schemas/input-types.schema.json +1 -1
- package/schemas/issue.schema.json +1 -1
- package/schemas/job.schema.json +1 -1
- package/schemas/link.schema.json +1 -1
- package/schemas/node.schema.json +1 -1
- package/schemas/plugins-doctor.schema.json +1 -1
- package/schemas/plugins-registry.schema.json +1 -1
- package/schemas/project-config.schema.json +1 -1
- package/schemas/refresh-report.schema.json +1 -1
- package/schemas/report-base-deterministic.schema.json +1 -1
- package/schemas/report-base.schema.json +1 -1
- package/schemas/scan-result.schema.json +1 -1
- package/schemas/sidecar.schema.json +1 -1
- package/schemas/signal.schema.json +1 -1
- package/schemas/summaries/agent.schema.json +1 -1
- package/schemas/summaries/command.schema.json +1 -1
- package/schemas/summaries/hook.schema.json +1 -1
- package/schemas/summaries/markdown.schema.json +1 -1
- package/schemas/summaries/skill.schema.json +1 -1
- package/schemas/user-settings.schema.json +1 -1
- package/schemas/view-slots.schema.json +1 -1
- 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.
|
|
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.
|
|
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
|
@@ -654,22 +654,17 @@ Two columns on `scan_nodes` source from the sidecar's `annotations:` block when
|
|
|
654
654
|
|
|
655
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.
|
|
656
656
|
|
|
657
|
-
### Tags
|
|
657
|
+
### Tags
|
|
658
658
|
|
|
659
|
-
|
|
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.
|
|
660
660
|
|
|
661
|
-
- **
|
|
662
|
-
- **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.
|
|
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
|
-
The
|
|
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.
|
|
665
664
|
|
|
666
|
-
-
|
|
667
|
-
- The optional `--tag-source author|user` flag filters one source.
|
|
668
|
-
- The UI distinguishes them visually so the attribution stays explicit (different chip style; author chips render first, user chips after).
|
|
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
|
-
|
|
671
|
-
|
|
672
|
-
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").
|
|
673
668
|
|
|
674
669
|
### Stability
|
|
675
670
|
|
package/cli-contract.md
CHANGED
|
@@ -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
|
---
|
package/conformance/README.md
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Sample sidecar matching agent-example.md.
|
|
2
2
|
# Validates against:
|
|
3
|
-
# - https://skill-map.
|
|
4
|
-
# - https://skill-map.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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.
|
|
4
|
+
"canonicalUrlPrefix": "https://skill-map.ai/spec/v0",
|
|
5
5
|
"schemas": {
|
|
6
6
|
"topLevel": [
|
|
7
7
|
{
|
|
@@ -174,22 +174,22 @@
|
|
|
174
174
|
}
|
|
175
175
|
]
|
|
176
176
|
},
|
|
177
|
-
"specPackageVersion": "0.
|
|
177
|
+
"specPackageVersion": "0.40.0",
|
|
178
178
|
"integrity": {
|
|
179
179
|
"algorithm": "sha256",
|
|
180
180
|
"files": {
|
|
181
|
-
"CHANGELOG.md": "
|
|
182
|
-
"README.md": "
|
|
183
|
-
"architecture.md": "
|
|
184
|
-
"cli-contract.md": "
|
|
185
|
-
"conformance/README.md": "
|
|
186
|
-
"conformance/cases/extractor-emits-signal.json": "
|
|
187
|
-
"conformance/cases/kernel-empty-boot.json": "
|
|
188
|
-
"conformance/cases/no-global-scope.json": "
|
|
189
|
-
"conformance/cases/orphan-markdown-fallback.json": "
|
|
190
|
-
"conformance/cases/plugin-missing-ui-rejected.json": "
|
|
191
|
-
"conformance/cases/sidecar-end-to-end.json": "
|
|
192
|
-
"conformance/cases/signal-collision-detection.json": "
|
|
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",
|
|
@@ -203,56 +203,56 @@
|
|
|
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": "
|
|
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": "
|
|
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": "
|
|
219
|
-
"schemas/api/rest-envelope.schema.json": "
|
|
220
|
-
"schemas/bump-report.schema.json": "
|
|
221
|
-
"schemas/conformance-case.schema.json": "
|
|
222
|
-
"schemas/conformance-result.schema.json": "
|
|
223
|
-
"schemas/execution-record.schema.json": "
|
|
224
|
-
"schemas/extensions/action.schema.json": "
|
|
225
|
-
"schemas/extensions/analyzer.schema.json": "
|
|
226
|
-
"schemas/extensions/base.schema.json": "
|
|
227
|
-
"schemas/extensions/extractor.schema.json": "
|
|
228
|
-
"schemas/extensions/formatter.schema.json": "
|
|
229
|
-
"schemas/extensions/hook.schema.json": "
|
|
230
|
-
"schemas/extensions/provider-kind.schema.json": "
|
|
231
|
-
"schemas/extensions/provider.schema.json": "
|
|
232
|
-
"schemas/frontmatter/base.schema.json": "
|
|
233
|
-
"schemas/history-stats.schema.json": "
|
|
234
|
-
"schemas/input-types.schema.json": "
|
|
235
|
-
"schemas/issue.schema.json": "
|
|
236
|
-
"schemas/job.schema.json": "
|
|
237
|
-
"schemas/link.schema.json": "
|
|
238
|
-
"schemas/node.schema.json": "
|
|
239
|
-
"schemas/plugins-doctor.schema.json": "
|
|
240
|
-
"schemas/plugins-registry.schema.json": "
|
|
241
|
-
"schemas/project-config.schema.json": "
|
|
242
|
-
"schemas/refresh-report.schema.json": "
|
|
243
|
-
"schemas/report-base-deterministic.schema.json": "
|
|
244
|
-
"schemas/report-base.schema.json": "
|
|
245
|
-
"schemas/scan-result.schema.json": "
|
|
246
|
-
"schemas/sidecar.schema.json": "
|
|
247
|
-
"schemas/signal.schema.json": "
|
|
248
|
-
"schemas/summaries/agent.schema.json": "
|
|
249
|
-
"schemas/summaries/command.schema.json": "
|
|
250
|
-
"schemas/summaries/hook.schema.json": "
|
|
251
|
-
"schemas/summaries/markdown.schema.json": "
|
|
252
|
-
"schemas/summaries/skill.schema.json": "
|
|
253
|
-
"schemas/user-settings.schema.json": "
|
|
254
|
-
"schemas/view-slots.schema.json": "
|
|
255
|
-
"versioning.md": "
|
|
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.
|
|
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.
|
|
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.
|
|
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": "
|
|
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",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/api/rest-envelope.schema.json",
|
|
4
4
|
"title": "RestEnvelope",
|
|
5
5
|
"description": "Wrapper shape for REST responses under `/api/*` (Step 14.2). Five variants distinguished by the `kind` discriminator and which payload field is present (`items` for list kinds AND `'annotations.registered'`, `item` for single-resource kinds, `value` for `kind: 'config'` and `'sidecar.bumped'`). The `/api/scan` and `/api/health` responses are exempt, they carry the underlying `ScanResult` / `IHealthResponse` shape directly. The `/api/graph` response is also exempt, it returns the formatter's native textual output (text/plain or text/markdown). Step 14.5.d adds the required `kindRegistry` field on every payload-bearing list / single / config variant so the UI can render Provider-declared kinds (label, color, icon) without hardcoding visuals; the sibling `providerRegistry` field carries the registered Providers' own identity (label, color, chip visibility) so the UI renders the active-lens dropdown and the per-node provider chip from the real Provider set instead of a hardcoded list. Sentinel kinds (`health`, `scan`, `graph`) stay exempt because they don't carry an envelope payload. Step 9.6 closes the `'sidecar.bumped'` (R7) and `'annotations.registered'` (R7) gaps, both are payload-bearing but carry their own variant shapes (sidecar.bumped: `value` + `elapsedMs`, no `filters`/`counts`/`kindRegistry`; annotations.registered: `items` + `counts.total`, no `filters`/`kindRegistry`) because they project read-only kernel surfaces orthogonal to the kindRegistry. The change keeps `schemaVersion` at `'1'`, the BFF is greenfield (no released consumers depend on the prior shape), so a versioned migration buys nothing.",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/bump-report.schema.json",
|
|
4
4
|
"title": "BumpReport",
|
|
5
5
|
"description": "Report shape produced by the built-in deterministic `node-bump` Action (Step 9.6.3, Decision #125). Extends `report-base-deterministic.schema.json` (the deterministic counterpart to `report-base.schema.json`, which carries the LLM-only `confidence` + `safety` fields). The `node-bump` Action returns one of three concrete shapes, distinguished by `ok` / `noop` / `reason`: success-with-write (`{ ok: true, version }`), silent-no-op under `force` (`{ ok: true, noop: true }`), or refusal (`{ ok: false, reason: 'fresh' }`).",
|
|
6
6
|
"allOf": [{ "$ref": "report-base-deterministic.schema.json" }],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/conformance-case.schema.json",
|
|
4
4
|
"title": "ConformanceCase",
|
|
5
5
|
"description": "Shape of a single declarative test case under `spec/conformance/cases/<id>.json`. Consumed by language-neutral conformance runners. See `spec/conformance/README.md` for the runner contract.",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/conformance-result.schema.json",
|
|
4
4
|
"title": "ConformanceResult",
|
|
5
5
|
"description": "Machine-readable output of `sm conformance run --json`. Aggregates pass / fail totals across the selected scope set plus per-scope and per-case breakdowns. The `elapsedMs` top-level field is the command's own wall-clock (see `cli-contract.md` §Elapsed time).",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/execution-record.schema.json",
|
|
4
4
|
"title": "ExecutionRecord",
|
|
5
5
|
"description": "A single row in the execution history (`state_executions`). One record per action invocation, regardless of whether the runner was CLI, Skill, or in-process.",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/action.schema.json",
|
|
4
4
|
"title": "ExtensionAction",
|
|
5
5
|
"description": "Manifest shape for an `Action` extension. An action operates on one or more nodes in one of two modes: `deterministic` (code runs in-process, returns a report JSON directly) or `probabilistic` (kernel renders a prompt, a runner executes it against an LLM, the callback closes the job). **Structure-as-truth files**: every Action carries `<action-dir>/report.schema.json` (the JSON Schema for the report, MUST extend `report-base.schema.json`); probabilistic Actions additionally carry `<action-dir>/prompt.md` (the prompt template). The kernel resolves both by convention; missing or mis-placed files surface as `load-error`. A deterministic Action with a `prompt.md` in its folder is also `load-error` (config inconsistent). **`prob*` prefix convention**: manifest fields that only apply when `mode=probabilistic` start with `prob`; if a deterministic-only field ever appears, it starts with `det`.",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/analyzer.schema.json",
|
|
4
4
|
"title": "ExtensionAnalyzer",
|
|
5
5
|
"description": "Manifest shape for an `Analyzer` extension. An analyzer consumes the full graph (nodes + links) after all extractors have run, emits `Issue[]`, and MAY emit view contributions to project findings into the UI. Analyzers are dual-mode: `deterministic` analyzers MUST be byte-for-byte reproducible (same graph in → same issues out; time, random, and network are forbidden) and run synchronously inside `sm check` / `sm scan`; `probabilistic` analyzers invoke an LLM through the kernel's `RunnerPort` and execute only as queued jobs (`sm job submit analyzer:<id>`); their output MAY vary across runs and they NEVER participate in `sm scan`. Each issue emitted is tagged with `analyzer_id = <plugin-id>/<extension-id>` by default (the extension's qualified id, derived from structure); analyzers that need to discriminate sub-types append `:<sub-id>` at emit time. Severity is set per-emit (no manifest-level default).",
|
|
6
6
|
"allOf": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/base.schema.json",
|
|
4
4
|
"title": "ExtensionBase",
|
|
5
5
|
"description": "Base manifest shape common to every extension kind. Kind-specific schemas (`provider`, `extractor`, `analyzer`, `action`, `formatter`, `hook`) extend this via `allOf` and add a kind-specific shape. Both `id` and `kind` are derived from the filesystem structure (`<plugin>/<kind-plural>/<id>/index.ts`, where the parent folder dictates the kind and the leaf folder dictates the id), so they are NOT manifest fields. Manifests carrying `id` or `kind` are rejected as `invalid-manifest`. Closed-content enforcement (unknown keys = bug) lives on the kind schemas via `unevaluatedProperties: false`; those see base's evaluated keys through the `allOf` composition.",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/extractor.schema.json",
|
|
4
4
|
"title": "ExtensionExtractor",
|
|
5
5
|
"description": "Manifest shape for an `Extractor` extension. An extractor consumes a parsed node (frontmatter + body) and emits output through three context-supplied callbacks rather than returning a value: `ctx.emitLink(link)` writes to the kernel's `links` table (validated against the global closed enum of link kinds before persistence; per-extractor whitelisting was retired with structure-as-truth, the global enum is the contract), `ctx.enrichNode(partial)` merges author-canonical properties into the kernel's enrichment layer (separate from the author-supplied frontmatter), `ctx.emitContribution(id, payload)` emits per-node view contributions validated against the slot payload schema, and `ctx.store` persists into the plugin's own KV namespace or dedicated tables. The runtime method is `extract(ctx) → void`. Extractors run in isolation: they MUST NOT read other nodes, the graph, or the DB. Cross-node reasoning lives in Analyzers. Extractors are deterministic-only: pure code, runs synchronously inside `sm scan`, same input → same output every run. LLM-driven enrichment of a node is an Action concern (queued as a job), not an Extractor concern.",
|
|
6
6
|
"allOf": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/formatter.schema.json",
|
|
4
4
|
"title": "ExtensionFormatter",
|
|
5
5
|
"description": "Manifest shape for a `Formatter` extension. A formatter serializes the graph (or a filtered subgraph) into a string in a declared format. The format id comes from the formatter's folder name (structure-as-truth, `<plugin>/formatters/<formatId>/index.ts`), it is NOT a manifest field. Invoked by `sm graph --format <formatId>` and `sm export`. Formatters are deterministic-only, they sit at the graph-to-string boundary and their output MUST be byte-deterministic for the same input graph (the snapshot-test suite relies on this). The `mode` field MUST NOT appear in formatter manifests. Probabilistic narrators of the graph are a valid product but they live in jobs and emit Findings, not in formatters. All formatters accept the `--filter` expression; opting out is no longer supported.",
|
|
6
6
|
"allOf": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/hook.schema.json",
|
|
4
4
|
"title": "ExtensionHook",
|
|
5
5
|
"description": "Manifest shape for a `Hook` extension. Subscribes declaratively to a curated set of kernel lifecycle events. **Hooks are deterministic-only** since the structure-as-truth refactor: the `mode` field was removed; LLM-dependent lifecycle behaviour is modeled as a deterministic hook that enqueues a probabilistic Action via `ctx.queue('<plugin>/<action>', payload)`. Hooks react to events; they cannot block or alter the main pipeline. The set of hookable triggers is intentionally small, ten events out of the full job-events catalog. Eight are pipeline-driven (emitted from inside `runScan`); two (`boot`, `shutdown`) are CLI-process-driven (emitted by the driving binary before / after the verb runs, fire-and-forget so `process.exit` is never blocked). Other events (per-node `scan.progress`, `model.delta`, `run.*`, internal job lifecycle) are deliberately not hookable: too verbose for a reactive surface, internal to the runner, or covered elsewhere. Declaring a trigger outside the hookable set yields `invalid-manifest` at load time.",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/provider-kind.schema.json",
|
|
4
4
|
"title": "ProviderKindMetadata",
|
|
5
5
|
"description": "Per-kind UI metadata written as `<plugin>/kinds/<kindName>/kind.json`. Lives next to the kind's frontmatter `schema.json` under the kind folder; together they are the structure-as-truth replacement for the old `kinds` map inside the Provider manifest. Reaches the UI via the `kindRegistry` field embedded in REST envelopes (`api/rest-envelope.schema.json`). The kind name is the folder name; it is NOT repeated as a field here.",
|
|
6
6
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/extensions/provider.schema.json",
|
|
4
4
|
"title": "ExtensionProvider",
|
|
5
5
|
"description": "Manifest shape for a `Provider` extension. A Provider declares its own universe: the platform it recognises (Claude Code, Codex, Antigravity, Obsidian vault, generic MD), the catalog of node `kind`s it emits, and the per-kind frontmatter schema each kind follows. **Structure-as-truth**: exactly one Provider lives in each plugin that carries one, declared as `<plugin>/provider.ts`. The kinds catalog lives as folders under `<plugin>/kinds/<kindName>/` and the loader discovers each entry by walking that directory; the manifest itself NO LONGER carries a `kinds` map. Each kind folder MUST contain `schema.json` (the kind's frontmatter JSON Schema, extending `frontmatter/base.schema.json` via `allOf` + `$ref`) and `kind.json` (UI metadata under `{ ui: {...} }`). The kernel resolves these at boot time and registers each schema with AJV for scan-time validation. Exactly zero or one Provider MUST match any given file; multiple matches → `provider-ambiguous` issue, file unclassified. **`roots` is enforcement-grade**: a Provider declaring `roots` only receives files matching at least one glob; a Provider without `roots` acts as a fallback for files unmatched by any other Provider's roots. Providers are deterministic-only, they sit at the filesystem boundary and run during boot; probabilistic classification would make boot slow, costly, and non-reproducible. The `mode` field MUST NOT appear in Provider manifests. If you need LLM-assisted classification, write a probabilistic Action that runs as a queued job and writes back through the enrichment layer; Extractors are deterministic-only and Providers stay on the deterministic boot path. Distinct from the **hexagonal-architecture** 'adapter' (`RunnerPort.adapter`, `StoragePort.adapter`, etc.), which is an internal driven-adapter implementing a port, Providers live in the extension surface, hexagonal adapters live in `src/kernel/adapters/`.",
|
|
6
6
|
"allOf": [
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/frontmatter/base.schema.json",
|
|
4
4
|
"title": "FrontmatterBase",
|
|
5
|
-
"description": "Universal frontmatter shape every Provider's per-kind schema extends via `allOf` + `$ref` to this `$id`. `name` and `description` are the
|
|
5
|
+
"description": "Universal frontmatter shape every Provider's per-kind schema extends via `allOf` + `$ref` to this `$id`. `name` and `description` are the only universal fields, confirmed by cross-vendor research: `description` is the single field every format carries, and `name` is universal among formats with explicit identifiers. Everything else is vendor idiosyncrasy and lives on the per-vendor per-kind schema, NOT here. (Taxonomy `tags`, for example, is a skill-map concept with no vendor frontmatter analog, so it lives in the `.sm` sidecar `annotations.tags`, not here.) Per-vendor schemas (Anthropic Claude, Cursor, Obsidian, the Agent Skills open standard, …) declare their own fields on top via the per-kind extension. `additionalProperties: true` is intentional: skill-map AGGREGATES vendor specs, it does not curate them. Vendor-specific fields (`tools`, `allowedTools`, `model`, etc.) flow through validation silently because the per-kind extension declares them.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["name", "description"],
|
|
8
8
|
"additionalProperties": true,
|
|
@@ -16,11 +16,6 @@
|
|
|
16
16
|
"type": "string",
|
|
17
17
|
"minLength": 1,
|
|
18
18
|
"description": "One-to-three-sentence description. REQUIRED."
|
|
19
|
-
},
|
|
20
|
-
"tags": {
|
|
21
|
-
"type": "array",
|
|
22
|
-
"items": { "type": "string", "minLength": 1 },
|
|
23
|
-
"description": "**Author-supplied** taxonomy tags written in the markdown frontmatter, what the file's author considers the node's intrinsic categories. Skill-map's tag system is **dual-source**: this field carries author tags; `sidecar.annotations.tags` carries user tags (post-hoc, written by whoever curates the project from their `.sm` sidecar). Both surfaces are first-class, searches and listings (`sm list --tag`, UI faceted search) match the union and the UI distinguishes them visually so the attribution stays explicit. Empty array and missing field are equivalent."
|
|
24
19
|
}
|
|
25
20
|
}
|
|
26
21
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://skill-map.
|
|
3
|
+
"$id": "https://skill-map.ai/spec/v0/history-stats.schema.json",
|
|
4
4
|
"title": "HistoryStats",
|
|
5
5
|
"description": "Machine-readable output of `sm history stats --json`. Aggregates over `state_executions` within a time window. camelCase keys throughout. The `elapsedMs` top-level field is the command's own wall-clock (see `cli-contract.md` §Elapsed time), distinct from `totals.durationMsTotal`, which is the sum of every execution record's duration.",
|
|
6
6
|
"type": "object",
|