@skill-map/spec 0.60.0 → 0.62.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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # Spec changelog
2
2
 
3
+ ## 0.62.0
4
+
5
+ ### Minor Changes
6
+
7
+ - New normative import-trust boundary for project-local plugins: a drop-in plugin under `<cwd>/.skill-map/plugins/` is discovered but its extension code is NOT imported or executed by the runtime verbs until the operator grants local trust via `sm plugins enable <id>`. The committed `settings.json` baseline cannot grant it, so cloning and scanning a repo no longer auto-executes its plugins; built-ins and `--plugin-dir` stay ungated. Defined in architecture.md §Locality.
8
+
9
+ ### Patch Changes
10
+
11
+ - Reconciled the exit-codes table in `cli-contract.md`: code `2` no longer claims a missing DB (it covers a present-but-unreadable or corrupt DB), and code `5` now documents an absent project DB file, so a read verb with nothing to open exits `5` (run `sm scan` first). This matches the reference CLI, which ~20 read verbs already honour, and the existing server boot-resilience clause; no behaviour changed.
12
+
13
+ - The `sm tutorial` book now adapts to the active provider lens via two tracks: a rich track (Claude / Codex, with agents, commands, slash and mentions) and a basic track (the open-standard Agent Skills / Antigravity family, skills and markdown wired by markdown references). Scaffolding for the open standard now lays a complete references-based campaign instead of a Claude-shaped book with gaps, and the provider/lens narration was corrected to the current model.
14
+
15
+ ## User-facing
16
+
17
+ `sm tutorial` now runs end to end beyond Claude: a basic skills-and-references book on the open Agent Skills standard (agent-skills / Antigravity) and a rich book for OpenAI Codex, each matching how scans resolve your project.
18
+
19
+ ## 0.61.0
20
+
21
+ ### Minor Changes
22
+
23
+ - Give the Antigravity provider its own `workflow` kind and promote it to `beta` (enabled by default). Under the antigravity lens, `.agent/workflows/<name>.md` (singular `.agent`) classifies as a `workflow` node (handle = filename) while skills keep the open-standard `.agents/skills/` classifier. The slash extractor now runs under antigravity, so `/name` resolves to both skills and workflows, reserved verbs are flagged on both, and `.agent/workflows/` auto-detects the lens.
24
+
25
+ ## User-facing
26
+
27
+ **Antigravity is on by default now.** A project with a `.agent/workflows/` folder auto-detects the Antigravity lens; those files show up as workflows (not plain Markdown), and a `/name` reference links to the matching workflow or skill.
28
+
3
29
  ## 0.60.0
4
30
 
5
31
  ### Minor Changes
package/architecture.md CHANGED
@@ -70,9 +70,9 @@ The UI is **not** a driving adapter; it is an HTTP/WS client of the Server. Exac
70
70
 
71
71
  A skill-map project sees its filesystem through exactly one **active provider lens** at any time: 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.
72
72
 
73
- The lens is project-scope state, living 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 (several markers), the CLI and UI prompt the user to pick one enabled provider. There is no unlensed state: when no vendor marker is present at all, the lens resolves to the open-standard `agent-skills` view, the universal default lens, which is NOT persisted, so a vendor marker added later still auto-detects on the next scan. The non-gated `core/markdown` base still classifies every unclaimed `.md` underneath, but it is not itself a selectable lens (see below). **The marker set is provider-owned**: each Provider declares its detection markers in its manifest `detect.markers` block (see [`provider.schema.json`](./schemas/extensions/provider.schema.json#/properties/detect)), e.g. `claude` → `.claude/`, `codex` → `.codex/`, `agent-skills` → `.agents/` (`AGENTS.md` is deliberately NOT an `codex` marker: it is the open agents.md standard, common in non-Codex repos and alongside `.claude/`, so keying detection off it would mis-route plain-markdown repos and force ambiguous prompts; a genuine Codex project is identified by `.codex/`). No central hardcoded detection table; the detectable set derives from 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, first match the default suggestion. A Provider with no `detect` block is never auto-suggested but can 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 marker, so a Google project's `.agents/` files are owned by the `agent-skills` provider; the `antigravity` lens is set manually via `sm config set activeProvider antigravity`. `antigravity` ships `experimental` (disabled by default, see below), so it does not auto-detect until enabled; `agent-skills` is `stable` (the locked open default lens), so a project's `.agents/` marker auto-detects it and a project with no vendor marker falls back to it.
73
+ The lens is project-scope state, living 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 (several markers), the CLI and UI prompt the user to pick one enabled provider. There is no unlensed state: when no vendor marker is present at all, the lens resolves to the open-standard `agent-skills` view, the universal default lens, which is NOT persisted, so a vendor marker added later still auto-detects on the next scan. The non-gated `core/markdown` base still classifies every unclaimed `.md` underneath, but it is not itself a selectable lens (see below). **The marker set is provider-owned**: each Provider declares its detection markers in its manifest `detect.markers` block (see [`provider.schema.json`](./schemas/extensions/provider.schema.json#/properties/detect)), e.g. `claude` → `.claude/`, `codex` → `.codex/`, `agent-skills` → `.agents/`, `antigravity` → `.agent/workflows/` (`AGENTS.md` is deliberately NOT an `codex` marker: it is the open agents.md standard, common in non-Codex repos and alongside `.claude/`, so keying detection off it would mis-route plain-markdown repos and force ambiguous prompts; a genuine Codex project is identified by `.codex/`). No central hardcoded detection table; the detectable set derives from 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, first match the default suggestion. A Provider with no `detect` block is never auto-suggested but can be selected manually. Google's Antigravity CLI (which replaced the retired Gemini CLI on 2026-05-19) uses the open-standard `.agents/skills/` for skills but its OWN `.agent/workflows/` (singular `.agent`) for workflows; the latter is its `detect` marker. `antigravity` ships `beta` (enabled by default), so its `.agent/workflows/` marker auto-detects the antigravity lens; a project that ALSO carries `.agents/` surfaces an ambiguous prompt (antigravity vs the `agent-skills` open default). `agent-skills` is `stable` (the locked open default lens), so a project's shared `.agents/` marker auto-detects it (a project with no vendor marker falls back to it), and a Google project's `.agents/skills/` files are owned by `agent-skills` for auto-detect, not by antigravity.
74
74
 
75
- **Not-ready Providers ship disabled.** A Provider that is registered but not yet ready for end users declares `stability: 'experimental'` (see [`base.schema.json`](./schemas/extensions/base.schema.json#/properties/stability)), which ships it **disabled by default**: it does not classify, does not register, is never auto-detected, and is absent from the `selectable` set served by `GET /api/active-provider` until the operator opts in (`sm plugins enable <id>`, the Settings toggle, or a config override). There is no separate `comingSoon` flag: enabled/disabled is the single availability axis, and `stability: 'experimental'` is just the installed default flipped off. Today `antigravity` is experimental, so `claude` (stable), `codex` (beta), and `agent-skills` (stable, the locked open default) are selectable by default; enabling the experimental `antigravity` makes it both selectable and classifying. The non-gated `core/markdown` base is locked-enabled but is NOT a selectable lens, it is the substrate beneath whatever lens is active (see §Active-lens scope for providers). `stability: 'beta'` ships ENABLED like `stable` but renders a maturity badge (it is NOT a disabled state); this is distinct from `hideChip`, which only suppresses the per-card badge.
75
+ **Not-ready Providers ship disabled.** A Provider that is registered but not yet ready for end users declares `stability: 'experimental'` (see [`base.schema.json`](./schemas/extensions/base.schema.json#/properties/stability)), which ships it **disabled by default**: it does not classify, does not register, is never auto-detected, and is absent from the `selectable` set served by `GET /api/active-provider` until the operator opts in (`sm plugins enable <id>`, the Settings toggle, or a config override). There is no separate `comingSoon` flag: enabled/disabled is the single availability axis, and `stability: 'experimental'` is just the installed default flipped off. Today all four lenses ship enabled and selectable, `claude` (stable), `antigravity` (beta), `codex` (beta), and `agent-skills` (stable, the locked open default); no built-in Provider currently ships `experimental` (the flag's live built-in examples are extractors / analyzers, e.g. `core/mcp-tools` and `core/annotation-stale`). The non-gated `core/markdown` base is locked-enabled but is NOT a selectable lens, it is the substrate beneath whatever lens is active (see §Active-lens scope for providers). `stability: 'beta'` ships ENABLED like `stable` but renders a maturity badge (it is NOT a disabled state); this is distinct from `hideChip`, which only suppresses the per-card badge.
76
76
 
77
77
  ### Consequence: one graph per project at a time
78
78
 
@@ -90,7 +90,7 @@ A provider plugin MAY declare it reads source files belonging to ANOTHER provide
90
90
 
91
91
  ### Universal extractors and per-provider extractors
92
92
 
93
- The lens does NOT gate the universal extractors under `core/` (markdown links, code-region file paths, external URLs, sidecar annotations); their semantics are provider-agnostic, so they run regardless of the active provider. Provider-specific extractors (Claude's `@`-directive parser, Cursor's picker-derived references, the future Codex AGENTS.md walker, future Antigravity parsers) declare `precondition: { provider: '<id>' }` on their manifest; the orchestrator invokes them on every node visited during the scan as long as the **active lens** is in the declared provider list, regardless of which provider's `classify()` claimed the node. The declared list MAY name more than one lens: the claude `@`-directive and `/command` extractors run under both `claude` and `codex` (`precondition: { provider: ['claude', 'codex'] }`), because OpenAI Codex sub-agents share the same `@<name>` mention and `/command` grammar; codex declares `invokes: ['skill']`, so under the codex lens a `/name` slash signal resolves to the provider's open-standard `.agents/skills/<name>/SKILL.md` skills (Codex reads its skills from the open `.agents/skills/` layout). A body-scoped extractor reads whatever the walker yielded as the node body: for most providers the text after the frontmatter fence, but for a provider declaring `read.bodyField` (see [`provider.schema.json`](./schemas/extensions/provider.schema.json#/properties/read)) the named frontmatter field instead, since Codex sub-agents are pure TOML whose markdown prompt is the `developer_instructions` field, the codex provider sets `bodyField: 'developer_instructions'` so that prompt flows through the same body pipeline (body hash, markdown-link / backtick-path / external-url, and the lens-gated `@` / `/`).
93
+ The lens does NOT gate the universal extractors under `core/` (markdown links, code-region file paths, external URLs, sidecar annotations); their semantics are provider-agnostic, so they run regardless of the active provider. Provider-specific extractors (Claude's `@`-directive parser, Cursor's picker-derived references, the future Codex AGENTS.md walker, future Antigravity parsers) declare `precondition: { provider: '<id>' }` on their manifest; the orchestrator invokes them on every node visited during the scan as long as the **active lens** is in the declared provider list, regardless of which provider's `classify()` claimed the node. The declared list MAY name more than one lens: the claude `@`-directive extractor runs under `claude` and `codex` (`precondition: { provider: ['claude', 'codex'] }`), because OpenAI Codex sub-agents share the same `@<name>` mention grammar; the `/command` (slash) extractor additionally runs under `antigravity` (`precondition: { provider: ['claude', 'codex', 'antigravity'] }`), since Antigravity invokes both skills and workflows by the same `/<name>` slash. codex declares `invokes: ['skill']`, so under the codex lens a `/name` slash signal resolves to the provider's open-standard `.agents/skills/<name>/SKILL.md` skills (Codex reads its skills from the open `.agents/skills/` layout); antigravity declares `invokes: ['skill', 'workflow']`, so under its lens a `/name` resolves to either a `.agents/skills/<name>/SKILL.md` skill or a `.agent/workflows/<name>.md` workflow. A body-scoped extractor reads whatever the walker yielded as the node body: for most providers the text after the frontmatter fence, but for a provider declaring `read.bodyField` (see [`provider.schema.json`](./schemas/extensions/provider.schema.json#/properties/read)) the named frontmatter field instead, since Codex sub-agents are pure TOML whose markdown prompt is the `developer_instructions` field, the codex provider sets `bodyField: 'developer_instructions'` so that prompt flows through the same body pipeline (body hash, markdown-link / backtick-path / external-url, and the lens-gated `@` / `/`).
94
94
 
95
95
  The gate is the active lens, not the node's provider. A `@handle` token in `CLAUDE.md` or `notes/todo.md` (files the `claude` provider disclaims to `core/markdown`) still gets parsed by `claude/at-directive` under the `claude` lens, because the lens represents the runtime grammar and the runtime reads markdown across the whole project, not only files it owns. The earlier double-check ("node's provider matches AND the lens") silently dropped that surface; dropping the node side restores it. Cross-lens isolation holds via the lens half alone: under `codex`, claude extractors are silent on every node (including `.claude/*`) because lens authorisation is missing. Under the open-standard `agent-skills` default lens (a project with no vendor marker), the `claude` / `codex`-gated extractors stay silent because `agent-skills` is not in their declared provider allowlist; only the universal extractors run, alongside the open-standard `skill` classifier.
96
96
 
@@ -389,7 +389,7 @@ A node landing in the reserved set joins a per-scan `Set<nodePath>` consumed by
389
389
 
390
390
  2. **It downgrades any link resolving to a reserved target** (by path OR name match) by subtracting `RESERVED_PENALTY = 0.9` (a `delta` op) from the 1.0 baseline, folding it to `RESERVED_TARGET = 0.1`, emitting the `delta -0.9` in the same score-phase pass as its reserved warns. The reserved-target set is computed by the post-walk lift and surfaced via `ctx.reservedNodePaths`. The visual weight drops well below the broken floor (`0.5`) so the operator sees the edge resolves to a file the runtime ignores. When the trigger has multiple candidates (name index collision) and the strict-kind filter accepts more than one, the resolver picks the first allowed candidate; if non-reserved, the link keeps the 1.0 baseline, and only when EVERY accepted candidate is reserved does the penalty apply. With `core/name-reserved` disabled, a reserved-resolving link gets no `delta -0.9` and no warn, falling back to the 1.0 baseline (symmetric disable).
391
391
 
392
- The lookup normalises both sides through the §Extractor · trigger normalization pipeline, so a literal `Init-Project` in the manifest still matches a user `name: init project` or filename `Init-Project.md`. The catalog is intentionally per-kind, not global: a name reserved for commands (`/help`) MAY legitimately appear as a skill (a "help" skill triggered through a non-command channel). Lens scope respects the same per-kind boundary: Antigravity declares its reserved names under `skill` (not `command`) because the invocable they shadow is a skill file, so only `skill`-kind nodes are tested.
392
+ The lookup normalises both sides through the §Extractor · trigger normalization pipeline, so a literal `Init-Project` in the manifest still matches a user `name: init project` or filename `Init-Project.md`. The catalog is intentionally per-kind, not global: a name reserved for commands (`/help`) MAY legitimately appear as a skill (a "help" skill triggered through a non-command channel). Lens scope respects the same per-kind boundary: Antigravity declares its reserved names under `skill` AND `workflow` (not `command`) because the invocables they shadow are skill files (`.agents/skills/`) and workflow files (`.agent/workflows/`), both invoked by `/<name>`, so skill- and workflow-kind nodes are tested.
393
393
 
394
394
  **Update policy.** Built-in catalogs drift as vendor runtimes evolve. Each catalog change ships as a kernel patch with a changeset entry; the catalog is API surface users rely on the analyzer to reflect. User-installed Providers MAY declare their own `reservedNames` with the same shape; the analyzer and penalty run uniformly across built-in and user-installed Providers.
395
395
 
@@ -558,6 +558,7 @@ Hooks introduce no new persisted state and do NOT participate in the determinist
558
558
  ### Locality
559
559
 
560
560
  - **Drop-in**: extensions live inside plugins, discovered at boot from `<cwd>/.skill-map/plugins/<id>/` only. The `--plugin-dir <path>` escape hatch on the `sm plugins …` verb family loads a custom directory per invocation when the user explicitly opts in.
561
+ - **Import trust (security boundary).** A drop-in plugin discovered under the project-local `<cwd>/.skill-map/plugins/` is parsed (manifest read + surfaced in `sm plugins list`) but its extension CODE is NOT imported or executed until the operator grants LOCAL trust: a `config_plugins` (DB) override enabling the plugin (`<id>`) or any of its extensions (`<id>/<ext>`), as written by `sm plugins enable <id>` or the Settings toggle. The committed `settings.json` baseline does NOT grant import trust: a cloned repo controls its own `.skill-map/settings.json`, so honouring it would let a hostile repo auto-execute its plugins on the victim's first `sm scan`. A fresh clone therefore ships its project-local plugins discovered-but-unexecuted; the runtime emits a one-time notice naming how many were found and pointing at `sm plugins enable`. Built-in extensions (compiled into the CLI) and an explicit `--plugin-dir <path>` (the operator pointed the loader at the code on purpose) are NOT gated; `--no-plugins` skips discovery entirely. The `sm plugins` management family (`list` / `show` / `enable` / `disable` / `doctor`) still imports discovered plugin code to enumerate extensions, running those verbs is itself the operator's explicit choice to work with the project's plugins.
561
562
  - **Built-in**: the reference impl bundles a default extension set (one Provider, four extractors, five analyzers, one formatter, one hook). The fifth analyzer, `core/schema-violation`, replays every scanned node and link through the authoritative spec schemas via AJV, the kernel-side guard against persisting non-conforming graph rows. The first built-in Hook is `core/update-check`, subscribing to `shutdown` to run the once-per-day "update available" probe + banner that lived on the CLI entry path before the Hook kind had concrete consumers. Loaded from `src/extensions/`, these are indistinguishable from plugin-supplied extensions to the kernel.
562
563
 
563
564
  ---
package/cli-contract.md CHANGED
@@ -50,6 +50,12 @@ privacy gate (`sm config set --yes` or the Settings UI confirm dialog).
50
50
  Plugins load from `<cwd>/.skill-map/plugins/` by default; an arbitrary
51
51
  external location MAY be loaded via the `--plugin-dir <path>` escape
52
52
  hatch on the `sm plugins …` verb family, user-explicit per invocation.
53
+ Project-local plugins are discovered but their code is NOT executed by
54
+ `sm scan` / `sm serve` (and the other runtime verbs) until the operator
55
+ grants local trust via `sm plugins enable <id>`; the committed
56
+ `settings.json` does not grant it. `--plugin-dir` and built-ins are not
57
+ gated. See [`architecture.md` §Locality](./architecture.md) (import
58
+ trust) for the normative model.
53
59
 
54
60
  ### User-settings file (narrow, documented exception)
55
61
 
@@ -141,10 +147,10 @@ All verbs use this shared table. Additional codes MAY be defined per-verb (docum
141
147
  |---|---|---|
142
148
  | `0` | OK | Command completed, no issues at or above the configured severity threshold. |
143
149
  | `1` | Issues found | Command completed, but deterministic issues at `error` severity exist. Applies to `sm scan`, `sm check`, `sm doctor`. |
144
- | `2` | Operational error | Bad flags, missing DB, unreadable file, corrupt config, runtime / environment mismatch (e.g. wrong Node version, missing native dependency), unhandled exception. Accompanied by an error message on stderr. |
150
+ | `2` | Operational error | Bad flags, a present-but-unreadable / corrupt DB, unreadable file, corrupt config, runtime / environment mismatch (e.g. wrong Node version, missing native dependency), unhandled exception. Accompanied by an error message on stderr. (An *absent* project DB file is `5`, see below.) |
145
151
  | `3` | Duplicate conflict | Job submission refused because an active duplicate exists (same `action + version + node + contentHash`). Returned by `sm job submit`. |
146
152
  | `4` | Nonce mismatch | `sm record` called with an `id`/`nonce` pair that does not match. |
147
- | `5` | Not found | A named resource does not exist (node id, job id, plugin id, config key). |
153
+ | `5` | Not found | A named resource does not exist (node id, job id, plugin id, config key), or the project DB file is absent so a read verb (`sm check`, `list`, `show`, `graph`, `export`, `history`, `orphans`, `db dump` / `reset` / `backup` / `shell`, `job prune`) has nothing to open, run `sm scan` first. An explicit `--db <path>` that does not exist is the same case (see §Server boot resilience). |
148
154
 
149
155
  Codes 6–15 are reserved. Codes ≥ 16 are free for verb-specific use.
150
156
 
@@ -191,7 +197,7 @@ The destination is the selected Provider's `scaffold.skillDir` (e.g. `.claude/sk
191
197
  - Without `--for`, the default is the first scaffold-capable Provider in catalog order (Claude). The verb requires an empty cwd (see below), so there is no marker to detect: provider auto-detection does not apply.
192
198
  - Without `--for`, on interactive stdin the verb prompts with a numbered list of Providers declaring `scaffold.skillDir`, marking the default (Claude); an empty answer accepts it. Each option shows the Provider label plus any `scaffold.aka` agents in parentheses (e.g. the open standard lists Antigravity and OpenAI Codex). The `aka` strings are display-only, NOT accepted by `--for`.
193
199
  - Without `--for`, on non-interactive stdin (pipes, CI) the verb selects the default without prompting, staying scriptable.
194
- - `--experimental` includes Providers flagged `stability: 'experimental'` (today `agent-skills`) as scaffold destinations and enables them in the seeded fixture so the demo scan classifies their nodes. Without it, experimental Providers are omitted from the prompt and `--for <experimental-id>` is a usage error (they ship disabled by default). Default behaviour offers only stable Providers (Claude).
200
+ - `--experimental` includes Providers flagged `stability: 'experimental'` as scaffold destinations and enables them in the seeded fixture so the demo scan classifies their nodes. Without it, experimental Providers are omitted from the prompt and `--for <experimental-id>` is a usage error (they ship disabled by default). Default behaviour offers the stable, ready destinations (today Claude, the rich-track anchor, and the open-standard `agent-skills`, the basic-track anchor).
195
201
 
196
202
  Behaviour:
197
203
 
package/index.json CHANGED
@@ -174,14 +174,14 @@
174
174
  }
175
175
  ]
176
176
  },
177
- "specPackageVersion": "0.60.0",
177
+ "specPackageVersion": "0.62.0",
178
178
  "integrity": {
179
179
  "algorithm": "sha256",
180
180
  "files": {
181
- "CHANGELOG.md": "280befaa7de6239b81a8fe11068835b4688e2fc76892e5826ed7f929514dc085",
181
+ "CHANGELOG.md": "db921746ca85beb0aaa13f6ae79892a980d256238015ebc4ac711dbd2fb13714",
182
182
  "README.md": "a790cd010b46d47883d1f37e3893cea9d7aa69ec4750c0202e6a0c99991e7980",
183
- "architecture.md": "88f1af51a2d822535c813241c87a80b3889ecd60bac4dcc84318e00e1946ab5f",
184
- "cli-contract.md": "3494cd18c15e4d85d694b4a7cbb4e364dad1385bd809ec3656e2f48f8238c41b",
183
+ "architecture.md": "434954b096c0f34752002996356d2d8e7cf578b345f62525fe80a50a72ccb6ba",
184
+ "cli-contract.md": "691813e1eb847316304d5f90cebd6e6b9210f83dd4ee801fce0b69946ef130a6",
185
185
  "conformance/README.md": "dcbef7249f161acf597552a05dcadc813cd0ced430dcd3f813fcf5e1c876335d",
186
186
  "conformance/cases/backtick-path-extraction.json": "4620e7f8bc161fc57cb44001e9d99879c7e22b4865a0c27a20dc28969cd936d9",
187
187
  "conformance/cases/extractor-collision-detection.json": "179a02c61892f0d26492de0c4e2c327fa6b4986d1265a8f119e871df6afe4658",
@@ -234,7 +234,7 @@
234
234
  "interfaces/security-scanner.md": "0996dd782e2d39d4791f2e290da4bb1a68a5b30c1f79187977188ec8e3fe6ef2",
235
235
  "job-events.md": "2c7017f5f0003b19653424111a07043487173cbe88b51e961598bb1693987059",
236
236
  "job-lifecycle.md": "ce33bc8bb5090ea183f860e495bfccc2a4a0ac2e23f6ebad83b9c28aad59124e",
237
- "plugin-author-guide.md": "c628ef0867dd8321f261d9e806954b17cda14f8080a92af5623dfa9377fd191e",
237
+ "plugin-author-guide.md": "9244ee6aef49100867d46b324e13b3c3413a071813e34889563d4bfcef78c7f0",
238
238
  "plugin-kv-api.md": "5e095581020043af73ff028e272f56d42ca9eb6e506dd777d45703f9db796a5b",
239
239
  "plugin-quickstart.md": "19092b278d80df357ea623dc3bd9f833d059582ee1356f317621913d91e50512",
240
240
  "prompt-preamble.md": "5d0f836688aa23eafc32104c3174132340b268361f6060326eec84da17c6ad6d",
@@ -251,7 +251,7 @@
251
251
  "schemas/extensions/formatter.schema.json": "880dc379ad545a62404403533a01eda5171edba0390561fc46ec6e986e0b9bd3",
252
252
  "schemas/extensions/hook.schema.json": "f56aef59e9986ffdf7d86aa2e048dccccf217000a358b8c64737cbd911c48dad",
253
253
  "schemas/extensions/provider-kind.schema.json": "499b2418bbe6d8a84a1608e26c56b52c2652a30ce314bc2989094418797dc1e6",
254
- "schemas/extensions/provider.schema.json": "8d2022ee0721233abcf35aa019168c41f69214035b718c1da1f9b15839370a4a",
254
+ "schemas/extensions/provider.schema.json": "33f189cb6d6e987d7af1d5a8968834f92ba674f5621953aaa1f84d3a079a53e3",
255
255
  "schemas/frontmatter/base.schema.json": "47f05ffa2a51f465f1b8df70cc7a1e7afe2c40f8d37826cd8a569977e9036b8d",
256
256
  "schemas/history-stats.schema.json": "436aa0ffe744bdb699000447e86b45724fbd2cc4642781074eb1527522b9058c",
257
257
  "schemas/input-types.schema.json": "93b27a1cbd1f131d42730eb9a89cf3af6889e9f17b20a48ce36133885503e01b",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skill-map/spec",
3
- "version": "0.60.0",
3
+ "version": "0.62.0",
4
4
  "description": "JSON Schemas, prose contracts, and conformance suite for the skill-map specification.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -60,6 +60,8 @@ The kernel scans one root: `<cwd>/.skill-map/plugins/`, committed-with-the-repo
60
60
 
61
61
  A plugin is any direct child directory of that root containing a `plugin.json`. Nested directories are not searched recursively. Pass `--plugin-dir <path>` to replace the default root with a custom directory (mostly for testing, or a plugin set the operator opts into).
62
62
 
63
+ **Import trust.** A project-local plugin is discovered (manifest parsed, listed by `sm plugins list`) but its code is NOT imported by the runtime verbs (`sm scan`, `sm serve`, ...) until the operator trusts it locally with `sm plugins enable <id>` (or the Settings toggle), which writes a `config_plugins` override. This is a security boundary: cloning a repo and scanning it must not auto-execute the repo's plugins, so the committed `settings.json` baseline cannot grant import trust, only the local DB override can. Authors developing a plugin enable it once locally; `--plugin-dir` is not gated. See [`architecture.md` §Locality](./architecture.md).
64
+
63
65
  After every change to `plugins/`, run `sm plugins list` to see each plugin's load status. The seven statuses are documented under [Diagnostics](#diagnostics).
64
66
 
65
67
  ### Plugin id uniqueness
@@ -97,18 +97,24 @@
97
97
  "type": "object",
98
98
  "required": ["skillDir"],
99
99
  "additionalProperties": false,
100
- "description": "Authoring targets for verbs that MATERIALISE files into this Provider's on-disk territory (today only `sm tutorial`, which drops a skill folder where the Provider's runtime will discover it). Distinct from `detect` (which READS markers to suggest a lens) and from `classify` (which READS paths during a scan): `scaffold` is the WRITE side, the directory a generator drops new content into so the target runtime picks it up. Optional: a Provider with no `scaffold` block is never offered as a destination by a materialising verb (e.g. `codex` until Codex skills land, `antigravity` whose skills live under the open-standard `agent-skills` territory, `core/markdown` which owns no authoring convention). The skill-folder convention is uniform across hosts (`<skillDir>/<name>/SKILL.md`), so a single `skillDir` is enough today; a future verb that scaffolds agents or commands adds a sibling field (`agentDir`, `commandDir`) without breaking this one.",
100
+ "description": "Authoring targets for verbs that MATERIALISE files into this Provider's on-disk territory (today only `sm tutorial`, which drops a skill folder where the Provider's runtime will discover it). Distinct from `detect` (which READS markers to suggest a lens) and from `classify` (which READS paths during a scan): `scaffold` is the WRITE side, the directory a generator drops new content into so the target runtime picks it up. Optional: a Provider with no `scaffold` block is never offered as a destination by a materialising verb (e.g. `antigravity`, whose skills and basic-track book are already covered by the open-standard `agent-skills` row, and `core/markdown`, which owns no authoring convention). The skill-folder convention is uniform across hosts (`<skillDir>/<name>/SKILL.md`), so a single `skillDir` is enough today; a future verb that scaffolds agents or commands adds a sibling field (`agentDir`, `commandDir`) without breaking this one.",
101
101
  "properties": {
102
102
  "skillDir": {
103
103
  "type": "string",
104
104
  "minLength": 1,
105
105
  "pattern": "^\\.?[A-Za-z0-9][A-Za-z0-9._/-]*$",
106
- "description": "Directory (relative to the scope root) under which a materialising verb writes a skill folder, e.g. `.claude/skills` for Claude, `.agents/skills` for the open standard. The verb appends `/<skillName>/SKILL.md`. Relative, no leading slash and no `..` traversal (the pattern forbids both); the consuming verb joins it onto the cwd."
106
+ "description": "Directory (relative to the scope root) under which a materialising verb writes a skill folder, e.g. `.claude/skills` for Claude, `.agents/skills` for the open standard (also Codex, whose skills adopt that layout). The verb appends `/<skillName>/SKILL.md`. Relative, no leading slash and no `..` traversal (the pattern forbids both); the consuming verb joins it onto the cwd."
107
+ },
108
+ "marker": {
109
+ "type": "string",
110
+ "minLength": 1,
111
+ "pattern": "^\\.?[A-Za-z0-9][A-Za-z0-9._/-]*$",
112
+ "description": "Optional directory the materialising verb creates so the active-lens resolver picks THIS Provider when its `skillDir` is shared with another lens. The open `.agents/skills` territory is read by several lenses (`agent-skills`, `antigravity`, `codex`), so a Provider whose skillDir is that shared territory but whose lens needs a distinct marker (e.g. Codex's `.codex`) declares it here, and `sm tutorial --for <id>` drops the marker alongside the skill so the project resolves the intended lens. Omitted when the skillDir's own parent IS the marker (`.claude/skills` → the `.claude` marker)."
107
113
  },
108
114
  "aka": {
109
115
  "type": "array",
110
116
  "minItems": 1,
111
- "description": "Display-only hints naming the agents that consume this Provider's scaffold territory, shown in parentheses next to the Provider label in the `sm tutorial` destination prompt (e.g. the open-standard `.agents/skills` is read by Google's Antigravity and OpenAI's Codex, so its `agent-skills` Provider lists them here). Purely presentational: these strings are NOT matched by `--for` (only registered Provider ids are) and have no runtime effect. Optional; absent means the prompt shows the bare Provider label.",
117
+ "description": "Display-only hints naming the agents that consume this Provider's scaffold territory AND share its tutorial track, shown in parentheses next to the Provider label in the `sm tutorial` destination prompt (e.g. the open-standard `.agents/skills` `agent-skills` Provider lists Google's Antigravity, which shares both the territory and the basic track; OpenAI's Codex also reads that territory but is a rich-track lens, so it is NOT listed here, advertising it under the basic row would hand it the wrong book). Purely presentational: these strings are NOT matched by `--for` (only registered Provider ids are) and have no runtime effect. Optional; absent means the prompt shows the bare Provider label.",
112
118
  "items": { "type": "string", "minLength": 1 }
113
119
  }
114
120
  }