@skill-map/spec 0.33.0 → 0.34.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 +38 -0
- package/README.md +1 -1
- package/architecture.md +26 -10
- package/cli-contract.md +1 -1
- package/conformance/cases/plugin-missing-ui-rejected.json +1 -1
- package/conformance/coverage.md +1 -1
- package/conformance/fixtures/orphan-markdown/ARCHITECTURE.md +1 -1
- package/db-schema.md +1 -1
- package/index.json +13 -13
- package/package.json +1 -1
- package/plugin-author-guide.md +4 -4
- package/schemas/api/rest-envelope.schema.json +2 -2
- package/schemas/extensions/provider.schema.json +1 -1
- package/schemas/project-config.schema.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Spec changelog
|
|
2
2
|
|
|
3
|
+
## 0.34.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2593664: Retire the `gemini` Provider and onboard the `antigravity` Provider. Google released the Antigravity CLI on 2026-05-19 as the replacement for the Gemini CLI (which sunsets 2026-06-18 for consumer tiers). Antigravity preserved the four pillars of Gemini CLI (Agent Skills, Hooks, Subagents, Extensions/plugins) but adopted the open-standard `.agents/` layout instead of carrying forward a vendor-specific `.gemini/` directory, so the old Provider classified obsolete paths.
|
|
8
|
+
|
|
9
|
+
Three coordinated changes ship together:
|
|
10
|
+
|
|
11
|
+
1. **`gemini` bundle deleted in full.** The provider, schemas, conformance fixtures, and tests under `src/plugins/gemini/` are gone. Any project relying on `.gemini/` classification routes Antigravity skills through the existing `agent-skills` Provider (open standard, dirname-based identifier) and AGENTS.md through the universal `core/markdown` fallback.
|
|
12
|
+
|
|
13
|
+
2. **New `antigravity` bundle (metadata-only).** `src/plugins/antigravity/providers/antigravity/` ships an empty-kinds Provider whose `classify()` always returns `null`. It contributes lens identity and a seed `reservedNames` catalog (Antigravity TUI built-in slash commands: `/agents`, `/help`, `/quit`, `/exit`, `/skills`, `/hooks`). When Google formalises subagent / hook on-disk paths the Provider will gain `kinds` and `classify()` accordingly.
|
|
14
|
+
|
|
15
|
+
3. **Active-lens auto-detect drops the `.gemini/` marker.** No replacement marker (Antigravity has no vendor-specific workspace directory). The lens is set manually via `sm config set activeProvider antigravity`.
|
|
16
|
+
|
|
17
|
+
Spec edits: `spec/architecture.md`, `spec/cli-contract.md`, `spec/plugin-author-guide.md`, `spec/db-schema.md`, `spec/README.md`, schemas in `spec/schemas/` updated to remove `gemini` references and add Antigravity context. `spec/index.json` regenerated.
|
|
18
|
+
|
|
19
|
+
## User-facing
|
|
20
|
+
|
|
21
|
+
**Gemini CLI support retired.** Antigravity CLI projects (Google's May 2026 replacement) scan via the open-standard `.agents/skills/` paths under the existing `agent-skills` lens. Run `sm config set activeProvider antigravity` to flag a project as Antigravity-flavoured.
|
|
22
|
+
|
|
23
|
+
- ee919da: Reserved-name catalog per Provider. Each Provider runtime owns a set of invocation names its built-ins consume (Claude reserves `/help`, `/clear`, `/init`, `/agents`, `/model`, … under `command`, and `general-purpose`, `output-style-setup`, `statusline-setup` under `agent`). User files declaring one of these names are silently shadowed at runtime, the kernel now surfaces the collision.
|
|
24
|
+
|
|
25
|
+
Two changes ship together:
|
|
26
|
+
|
|
27
|
+
1. **New `IProvider.reservedNames?: Record<kind, string[]>`**. Each Provider declares the names its runtime reserves per kind. Claude ships the documented built-in catalog (command + agent today); Gemini, OpenAI, and agent-skills declare none yet (no `reservedNames` field). User plugins MAY declare their own with the same shape.
|
|
28
|
+
|
|
29
|
+
2. **Two consumers share the catalog through a single per-scan `Set<nodePath>`**:
|
|
30
|
+
- **New `core/reserved-name` analyzer** emits one `warn` issue per user node whose normalised identifiers intersect its Provider's `reservedNames[kind]`. The issue carries `data: { provider, kind }` and a message pointing at the file with a rename hint.
|
|
31
|
+
- **The post-walk confidence-lift transform downgrades** any link that resolves to a reserved target (path or name match) to `RESERVED_TARGET_CONFIDENCE = 0.1` instead of bumping to `1.0`. When the same trigger has both a reserved and a non-reserved candidate accepted by the strict-kind filter, the non-reserved one wins and the bump goes to `1.0` normally.
|
|
32
|
+
|
|
33
|
+
The detection runs once per scan in the orchestrator (`buildReservedNodePaths`) so the analyzer and the transform share identical truth, the two surfaces cannot drift.
|
|
34
|
+
|
|
35
|
+
New spec section: `§Provider · reservedNames` in `spec/architecture.md`.
|
|
36
|
+
|
|
37
|
+
## User-facing
|
|
38
|
+
|
|
39
|
+
**Files whose name shadows a built-in are flagged.** A file like `.claude/commands/help.md` now emits a `warn` (Claude's runtime ignores it for its own `/help`), and incoming `/help` edges resolve to it at confidence `0.1` instead of `1.0`.
|
|
40
|
+
|
|
3
41
|
## 0.33.0
|
|
4
42
|
|
|
5
43
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# skill-map spec
|
|
2
2
|
|
|
3
|
-
The **skill-map specification** defines a vendor-neutral standard for mapping, inspecting, and managing collections of interrelated Markdown files, skills, agents, commands, hooks, and notes that compose AI-agent ecosystems (Claude Code, Codex,
|
|
3
|
+
The **skill-map specification** defines a vendor-neutral standard for mapping, inspecting, and managing collections of interrelated Markdown files, skills, agents, commands, hooks, and notes that compose AI-agent ecosystems (Claude Code, Codex, Antigravity, docs sites, and any future platform).
|
|
4
4
|
|
|
5
5
|
This document is the **source of truth**. The reference implementation under `../src/` conforms to this spec. Third parties can build alternative implementations (any language, any UI, any CLI) using only `spec/`, without reading the reference source.
|
|
6
6
|
|
package/architecture.md
CHANGED
|
@@ -43,11 +43,11 @@ 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`, `.
|
|
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`.
|
|
47
47
|
|
|
48
48
|
### Consequence: one graph per project at a time
|
|
49
49
|
|
|
50
|
-
The persisted scan graph (`scan_*` zone) reflects the project as the active lens sees it. No cross-provider merging happens at storage time. A repo with both `.claude/` and `.
|
|
50
|
+
The persisted scan graph (`scan_*` zone) reflects the project as the active lens sees it. No cross-provider merging happens at storage time. A repo with both `.claude/` and `.codex/` does NOT show "everyone's nodes at once"; it shows the active lens's view.
|
|
51
51
|
|
|
52
52
|
### Consequence: lens change is destructive of the scan zone
|
|
53
53
|
|
|
@@ -61,9 +61,9 @@ A provider plugin MAY declare it reads source files belonging to ANOTHER provide
|
|
|
61
61
|
|
|
62
62
|
### Universal extractors and per-provider extractors
|
|
63
63
|
|
|
64
|
-
The lens does NOT gate the universal extractors that ship under `core/` (markdown links, external URLs, sidecar annotations). Those run regardless of the active provider because their semantics are provider-agnostic. Provider-specific extractors (Claude's `@`-directive parser,
|
|
64
|
+
The lens does NOT gate the universal extractors that ship under `core/` (markdown links, external URLs, sidecar annotations). Those run regardless of the active provider because their semantics are provider-agnostic. Provider-specific extractors (Claude's `@`-directive parser, Cursor's picker-derived references, the future Codex AGENTS.md walker, future Antigravity-specific 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.
|
|
65
65
|
|
|
66
|
-
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 runtime grammar is what the lens represents and the runtime reads markdown across the whole project, not only the 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 is preserved by the lens half alone: under `
|
|
66
|
+
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 runtime grammar is what the lens represents and the runtime reads markdown across the whole project, not only the 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 is preserved by the lens half alone: under `openai`, claude extractors are silent on every node (including `.claude/*`), because the lens authorisation is missing. When `activeProvider` is `null` (no setting, no filesystem marker), provider-gated extractors are skipped uniformly.
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
@@ -102,7 +102,7 @@ The loader enforces two id-uniqueness analyzers during discovery (see [`plugin-a
|
|
|
102
102
|
|
|
103
103
|
In addition, the loader **qualifies every extension** with its owning plugin id before registering it. The registry stores extensions under the qualified id `<plugin-id>/<extension-id>` (e.g. `core/slash`, `core/broken-ref`, `my-plugin/my-extractor`). Authors continue to declare the short `id` in each extension manifest; the loader composes the qualified form from `manifest.id` at load time. Built-in extensions bundled with the reference impl declare their `pluginId` directly in `built-ins.ts`, `core/` for kernel-internal primitives (every analyzer, the formatter, the cross-vendor extractors `annotations` / `slash` / `at-directive` / `markdown-link` / `external-url-counter` / `stability`) and vendor-specific bundles such as `claude/` (the Claude provider) for Provider integrations whose territory is platform-bound. If a plugin author injects a `pluginId` field on an extension that disagrees with `plugin.json`'s `id`, the loader emits `invalid-manifest` with a directed reason.
|
|
104
104
|
|
|
105
|
-
Each plugin (and each built-in bundle) declares a **granularity** that controls how its extensions are toggled. `granularity: 'bundle'` (the default) means the plugin id is the only enable/disable key; `granularity: 'extension'` means each extension is independently toggle-able under its qualified id. The loader's pre-import `resolveEnabled(pluginId)` short-circuit is always coarse (bundle level), when a granularity=`extension` bundle is partially enabled, the import work proceeds and the runtime composer (the CLI's `composeScanExtensions` / `composeFormatters` in `src/cli/util/plugin-runtime.ts`) drops the disabled extensions before they reach the orchestrator. Vendor Provider bundles (`claude`, `
|
|
105
|
+
Each plugin (and each built-in bundle) declares a **granularity** that controls how its extensions are toggled. `granularity: 'bundle'` (the default) means the plugin id is the only enable/disable key; `granularity: 'extension'` means each extension is independently toggle-able under its qualified id. The loader's pre-import `resolveEnabled(pluginId)` short-circuit is always coarse (bundle level), when a granularity=`extension` bundle is partially enabled, the import work proceeds and the runtime composer (the CLI's `composeScanExtensions` / `composeFormatters` in `src/cli/util/plugin-runtime.ts`) drops the disabled extensions before they reach the orchestrator. Vendor Provider bundles (`claude`, `antigravity`, `openai`, `agent-skills`) ship as granularity=`bundle` (the platform integration is on or off as a whole); the `core` bundle is granularity=`extension` (every kernel built-in is removable, satisfying §Boot invariant: "no extension is privileged"). See [`plugin-author-guide.md` §Granularity, bundle vs extension](./plugin-author-guide.md#granularity--bundle-vs-extension) for the author-facing summary.
|
|
106
106
|
|
|
107
107
|
### `RunnerPort`
|
|
108
108
|
|
|
@@ -201,7 +201,7 @@ Six kinds, all first-class, all loaded through the same registry. Each kind has
|
|
|
201
201
|
|
|
202
202
|
| Kind | Role | Input | Output |
|
|
203
203
|
|---|---|---|---|
|
|
204
|
-
| **Provider** | Recognizes a platform. The kind catalog lives on disk under `<plugin>/kinds/<kindName>/{schema.json, kind.json}` (structure-as-truth); the loader projects it onto the runtime descriptor. The Provider's walker hardcodes the paths it scans within the project (e.g. `.claude/`, `.
|
|
204
|
+
| **Provider** | Recognizes a platform. The kind catalog lives on disk under `<plugin>/kinds/<kindName>/{schema.json, kind.json}` (structure-as-truth); the loader projects it onto the runtime descriptor. The Provider's walker hardcodes the paths it scans within the project (e.g. `.claude/`, `.codex/`); it does NOT extend the scan into the user's HOME. `Provider.roots` is enforcement-grade: a Provider with declared roots only sees matching files; a Provider without `roots` acts as the fallback. Deterministic-only. | Filesystem walk results, candidate path. | `{ kind, provider } \| null`. |
|
|
205
205
|
| **Extractor** | Extracts signals from a node body. Deterministic-only: runs synchronously inside `sm scan`. Output flows through context callbacks (no return value): `ctx.emitLink(link)` for the kernel's `links` table (validated against the global closed enum of link kinds; per-extractor allowlist was retired with the structure-as-truth refactor), `ctx.enrichNode(partial)` for the kernel's enrichment layer (separate from the author's frontmatter), `ctx.emitContribution(id, payload)` for view contributions, `ctx.store` for the plugin's own KV / dedicated tables. | Parsed node (frontmatter + body) + callbacks. | `void` (output via callbacks). |
|
|
206
206
|
| **Analyzer** | Evaluates the graph. Dual-mode: `deterministic` runs in `sm check`, `probabilistic` runs in jobs. The analyzer↔action relationship is declared from the Action side via `precondition.analyzerIds` (Modelo B). | Full graph (nodes + links). | `Issue[]`. |
|
|
207
207
|
| **Action** | Operates on one or more nodes. Dual-mode: `deterministic` (in-process code) or `probabilistic` (rendered prompt the runner executes). Files-by-convention: every Action carries `<action-dir>/report.schema.json`; probabilistic Actions additionally carry `<action-dir>/prompt.md`. The retired `reportSchemaRef` / `promptTemplateRef` / `expectedTools` / `fanOutPolicy` manifest fields were replaced by these conventions and the simplified `precondition` block. | Node(s), optional args. | Deterministic: report JSON. Probabilistic: rendered prompt that a runner executes. |
|
|
@@ -247,7 +247,7 @@ The kernel ships every Provider's `ui` block to the BFF at boot; the BFF aggrega
|
|
|
247
247
|
|
|
248
248
|
### Provider · dispatch order and the universal markdown fallback
|
|
249
249
|
|
|
250
|
-
`sm scan` iterates Providers in **registration order**, vendor-specific Providers first (built-in: `claude` → `
|
|
250
|
+
`sm scan` iterates Providers in **registration order**, vendor-specific Providers first (built-in: `claude` → `antigravity` → `openai` → `agent-skills`; user-installed plugins follow in load order), then the built-in `core/markdown` Provider LAST. Each Provider's walker enumerates the full project tree for its declared `read.extensions`; for every emitted file, the orchestrator calls `provider.classify(path, frontmatter)`. The kernel maintains a per-scan `Set<path>` of already-classified files so each path is offered to AT MOST one Provider's `classify`: the first Provider whose `classify` returns non-null claims the file, and subsequent Providers see the path as taken and skip.
|
|
251
251
|
|
|
252
252
|
The dispatch contract has two consequences implementations MUST honour:
|
|
253
253
|
|
|
@@ -265,8 +265,8 @@ The closed set of sources:
|
|
|
265
265
|
| `TIdentifierSource` | Reads | Typical kinds |
|
|
266
266
|
|---|---|---|
|
|
267
267
|
| `'frontmatter.name'` | `node.frontmatter.name` | every invocable kind whose schema declares `name` as required (agents, commands, skills); the canonical source when the author set it. |
|
|
268
|
-
| `'filename-basename'` | `basename(path)` with the extension stripped | Anthropic
|
|
269
|
-
| `'dirname'` | `basename(dirname(path))` | Anthropic /
|
|
268
|
+
| `'filename-basename'` | `basename(path)` with the extension stripped | Anthropic agents and commands, OpenAI Codex sub-agents, references at `<dir>/<name>.<ext>` resolve `@<name>` even when frontmatter is partial. |
|
|
269
|
+
| `'dirname'` | `basename(dirname(path))` | Anthropic / agent-skills (open standard, also adopted by Google Antigravity CLI), Anthropic explicitly documents that the directory between `skills/` and `/SKILL.md` is the invocation handle, with `frontmatter.name` as an optional override (https://code.claude.com/docs/en/skills.md). |
|
|
270
270
|
|
|
271
271
|
Sources MAY appear together; the resolver visits each declared source per node, normalises every yielded value with the §Extractor · trigger normalization pipeline, and contributes a presence entry to the cross-kind name index. Multiple sources that produce the same normalised name collapse into one bucket entry (the dual-source `['frontmatter.name', 'filename-basename']` on a `.claude/agents/foo.md` with `name: foo` yields a single `foo` entry, not two).
|
|
272
272
|
|
|
@@ -284,10 +284,26 @@ The transform runs after `dedupeLinks` and before the analyzer pipeline. For eac
|
|
|
284
284
|
|
|
285
285
|
The matrix is **per-link-kind, per-Provider**, strict: a `claude` Provider that declares `resolution: { mentions: ['agent'], invokes: ['command', 'skill'] }` does NOT bump a `/foo` slash matching an agent named `foo` (slash → agent is a kind mismatch surfaced by `link-conflict` / `kind-mismatch` analyzers, not silently treated as a resolution). The strictness is the load-bearing difference from the kind-agnostic `core/broken-ref` analyzer: `broken-ref`'s scope is "the name exists somewhere" (a name-only resolution is enough to clear the broken flag), the post-walk bump is "the name exists AS A VALID resolution for this link.kind". The `not-broken` + `not-bumped` combination is a documented edge case: the trigger resolves to a real node but the link's kind cannot legitimately point there.
|
|
286
286
|
|
|
287
|
-
The lookup uses the SOURCE node's Provider id deliberately: a Provider rules over the link.kinds its Extractors emit, regardless of where the resolution candidates physically live in the graph. A `claude` agent that mentions
|
|
287
|
+
The lookup uses the SOURCE node's Provider id deliberately: a Provider rules over the link.kinds its Extractors emit, regardless of where the resolution candidates physically live in the graph. A `claude` agent that mentions an `openai` agent (cross-provider mention) still follows claude's `resolution.mentions = ['agent']` rule. When the source node belongs to a Provider without `resolution` (e.g. a `CLAUDE.md` classified by `core/markdown`), the name path short-circuits, the path-match rule still applies.
|
|
288
288
|
|
|
289
289
|
**Distinct from the Signal IR `resolverRules` (§Resolver phase).** `resolverRules` rank candidates INSIDE a Signal (Phase 3+, no Provider declares it today); `resolution` runs against the merged Link graph post-walk and is the contract Extractors EMITTING Links rely on. The two surfaces share no mechanism and intentionally do not compose; when a Signal IR materialises into a Link, the `resolution` matrix runs unchanged against the resulting Link.
|
|
290
290
|
|
|
291
|
+
### Provider · reservedNames
|
|
292
|
+
|
|
293
|
+
Each Provider MAY declare an optional `reservedNames: Record<kind, string[]>` map listing, for each `node.kind` the runtime owns, the set of invocation names the runtime itself consumes. Anthropic's Claude CLI reserves `/help`, `/clear`, `/init`, `/agents`, `/model`, `/cost`, `/compact`, `/login`, `/logout`, … under `command`, and `general-purpose`, `output-style-setup`, `statusline-setup` under `agent`; a user-authored `.claude/commands/help.md` is silently shadowed at runtime (the built-in runs, the file is ignored).
|
|
294
|
+
|
|
295
|
+
The kernel intersects each Provider's `reservedNames[kind]` catalog with the scanned graph at orchestrator time: for every node, the post-walk pipeline derives its normalised identifiers via the §Provider · kind identifiers contract and asks "does any identifier fall in `reservedNames[node.kind]` for this node's Provider?". Matches land in a per-scan `Set<nodePath>` consumed by two surfaces:
|
|
296
|
+
|
|
297
|
+
1. **The `core/reserved-name` analyzer projects one `warn` issue per reserved-shadow node** (`severity: 'warn'`, message points at the offending file and suggests renaming). The analyzer is a pure projector, detection lives in the orchestrator so the same set drives the next surface.
|
|
298
|
+
|
|
299
|
+
2. **The post-walk confidence-lift transform downgrades any link that resolves to a reserved target** (by path OR by name match) to `RESERVED_TARGET_CONFIDENCE = 0.1` instead of bumping it to `1.0`. The visual weight in the graph drops well below the `0.5` / `0.8` extractor emit floors so the operator sees at a glance that 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 it is non-reserved, the link bumps to `1.0` normally; only when EVERY accepted candidate is reserved does the downgrade apply.
|
|
300
|
+
|
|
301
|
+
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).
|
|
302
|
+
|
|
303
|
+
**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 considered API surface that users rely on the analyzer to reflect. User-installed Providers MAY declare their own `reservedNames` with the same shape; the analyzer and the downgrade run uniformly across built-in and user-installed Providers.
|
|
304
|
+
|
|
305
|
+
Default `undefined` ≡ empty map ≡ no reserved names. Path matches against non-reserved targets are unaffected (they continue to bump to `1.0` unconditionally), the downgrade only fires when the resolved target is in the reserved set.
|
|
306
|
+
|
|
291
307
|
### Extractor · output callbacks
|
|
292
308
|
|
|
293
309
|
The `Extractor` runtime contract is `extract(ctx) → void`. The extractor emits its work through three callbacks the kernel binds onto `ctx`:
|
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`, `.
|
|
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`.
|
|
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
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
{ "type": "stderr-matches", "pattern": "plugin bad-provider:.*invalid.*must have required property 'ui'" },
|
|
13
13
|
{ "type": "json-path", "path": "$.providers.length", "equals": 5 },
|
|
14
14
|
{ "type": "json-path", "path": "$.providers[0]", "equals": "claude" },
|
|
15
|
-
{ "type": "json-path", "path": "$.providers[1]", "equals": "
|
|
15
|
+
{ "type": "json-path", "path": "$.providers[1]", "equals": "antigravity" },
|
|
16
16
|
{ "type": "json-path", "path": "$.providers[2]", "equals": "openai" },
|
|
17
17
|
{ "type": "json-path", "path": "$.providers[3]", "equals": "agent-skills" },
|
|
18
18
|
{ "type": "json-path", "path": "$.providers[4]", "equals": "markdown" },
|
package/conformance/coverage.md
CHANGED
|
@@ -18,7 +18,7 @@ This file is hand-maintained. A CI check before spec release compares the schema
|
|
|
18
18
|
| 8 | `job.schema.json` |, | 🔴 missing | Blocked by Step 10 (job system). Needs a case that submits a local action (no LLM), inspects `sm job show --json`. |
|
|
19
19
|
| 9 | `report-base.schema.json` |, | 🔴 missing | Indirect coverage once any summarizer case lands. Direct contract case: validate a handcrafted minimal report ({confidence, safety}) against the base schema. |
|
|
20
20
|
| 10 | `conformance-case.schema.json` |, | 🔴 missing | Self-referential: every `*.json` under `cases/` MUST validate against this schema. Add a meta-case that enumerates + validates all cases. |
|
|
21
|
-
| 11 | `frontmatter/base.schema.json` | `orphan-markdown-fallback` | 🟢 covered | Universal frontmatter shape, `name` + `description` only, `additionalProperties: true`. Per-kind schemas live with the Provider that emits them: vendor kinds (`skill` / `agent` / `command`) under `src/built-in-plugins/providers/{claude,
|
|
21
|
+
| 11 | `frontmatter/base.schema.json` | `orphan-markdown-fallback` | 🟢 covered | Universal frontmatter shape, `name` + `description` only, `additionalProperties: true`. Per-kind schemas live with the Provider that emits them: vendor kinds (`skill` / `agent` / `command`) under `src/built-in-plugins/providers/{claude,openai,agent-skills}/schemas/`; the format-named generic `markdown` kind under `src/built-in-plugins/providers/core-markdown/schemas/` (spec 0.18.0, markdown is provider-agnostic). All extend this base via `$ref`-by-`$id`. `orphan-markdown-fallback` exercises base-only frontmatter end-to-end via the `ARCHITECTURE.md` fixture file (no kind-specific extras). |
|
|
22
22
|
| 12 | `summaries/skill.schema.json` |, | 🔴 missing | Blocked by Step 10 (`skill-summarizer`). Case: submit summarizer, validate report. |
|
|
23
23
|
| 13 | `summaries/agent.schema.json` |, | 🔴 missing | Blocked by Step 11. |
|
|
24
24
|
| 14 | `summaries/command.schema.json` |, | 🔴 missing | Blocked by Step 11. |
|
|
@@ -4,7 +4,7 @@ description: Top-level markdown that no vendor Provider claims. Picked up by cor
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
This file lives at the project root with no platform-specific path
|
|
7
|
-
prefix. The claude /
|
|
7
|
+
prefix. The claude / openai / agent-skills Providers all return null
|
|
8
8
|
on it; the built-in `core/markdown` Provider claims it as kind
|
|
9
9
|
`markdown`. Without the universal fallback it would be silently
|
|
10
10
|
dropped from the scan.
|
package/db-schema.md
CHANGED
|
@@ -73,7 +73,7 @@ One row per detected node, matching [`schemas/node.schema.json`](./schemas/node.
|
|
|
73
73
|
| Column | Type | Constraint | Notes |
|
|
74
74
|
|---|---|---|---|
|
|
75
75
|
| `path` | TEXT | PRIMARY KEY | Relative path from scope root. Canonical node identifier. |
|
|
76
|
-
| `kind` | TEXT | NOT NULL | Open-by-design (`node.schema.json#/properties/kind`): the value is whatever the classifying Provider declares. Built-in catalogs: `claude` ships `skill` / `agent` / `command`; `
|
|
76
|
+
| `kind` | TEXT | NOT NULL | Open-by-design (`node.schema.json#/properties/kind`): the value is whatever the classifying Provider declares. Built-in catalogs: `claude` ships `skill` / `agent` / `command` / `mcp`; `openai` ships `agent`; `agent-skills` ships `skill`; `core/markdown` ships the format-named generic fallback `markdown` (universal, picks up any `.md` no vendor Provider claims, see `architecture.md` §Provider · dispatch order). The metadata-only `antigravity` Provider ships no kinds, Antigravity skills route through `agent-skills`. External Providers MAY emit their own. |
|
|
77
77
|
| `provider` | TEXT | NOT NULL | Provider extension id. |
|
|
78
78
|
| `title` | TEXT | NULL | |
|
|
79
79
|
| `description` | TEXT | NULL | |
|
package/index.json
CHANGED
|
@@ -174,23 +174,23 @@
|
|
|
174
174
|
}
|
|
175
175
|
]
|
|
176
176
|
},
|
|
177
|
-
"specPackageVersion": "0.
|
|
177
|
+
"specPackageVersion": "0.34.0",
|
|
178
178
|
"integrity": {
|
|
179
179
|
"algorithm": "sha256",
|
|
180
180
|
"files": {
|
|
181
|
-
"CHANGELOG.md": "
|
|
182
|
-
"README.md": "
|
|
183
|
-
"architecture.md": "
|
|
184
|
-
"cli-contract.md": "
|
|
181
|
+
"CHANGELOG.md": "50d7896784f0b209617e956bfe0dcbcc5af35d2dd6d76f5a0afdd96475fc4b27",
|
|
182
|
+
"README.md": "1c4b0ea58c4324f301043e9f5c36976a382d0bd2bc405a2e4e18463b0c50d946",
|
|
183
|
+
"architecture.md": "b38c5281acaaab57fbe4869780fb0a09712dd6927ec9bdaee961061d34f3525a",
|
|
184
|
+
"cli-contract.md": "2e20c2ac77c300b3f12759c3f36d56f4624862ff0abb34d100f1c3f00861bccc",
|
|
185
185
|
"conformance/README.md": "6871dde25b5770ed945284c9e0f749e0768ec3f5ba4966bdb215985789e43887",
|
|
186
186
|
"conformance/cases/kernel-empty-boot.json": "2a5be9c93143d07a16d998df09dcc8fa4ea2d2f9a0bff6417573ed5a770352c1",
|
|
187
187
|
"conformance/cases/no-global-scope.json": "1284763988026d924c0bd78ba8a9f417dc88f5b7e9f4c2b642ae0c447758bfd4",
|
|
188
188
|
"conformance/cases/orphan-markdown-fallback.json": "8ef6e49b7e6532bd845d9f54974a16e537cf98d355f0c5e4f4fb06abac3adcc5",
|
|
189
|
-
"conformance/cases/plugin-missing-ui-rejected.json": "
|
|
189
|
+
"conformance/cases/plugin-missing-ui-rejected.json": "59a571a2e80c2bac2050eacbe740f4f3f125849dd242954508f011304cc3e036",
|
|
190
190
|
"conformance/cases/sidecar-end-to-end.json": "dbb3640f95769a36b881855a261f918481edadea13a7eb0765c6090f2417a142",
|
|
191
|
-
"conformance/coverage.md": "
|
|
191
|
+
"conformance/coverage.md": "26aebe674304dca0d0173b1ed4af80be1f9384c18eb4d87574fc6021eee2e746",
|
|
192
192
|
"conformance/fixtures/orphan-markdown/.claude/agents/reviewer.md": "7f062731106f2d9811e4fffcf6ab44b8dfff4cfb16536a469514cc0664e832bf",
|
|
193
|
-
"conformance/fixtures/orphan-markdown/ARCHITECTURE.md": "
|
|
193
|
+
"conformance/fixtures/orphan-markdown/ARCHITECTURE.md": "ec903666440bae65da3796b1158c92cfcdce22e0e09c3b20bb690176881a6ac4",
|
|
194
194
|
"conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/kinds/markdown/kind.json": "6676a89bae5197e23cf50f1c11d596db558ac80f7334a7208fe57d8b92422251",
|
|
195
195
|
"conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/kinds/markdown/schema.json": "42795e7f1759fa25115a426edf5cd1b0c91b091b408aeee3f4f9fbc8f89f32bc",
|
|
196
196
|
"conformance/fixtures/plugin-missing-ui/.skill-map/plugins/bad-provider/plugin.json": "fb3f52f82f1635d0e5de74788eb5f640d0e36b19464a46f0b2812f6aa9db435f",
|
|
@@ -202,15 +202,15 @@
|
|
|
202
202
|
"conformance/fixtures/sidecar-end-to-end/.claude/agents/stale.sm": "cb04f7f3103b4218b09fd4da92f7ea429588b04c1dac6a9547ce362263b11224",
|
|
203
203
|
"conformance/fixtures/sidecar-example/agent-example.md": "741131403e8c9580d0b7a8c2446cb4502d01f80053b7a2092663de92431aaa82",
|
|
204
204
|
"conformance/fixtures/sidecar-example/agent-example.sm": "8329950d49c69a1199bbe6c06e32b8513973e64207b0db8756b67301e6a1f1e2",
|
|
205
|
-
"db-schema.md": "
|
|
205
|
+
"db-schema.md": "e56dab70f0469e8e6bd2440e8758c0436e710bc45c2ee812ac40a10b0c29ae77",
|
|
206
206
|
"interfaces/security-scanner.md": "e8049712b9cf7a07c786bf19f8f775f8ef9638f063f7fba5c7a8b1431b92f38e",
|
|
207
207
|
"job-events.md": "84206168ac12b536d34470d62f8c8cba95dab181fee66d23203c2cf5dfbee716",
|
|
208
208
|
"job-lifecycle.md": "9c429121f98a07c8795f8979ed1abc5e5334e3f89db51585a8da55c527ef855b",
|
|
209
|
-
"plugin-author-guide.md": "
|
|
209
|
+
"plugin-author-guide.md": "58331cdd07447f05775d2dd030f20e8276a1a227269c5f50b631230f83dec081",
|
|
210
210
|
"plugin-kv-api.md": "1acc69ed82433a74e35ada61d63a6d7379fb61046ff83de1e0facbe884c64704",
|
|
211
211
|
"prompt-preamble.md": "9dd4f6d1bc6a425f8782fcee10cbe75909e8d64e28781fda56c2fae909b02f40",
|
|
212
212
|
"schemas/annotations.schema.json": "e39990d47f53e25a1b3a5587a5714486d0b819b8eeaac10d42783a675296aee1",
|
|
213
|
-
"schemas/api/rest-envelope.schema.json": "
|
|
213
|
+
"schemas/api/rest-envelope.schema.json": "926c63af10574599da5583ed067788b4a72be427788f0aa11b61022fb9649461",
|
|
214
214
|
"schemas/bump-report.schema.json": "c2d853715d5f50098567bc23382a4e81baf78d589c6e1baf67d3b841e7f7d8ae",
|
|
215
215
|
"schemas/conformance-case.schema.json": "f6d4c9fb92e79cb516eeeb9d042223572a3bd5ff8e7871a0becce13916f20cf6",
|
|
216
216
|
"schemas/conformance-result.schema.json": "426998e4f5cb079778ca7d0233634667d4fbc5a7e399cc41211fabd768db8ee0",
|
|
@@ -222,7 +222,7 @@
|
|
|
222
222
|
"schemas/extensions/formatter.schema.json": "d6d417df20260e5ddfe71f104b11a45873869706f86372c3c3c78c583e06e8d5",
|
|
223
223
|
"schemas/extensions/hook.schema.json": "76bf2c07f9e689b3fd1c67cbad4516a4df10604f07103759e82670e5213ddcdf",
|
|
224
224
|
"schemas/extensions/provider-kind.schema.json": "add3c5648721e67887eb971a76b39319628effac6315cffd51f7dcf679810740",
|
|
225
|
-
"schemas/extensions/provider.schema.json": "
|
|
225
|
+
"schemas/extensions/provider.schema.json": "5fd8f0db17b3d4d23930cbba6f7dbc61feea0ea856fb720ccb9f07a544d18495",
|
|
226
226
|
"schemas/frontmatter/base.schema.json": "df0056a9478514a0db7a705e59868fa4f67673ac1cc9c9da979de4237cdd62a1",
|
|
227
227
|
"schemas/history-stats.schema.json": "5170dec0299f3d04382a38079a27b1f26300a6b95fdb1ea0fae11050ad9f0574",
|
|
228
228
|
"schemas/input-types.schema.json": "c713b768d0b0e3d0c764afb401189f7fb624a82b4e988b73aab015cf9c67c01f",
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
"schemas/node.schema.json": "8d0635a80c8e6f22be7fa04071654e857fc052869de15839f4b29593aa4527a3",
|
|
233
233
|
"schemas/plugins-doctor.schema.json": "c1d92f30fdb0080e8cd8f7dc5d43e01aae02a16640bc5eb04811c337a275de58",
|
|
234
234
|
"schemas/plugins-registry.schema.json": "cca7ae65f0c22510ea27ea5ae34e0074f5beb5871a57b005b6b831e6ceaff5c0",
|
|
235
|
-
"schemas/project-config.schema.json": "
|
|
235
|
+
"schemas/project-config.schema.json": "e613d302a763e8815863ae58ebfe997b18a3aa0c329f85d9554dfa8d97fdd326",
|
|
236
236
|
"schemas/refresh-report.schema.json": "54519b8caf86ba84c182f9565be9b5084bc1631ae05e9217ee18f34c0039fff3",
|
|
237
237
|
"schemas/report-base-deterministic.schema.json": "9d318d0181d121097c906ef3af1c52d71c782740bd04cf23418d7627ce2c3ed5",
|
|
238
238
|
"schemas/report-base.schema.json": "a1021e9a59b4df9f99cd92454d797e88469766e7d49f52d231c4645ffdfdad8f",
|
package/package.json
CHANGED
package/plugin-author-guide.md
CHANGED
|
@@ -127,7 +127,7 @@ Concrete examples for the reference impl's bundled extensions:
|
|
|
127
127
|
Built-ins split between two namespaces:
|
|
128
128
|
|
|
129
129
|
- **`core/`**, kernel-internal primitives, platform-agnostic. Owns every built-in analyzer (including `validate-all`), the ASCII formatter, and the cross-vendor extractors (`annotations`, `slash`, `at-directive`, `markdown-link`, `external-url-counter`) any Provider can rely on.
|
|
130
|
-
- **`claude/`**, the Claude Code Provider bundle: the Provider that classifies `.claude/{agents,commands,skills}` paths and parses their frontmatter.
|
|
130
|
+
- **`claude/`**, the Claude Code Provider bundle: the Provider that classifies `.claude/{agents,commands,skills}` paths and parses their frontmatter. Other vendor bundles (`antigravity`, `openai`, `agent-skills`) follow the same shape, Provider only, since the syntax their nodes use is shared with Claude and lives in `core`.
|
|
131
131
|
|
|
132
132
|
For your own plugin, the `id` you declare in `plugin.json` is the namespace for every extension the plugin contains. If your manifest declares `id: "my-plugin"` and your extension file declares `id: "foo-extractor"`, the kernel registers it as `my-plugin/foo-extractor`. You do **not** write the qualifier yourself, the loader injects it.
|
|
133
133
|
|
|
@@ -157,7 +157,7 @@ Every plugin and every built-in bundle declares a **granularity** that controls
|
|
|
157
157
|
|
|
158
158
|
Built-in mapping:
|
|
159
159
|
|
|
160
|
-
- **`claude`** / **`
|
|
160
|
+
- **`claude`** / **`antigravity`** / **`openai`** / **`agent-skills`**, `granularity: 'bundle'`. Each vendor Provider bundle is enabled or disabled as a whole; today every such bundle ships only its Provider, so the toggle flips classification + frontmatter parsing for that platform.
|
|
161
161
|
- **`core`**, `granularity: 'extension'`. `sm plugins disable core/superseded` flips just the supersession analyzer; every other core extension (every other analyzer, the ASCII formatter, the cross-vendor extractors) stays live.
|
|
162
162
|
|
|
163
163
|
Per-verb behaviour:
|
|
@@ -212,7 +212,7 @@ precondition?: {
|
|
|
212
212
|
|---|---|
|
|
213
213
|
| Absent (`undefined`) | **Default.** The extractor runs on every kind the loaded Providers emit. |
|
|
214
214
|
| `{ kind: ['claude/skill'] }` | Runs only on skill nodes from the Claude provider. |
|
|
215
|
-
| `{ kind: ['claude/skill', '
|
|
215
|
+
| `{ kind: ['claude/skill', 'agent-skills/skill'] }` | Runs on skills from either provider. |
|
|
216
216
|
| `{ provider: ['claude'] }` | Coarser: runs on every kind the `claude` plugin declares. |
|
|
217
217
|
| `{ kind: ['claude/skill'], provider: ['claude'] }` | Both filters apply (AND). |
|
|
218
218
|
|
|
@@ -339,7 +339,7 @@ You can read `ctx.node.sidecar.*` freely, the kernel's per-`(node, extractor)` c
|
|
|
339
339
|
|
|
340
340
|
> **Pick a syntax that doesn't collide with built-ins.** The built-in `at-directive` and `slash` extractors claim the `@` and `/` prefixes with LLM-aligned semantics:
|
|
341
341
|
>
|
|
342
|
-
> - **`core/at-directive`**: bare handles (`@team-lead`) and namespaced agents (`@my-plugin/foo-extractor`, `@skill-map:explore`) emit `mentions` links; file-flavoured tokens (`@docs/api/v1.md`, `@./readme.md`, `@../parent.md`, `@/abs/path.md`) emit `references` links so the graph treats them as file pointers, not entity mentions, the same way Claude Code /
|
|
342
|
+
> - **`core/at-directive`**: bare handles (`@team-lead`) and namespaced agents (`@my-plugin/foo-extractor`, `@skill-map:explore`) emit `mentions` links; file-flavoured tokens (`@docs/api/v1.md`, `@./readme.md`, `@../parent.md`, `@/abs/path.md`) emit `references` links so the graph treats them as file pointers, not entity mentions, the same way Claude Code / Antigravity CLI / Cursor would resolve them. The kind dispatch keys on (a) an explicit relative / absolute path prefix or (b) a known file extension at the tail.
|
|
343
343
|
> - **`core/slash`**: bare commands (`/scan`, `/skill-map:explore`) emit `invokes`; tokens whose next character is another `/` or any other identifier char are dropped as path segments (`/Volumes/disk`, `/api/v1/items`).
|
|
344
344
|
> - **Both extractors strip fenced code blocks and inline backticks before matching**, so author-marked literal payload never registers as invocation surface.
|
|
345
345
|
>
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"kindRegistry": {
|
|
54
54
|
"type": "object",
|
|
55
|
-
"description": "Catalog of node kinds active in the current scope, keyed by kind name. Built once per server boot from every enabled Provider's `kinds` map and embedded into every payload-bearing envelope so the UI can render kind tags / palette swatches / graph nodes against Provider-declared visuals (label, color, icon) without ever hardcoding a closed kind enum. Sentinel envelopes (`health`, `scan`, `graph`) are exempt. Each entry MAY carry contributions from multiple Providers when several declare the same kind name (e.g. Claude `agent` and
|
|
55
|
+
"description": "Catalog of node kinds active in the current scope, keyed by kind name. Built once per server boot from every enabled Provider's `kinds` map and embedded into every payload-bearing envelope so the UI can render kind tags / palette swatches / graph nodes against Provider-declared visuals (label, color, icon) without ever hardcoding a closed kind enum. Sentinel envelopes (`health`, `scan`, `graph`) are exempt. Each entry MAY carry contributions from multiple Providers when several declare the same kind name (e.g. Claude `agent` and OpenAI `agent`); the `providers` map keeps every contribution and `primaryProviderId` points at the one whose visuals drive the kind's primary CSS var. The kernel separately surfaces `provider-ambiguous` issues for files matched by more than one Provider; the UI may still receive the merged registry during the conflict window.",
|
|
56
56
|
"additionalProperties": {
|
|
57
57
|
"type": "object",
|
|
58
58
|
"required": ["primaryProviderId", "providers"],
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"providers": {
|
|
67
67
|
"type": "object",
|
|
68
68
|
"minProperties": 1,
|
|
69
|
-
"description": "Per-provider visuals for this kind name. Keyed by Provider id (e.g. `'claude'`, `'
|
|
69
|
+
"description": "Per-provider visuals for this kind name. Keyed by Provider id (e.g. `'claude'`, `'openai'`). Lets the UI render a node painted with its own Provider's color via `entry.providers[node.provider]` when the kind name is shared across Providers.",
|
|
70
70
|
"additionalProperties": {
|
|
71
71
|
"type": "object",
|
|
72
72
|
"required": ["label", "color"],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://skill-map.dev/spec/v0/extensions/provider.schema.json",
|
|
4
4
|
"title": "ExtensionProvider",
|
|
5
|
-
"description": "Manifest shape for a `Provider` extension. A Provider declares its own universe: the platform it recognises (Claude Code, Codex,
|
|
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": [
|
|
7
7
|
{ "$ref": "base.schema.json" }
|
|
8
8
|
],
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"activeProvider": {
|
|
28
28
|
"type": "string",
|
|
29
|
-
"description": "The active provider lens for this project. Exactly one provider id (from the enabled `providers` list) sees the project at any time. All extractors, classifiers, and resolution rules belonging to other providers are skipped during scan. Changing this triggers an atomic drop of the `scan_*` DB zone followed by a fresh scan under the new lens; `state_*` and `config_*` zones survive the switch. When absent on a fresh project, the kernel auto-detects from filesystem (presence of `.claude/`, `.
|
|
29
|
+
"description": "The active provider lens for this project. Exactly one provider id (from the enabled `providers` list) sees the project at any time. All extractors, classifiers, and resolution rules belonging to other providers are skipped during scan. Changing this triggers an atomic drop of the `scan_*` DB zone followed by a fresh scan under the new lens; `state_*` and `config_*` zones survive the switch. When absent on a fresh project, the kernel auto-detects from filesystem (presence of `.claude/`, `.codex/`, AGENTS.md, `.cursor/`, etc.) and prompts via the CLI / UI if the heuristic is ambiguous. Google's Antigravity CLI has no vendor-specific marker and is selected manually. Stability: experimental."
|
|
30
30
|
},
|
|
31
31
|
"roots": {
|
|
32
32
|
"type": "array",
|