docs(#1593): ADR for cross-runtime skill mapping + converter methodology

Phase A of epic #1258. Adds the single authoritative ADR documenting
the per-runtime skill mapping + converter transform-contract catalog
that ADR-3660 (layout) and ADR-1508 (module ownership) each carry a
third of. Ships a companion reference matrix projecting all 16
runtimes from their capability descriptors.

- docs/adr/1593-skill-mapping-converter-methodology.md (new ADR)
- docs/reference/skill-mapping-matrix.md (new reference page)
- docs/adr/README.md (index row + status fixes: 3660, 1016 Proposed->Accepted)
- docs/adr/1016-runtime-capability-descriptor.md (header Proposed->Accepted;
  the ConverterName enum is already code-enforced per ADR-857 phase 5e)

Doc-only. No code, no behavior change. Closes #1593.
This commit is contained in:
Tom Boucher
2026-06-22 16:23:44 -04:00
parent 3aa528d6e3
commit 860179ee5d
4 changed files with 181 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
# ADR-1016: Runtime Capability Descriptor
- **Status:** Proposed
- **Status:** Accepted
- **Date:** 2026-06-10
- **Issue:** [#1016](https://github.com/open-gsd/gsd-core/issues/1016)
- **Epic:** [#857](https://github.com/open-gsd/gsd-core/issues/857) (Capability system) — rollout phase 5

View File

@@ -0,0 +1,97 @@
# Skill mapping & converter methodology across runtimes
- **Status:** Accepted
- **Date:** 2026-06-22
- **Issue:** [#1593](https://github.com/open-gsd/gsd-core/issues/1593)
- **Epic:** [#1258](https://github.com/open-gsd/gsd-core/issues/1258) (Phase A — *"do first"*)
- **Extends:** [ADR-3660](3660-runtime-artifact-layout-module.md) (layout), [ADR-1016](1016-runtime-capability-descriptor.md) (enum — accepted here)
- **Sibling:** [ADR-1508](1508-runtime-artifact-conversion-module.md) (module ownership), [ADR-766](766-claude-code-plugin-manifest-module.md) (Claude plugin manifest)
## Context
GSD installs skills into 16 host CLIs (claude, codex, gemini, opencode, kilo, cursor, copilot, antigravity, windsurf, augment, trae, qwen, hermes, codebuddy, cline, kimi). The methodology governing *how* a source command file in `commands/gsd/*.md` becomes an installed skill on each runtime is real, load-bearing, and documented in fragments across three sources that disagree on what they own:
1. **[ADR-3660](3660-runtime-artifact-layout-module.md)** (Accepted) — owns the *structural* layout: the `{ kind, destSubpath, prefix, nesting, recursive, converter }` `ArtifactKindDescriptor` shape, per-runtime dest path, the `gsd-` prefix, flat-vs-nested under `gsd-ns-*` routers, and the `stage` closure contract binding each layout to its converter. ADR-3660 says where artifacts go; it does not describe what the converters *do*.
2. **[ADR-1016](1016-runtime-capability-descriptor.md)** (header Status: Proposed — **corrected to Accepted by this ADR**, see Decision 2) — owns the closed `ConverterName` enum and declares `artifactLayout` as descriptor data. Vocabulary only: it closes the set of named converters; it does not describe each converter's transform contract.
3. **`src/runtime-artifact-conversion.cts`** (~2,600 lines, the converter functions) — the actual per-runtime transform semantics: frontmatter filtering, tool-name rewrites, path rewrites, namespacing, description truncation, SKILL.md-vs-flat body format. **No ADR.** A future maintainer (human or agent) has no single place that says "this converter rewrites X, drops Y, truncates at Z."
A just-merged sibling — **[ADR-1508](1508-runtime-artifact-conversion-module.md)** (PR #1509, 2026-06-21) — owns *module ownership + dependency direction* for the conversion engine. Its body explicitly defers the methodology to this ADR: *"Distinct from epic #1258: #1258 Phase A documents the converter transform-contract catalog; this ADR decides module ownership + dependency direction."* The module now has a home; the *methodology it implements* did not.
Two concrete failures fall out of this documentation gap (surfaced while triaging #1243):
1. **Consumption:** `agent_skills`'s `global:` resolver hand-resolved a file path and could not reach plugin-provided skills. The resolution (PR #1261, Claude consume side) had to reverse-engineer the converter + layout + the platform's native skill-resolution mechanism separately because no ADR described how they relate.
2. **Provision:** GSD ships as a first-party plugin/extension on multiple platforms (`.claude-plugin/plugin.json` per ADR-766, `gemini-extension.json` per #775), but those manifests do not provide GSD's skills the platform-native way — the Claude manifest declares `commands` + `hooks`, no `skills`. No ADR states the provision methodology each platform demands.
## Decision
### 1. This ADR is the single authoritative description of the per-runtime skill mapping and converter transform contracts
It codifies — in one place — what ADR-3660 (layout), ADR-1016 (vocabulary), and `runtime-artifact-conversion.cts` (semantics) each carry a third of. The companion reference page, [`docs/reference/skill-mapping-matrix.md`](../reference/skill-mapping-matrix.md), holds the maintainable per-runtime table; this ADR holds the *decisions* behind it. **References, does not duplicate, ADR-3660** (the layout owner) — extends it with the converter + mapping methodology.
### 2. ADR-1016's `ConverterName` enum is Accepted (header correction)
ADR-1016's header says `Proposed`, but its `ConverterName` closed enum is **already code-enforced**: `gsd-core/bin/lib/capability-validator.cjs` rejects unknown converter names (*"is not a known ConverterName"*), and the enum is locked by a fail-first regression test at `tests/capability-registry.test.cjs:3956` (ADR-857 phase 5e). The decision is realized; the record is stale. This ADR accepts the enum and the ADR-1016 header is corrected `Proposed` → `Accepted` as a metadata correction (no behavior change).
The closed enum `VALID_CONVERTER_NAMES` (`capability-validator.cjs:651-678`) holds **24 names** in two blocks:
- **15 commands/skills converters** — the block ADR-1016's *"15 named first-party functions covering the 16 runtimes"* refers to. Of these, 13 are skill converters and 2 are command converters (`convertClaudeCommandToCodebuddyCommand`, `convertClaudeCommandToCursorCommand`). Three runtimes share `convertClaudeCommandToClaudeSkill` (claude, qwen, hermes), so the 15 skill-bearing runtimes (all except commands-only Gemini) resolve to 13 distinct skill converters.
- **9 agent converters** (`convertClaudeAgentTo{Copilot,Antigravity,Cursor,Windsurf,Augment,Trae,Codebuddy,Cline,Codex}Agent`) — added by #1173 for the descriptor-driven agent-conversion wiring (ADR-1235). These are not yet declared by any runtime's `agents` kind descriptor (the `convertedAgentsKind` builder exists but the declarations are deferred to a #1173 follow-up; the legacy `bin/install.js` agent loop remains authoritative).
### 3. The converter transform-contract categories
Every skill converter in `runtime-artifact-conversion.cts` composes some subset of eight transform categories. This is the catalog ADR-1508 deferred:
| # | Category | What it does | Representative functions |
|---|----------|--------------|--------------------------|
| 1 | **Frontmatter extraction & reconstruction** | Extract `(name, description, allowed-tools, argument-hint, agent, context, effort)` from the source command frontmatter; reconstruct in the runtime's skill frontmatter shape. | `extractFrontmatterAndBody`, `skillFrontmatterName`, every `convertClaudeCommandTo*Skill` |
| 2 | **Description truncation** | Runtimes with description-length limits truncate to the cap (e.g. Codex: 180 chars → `metadata.short-description`). | `convertClaudeCommandToCodexSkill` (`toSingleLine` + 177-char slice) |
| 3 | **Tool-name rewrites** | Map Claude tool names to runtime equivalents. | `convertToolName`, `convertKimiToolName`, `convertCopilotToolName`, `convertGeminiToolName`; inline: `AskUserQuestion`→`question`, `SlashCommand`→`skill` (opencode) |
| 4 | **Path rewrites** | `~/.claude` → the runtime's config path; `computePathPrefix` derives the install-target prefix; `transformContentToHyphen` normalizes `/gsd:<cmd>` → `gsd-<cmd>`. | `computePathPrefix`, `applyOpencodeFamilyPathPrefix`, `convertClaudeToOpencodeFrontmatter` |
| 5 | **Slash-command → skill-mention conversion** | For runtimes that surface skills (not slash commands), rewrite `/gsd:<cmd>` invocations into skill-tool mentions. | `convertSlashCommandsTo{Cursor,Windsurf,Augment,Trae,Codebuddy}SkillMentions` |
| 6 | **Runtime-specific branding / fields** | Emit runtime-required frontmatter the source does not carry. | Hermes: `version:`; Qwen: numeric `priority:` (`QWEN_SKILL_PRIORITY`); Codex: `metadata.short-description`; Kimi: name normalization |
| 7 | **Agent-reference neutralization** | For non-Claude runtimes, replace "Claude" → "the agent" and `CLAUDE.md` → the runtime's instruction file. | `neutralizeAgentReferences` |
| 8 | **Body format (SKILL.md-vs-flat)** | Governed by the layout `nesting` flag + the `stage` closure: nested runtimes ship `<router>/skills/<name>/SKILL.md`; flat runtimes ship `<prefix><stem>/SKILL.md` at one level. | `stageSkillsForRuntimeAsSkills` (in `install-profiles.cts`), `buildNamespaceBundleMap` |
A converter's contract is the fixed subset of these eight categories it applies, in order. **Transform order is load-bearing for byte-parity** (cf. ADR-1235 §0): stale-cleanup → path-prefix rewrite → `processAttribution` → runtime converter/branding → body normalization → filename rename. A converter that silently inherits another's ordering breaks byte-for-byte parity without a test signal.
### 4. The per-runtime skill mapping
The full 16-runtime matrix — dest path, prefix, nesting, loader recursion, converter, and per-runtime notes — lives in the companion reference page: [`docs/reference/skill-mapping-matrix.md`](../reference/skill-mapping-matrix.md). The authoritative source for any cell is the runtime's `capabilities/<runtime>/capability.json` `artifactLayout` descriptor (resolved by `resolveRuntimeArtifactLayout` in `runtime-artifact-layout.cts`); the reference page is the human-readable projection, kept in sync going forward.
Three structural facts the matrix encodes:
- **All 15 skill-bearing runtimes use `prefix: "gsd-"`.** (Gemini is commands-only — no skills kind.)
- **Six runtimes nest** under `gsd-ns-*` routers (cline, qwen, hermes, augment, trae, antigravity) because their skill loaders scan one level deep; the rest stay flat because their loaders recurse (cursor, opencode, kilo) or because nesting was reverted (claude — Skill-tool errors on unknown names, #924).
- **Three runtimes share `convertClaudeCommandToClaudeSkill`** (claude, qwen, hermes); the other 12 skill-bearing runtimes each have a dedicated converter.
### 5. Plugin / external-skill provision + consumption methodology
GSD's first-party plugin/extension on every supported platform should both **provide** its own skills and **consume** external/plugin-provided skills through each platform's *documented, native* mechanism — **never** by reaching into an undocumented or ephemeral cache.
**Provision** — ship GSD's skills the platform-native way:
- **Claude Code:** the `.claude-plugin/plugin.json` manifest should declare a `skills` field / `skills/` dir (today it declares only `commands` + `hooks`, per ADR-766). This is Phase B-provide / Phase D.
- **Other platforms:** assessed per-platform in Phase C; where a platform has no documented skill-provision model, record N/A with rationale.
**Consumption** — resolve plugin/external skills through the platform's native skill-resolution mechanism:
- **Claude Code:** the sub-agent `skills:` frontmatter preload (full content injected) and the runtime `Skill` tool (loads a namespaced skill by name). PR #1261 (Phase B consume side, merged 2026-06-15) is the reference implementation: `agent_skills` accepts the namespaced form `global:<plugin>:<skill>` and emits a by-name Skill-tool directive — no cache path is ever read.
- **Other platforms:** assessed per-platform in Phase C.
**Rejected:** reading another plugin's ephemeral cache (e.g. Claude Code's `${CLAUDE_PLUGIN_ROOT}` / `~/.claude/plugins/cache`, which *"changes when the plugin updates"*), or copying skill files to undocumented locations. These are workarounds, not fixes — the platform's native mechanism is the contract.
## Consequences
- **+** One authoritative description of the per-runtime skill mapping + converter transform contracts. A future maintainer or agent reads this ADR + the reference matrix instead of reverse-engineering three sources.
- **+** Unblocks Phases B-provide, C (C1–C6), and D of epic #1258 — each per-platform implementation cites this ADR as its methodology contract.
- **+** ADR-1016's header reflects reality (Accepted, not Proposed) — the ADR README index is corrected.
- **+** Closes the documentation leak adjacent to ADR-1508: the module has a home (ADR-1508), the methodology it implements has a record (this ADR).
- **−** The reference matrix must stay in sync with the capability descriptors. The descriptors (`capabilities/<runtime>/capability.json` `artifactLayout`) remain the source of truth; the reference page is a projection. A future runtime addition must update both the descriptor and the matrix row (the descriptor's `TypeError` on unknown runtime is the structural guard; the matrix drift is a documentation gap, not a runtime failure).
- **−** The eight transform-contract categories are descriptive, not type-enforced. A converter that grows a ninth category does not trip a gate — the closed `ConverterName` enum (ADR-1016) gates the *set* of converters, not the *shape* of each converter's transform.
## Relationship to other ADRs and issues
- **[ADR-3660](3660-runtime-artifact-layout-module.md)** (layout owner, Accepted) — extended, not duplicated. This ADR documents the converter contracts that ADR-3660's `stage` closure binds but does not describe.
- **[ADR-1016](1016-runtime-capability-descriptor.md)** (enum owner, header corrected to Accepted here) — the closed `ConverterName` enum is the type-enforcement substrate; this ADR documents what each named converter *does*.
- **[ADR-1508](1508-runtime-artifact-conversion-module.md)** (module owner, Accepted) — sibling. ADR-1508 decides *module ownership + dependency direction*; this ADR decides *methodology + transform contracts*. ADR-1508's Phase 1–2 implementation (epic #1507, relocating helpers inside `runtime-artifact-conversion.cts`) touches the same file this ADR documents — they are sequenced, not conflicting.
- **[ADR-766](766-claude-code-plugin-manifest-module.md)** (Claude plugin manifest, Accepted) — referenced for the provision methodology (the `skills` manifest field Phase B-provide / Phase D adds).
- **[ADR-1235](1235-descriptor-driven-agent-conversion-migration.md)** (descriptor-driven agent conversion) — complementary; its byte-parity transform-ordering rule is cited in Decision 3.
- **Epic [#1258](https://github.com/open-gsd/gsd-core/issues/1258)** — this is Phase A. Phase B-consume (PR #1261, merged) is the reference implementation canonized in Decision 5. Phases B-provide, C (C1–C6), D are tracked as separate issues per the epic's governance.

View File

@@ -48,7 +48,7 @@ See **[CONTRIBUTING.md — "Proposing an ADR or PRD"](../../CONTRIBUTING.md#prop
| [15-autonomous-cross-ai-convergence.md](15-autonomous-cross-ai-convergence.md) | Cross-AI plan convergence via existing orchestration commands | Proposed |
| [22-plan-drift-guard.md](22-plan-drift-guard.md) | Plan-vs-codebase drift guard: defaults and symbol-resolver seam | Proposed |
| [3524-cjs-sdk-hard-seam.md](3524-cjs-sdk-hard-seam.md) | CJS↔SDK hard seam — single canonical owner per responsibility (#3524) | Superseded by ADR-0174 |
| [3660-runtime-artifact-layout-module.md](3660-runtime-artifact-layout-module.md) | Runtime Artifact Layout Module owns per-runtime artifact placement | Proposed |
| [3660-runtime-artifact-layout-module.md](3660-runtime-artifact-layout-module.md) | Runtime Artifact Layout Module owns per-runtime artifact placement | Accepted |
| [0174-retire-gsd-sdk-package-boundary.md](0174-retire-gsd-sdk-package-boundary.md) | Retire @opengsd/gsd-sdk package boundary — single-runtime collapse | Accepted |
| [452-eslint-lint-harness.md](452-eslint-lint-harness.md) | Adopt standard ESLint flat-config lint harness; retire homegrown regex scanners | Accepted |
| [456-test-rigor-architecture.md](456-test-rigor-architecture.md) | Test-rigor architecture — deterministic scheduling, antagonistic tier, typed-surface mandate, delete-bad-tests policy | Accepted |
@@ -56,10 +56,11 @@ See **[CONTRIBUTING.md — "Proposing an ADR or PRD"](../../CONTRIBUTING.md#prop
| [660-release-from-next-head.md](660-release-from-next-head.md) | Release from the head of next; immutable release tags; @next dist-tag as the RC surface | Proposed |
| [58-runtime-install-policy-module.md](58-runtime-install-policy-module.md) | Runtime Install Policy Module owns the typed install-plan projection | Accepted |
| [766-claude-code-plugin-manifest-module.md](766-claude-code-plugin-manifest-module.md) | Claude Code Plugin Manifest Module owns the projection of gsd-core surfaces onto the Claude Code plugin contract | Accepted |
| [1016-runtime-capability-descriptor.md](1016-runtime-capability-descriptor.md) | Runtime Capability Descriptor | Proposed |
| [1016-runtime-capability-descriptor.md](1016-runtime-capability-descriptor.md) | Runtime Capability Descriptor | Accepted |
| [1235-descriptor-driven-agent-conversion-migration.md](1235-descriptor-driven-agent-conversion-migration.md) | Migrate agent conversion to the descriptor-driven install path (parity + per-runtime cutover) | Proposed |
| [1411-resolution-provenance.md](1411-resolution-provenance.md) | Resolution must report provenance, not fall open silently | Accepted |
| [1508-runtime-artifact-conversion-module.md](1508-runtime-artifact-conversion-module.md) | Runtime Artifact Conversion Module owns per-runtime content rewriting | Accepted |
| [1593-skill-mapping-converter-methodology.md](1593-skill-mapping-converter-methodology.md) | Skill mapping & converter methodology across runtimes | Accepted |
## Seam map

View File

@@ -0,0 +1,80 @@
# Per-runtime skill mapping matrix
> **Reference** page. The authoritative source for every cell is the runtime's `capabilities/<runtime>/capability.json` `artifactLayout` descriptor, resolved by `resolveRuntimeArtifactLayout` in `gsd-core/src/runtime-artifact-layout.cts`. This page is the human-readable projection; when they disagree, the descriptor wins.
>
> **Decision record:** [ADR-1593 — Skill mapping & converter methodology across runtimes](../adr/1593-skill-mapping-converter-methodology.md). See also [ADR-3660](../adr/3660-runtime-artifact-layout-module.md) (layout owner) and [ADR-1016](../adr/1016-runtime-capability-descriptor.md) (converter enum).
## How to read this matrix
GSD ships skills (and commands/agents) as Markdown files under `commands/gsd/*.md`. Each runtime installs them via a per-runtime **layout** (where they go) and a per-runtime **converter** (how their content is rewritten). The layout is a typed `ArtifactKindDescriptor`:
```
{ kind, destSubpath, prefix, nesting, recursive, converter }
```
- **dest** — the destination subpath under the runtime's config dir (e.g. `skills`, `skills/gsd`).
- **prefix** — the filename/dir prefix (`gsd-` for every skill-bearing runtime).
- **nesting** — `flat` (skills at one level) or `nested` (concrete skills nested under `gsd-ns-*` router dirs).
- **loader** — whether the runtime's skill loader recurses (`recursive: true` → nesting saves nothing, so the layout stays flat).
- **converter** — the `ConverterName` (closed enum, ADR-1016) that rewrites the source command into the runtime's skill format. `null` means raw-copy (no conversion).
For the transform each converter applies, see [ADR-1593 §3 — converter transform-contract categories](../adr/1593-skill-mapping-converter-methodology.md#3-the-converter-transform-contract-categories).
## The 16-runtime matrix
| Runtime | Skill dest (global) | Prefix | Nesting | Loader | Converter | Notes |
|---------|---------------------|--------|---------|--------|-----------|-------|
| **claude** | `skills/` | `gsd-` | flat | one-level (reverted from nested, #924) | `convertClaudeCommandToClaudeSkill` | Local scope ships commands+agents only (no `skills` kind). Plugin manifest (`ADR-766`) ships commands+hooks today; `skills` field is Phase B-provide. |
| **codex** | `skills/` | `gsd-` | flat | unconfirmed → conservative | `convertClaudeCommandToCodexSkill` | TOML config (`configFormat: toml`). Description truncated to 180 chars (`metadata.short-description`). `sandboxTier: codex-agent-sandbox`. |
| **gemini** | — *(no skills kind)* | — | — | — | — | Commands-only (TOML `.toml` in `commands/gsd`). No skill surface today — Phase C1 assesses Gemini's extension/skill model. |
| **opencode** | `skills/` | `gsd-` | flat | recursive (`**` glob) | `convertClaudeCommandToOpencodeSkill` | XDG config home. Shares the opencode-family converter entry point (`convertClaudeCommandToOpencodeFamilySkill`). Also ships `command` (singular) commands. |
| **kilo** | `skills/` | `gsd-` | flat | recursive (`**` glob) | `convertClaudeCommandToKiloSkill` | OpenCode fork; same `**` glob loader. `permissionWriter: kilo`. Also ships `command` commands. |
| **cursor** | `skills/` | `gsd-` | flat | recursive | `convertClaudeCommandToCursorSkill` | Also ships flat `commands/` via `convertClaudeCommandToCursorCommand`. `configFormat: none`. |
| **copilot** | `skills/` | `gsd-` | flat | unconfirmed → conservative | `convertClaudeCommandToCopilotSkill` | Markdown config. Scope-aware converter (global-home vs workspace-relative). |
| **antigravity** | `skills/` | `gsd-` | nested | non-recursive (one-level) | `convertClaudeCommandToAntigravitySkill` | `dot-home-nested` config home. Scope-aware converter. Nesting confirmed: *"will not recursive scan"*. |
| **windsurf** | `skills/` | `gsd-` | flat | unconfirmed → conservative | `convertClaudeCommandToWindsurfSkill` | `configFormat: none`. `installSurface: profile-marker-only`. |
| **augment** | `skills/` | `gsd-` | nested | non-recursive (single-level) | `convertClaudeCommandToAugmentSkill` | Also ships flat `commands/`. Settings-json config. |
| **trae** | `skills/` | `gsd-` | nested | non-recursive (flat; nesting errors) | `convertClaudeCommandToTraeSkill` | `configFormat: none`. Trae IDE (trae.ai), not trae-agent. |
| **qwen** | `skills/` | `gsd-` | nested | non-recursive (flat readdir) | `convertClaudeCommandToClaudeSkill` | **Shares Claude's converter.** Emits numeric `priority:` (`QWEN_SKILL_PRIORITY`) for `/skills` ordering. Settings-json config. |
| **hermes** | `skills/gsd/` | `gsd-` | nested | non-recursive (single-level probe) | `convertClaudeCommandToClaudeSkill` | **Shares Claude's converter.** `destSubpath: skills/gsd` (category dir). Emits required `version:` field. `prefix: gsd-` restored by #947. |
| **codebuddy** | `skills/` | `gsd-` | flat | unconfirmed → conservative | `convertClaudeCommandToCodebuddySkill` | Also ships flat `commands/` via `convertClaudeCommandToCodebuddyCommand`. `dot-home` config. |
| **cline** | `skills/` | `gsd-` | nested | non-recursive (flat `fs.readdir`) | `convertClaudeCommandToClineSkill` | **Global-only** — `local: []` (no local skill install). Targets `~/.cline/skills/<name>/SKILL.md` (Cline ≥ v3.48.0). `markdown-dir` config. |
| **kimi** | `skills/` | `gsd-` | flat | (false) | `convertClaudeCommandToKimiSkill` | Also ships a special `kimi-agents` kind (`buildKimiAgentArtifacts`). Name normalization (`normalizeKimiSkillName`). `generic-agents-root` config. |
### Structural facts
- **All 15 skill-bearing runtimes use `prefix: "gsd-"`.** Gemini is the only runtime with no skills kind (commands-only TOML).
- **Six runtimes nest** (cline, qwen, hermes, augment, trae, antigravity) because their skill loaders scan one level deep — nesting drops nested concrete skills out of the eager top-level listing while keeping them readable by file path (the namespace-router contract, #69).
- **Eight runtimes stay flat**: three because their loaders recurse (cursor, opencode, kilo — nesting saves nothing), one because nesting was reverted (claude — the Skill tool errors on unknown names rather than re-routing, #924), and four conservatively where the loader depth is unconfirmed (codex, copilot, windsurf, codebuddy).
- **Three runtimes share `convertClaudeCommandToClaudeSkill`** (claude, qwen, hermes). The converter branches on the `runtime` arg for per-runtime branding (Hermes `version:`, Qwen `priority:`).
## Nesting/loader verification (June 2026)
The nesting flag is set per the verified loader behavior of each runtime. Sources:
| Behavior | Runtimes | Evidence |
|----------|----------|----------|
| **NEST** (non-recursive / one-level scan) | cline, qwen, hermes, augment, trae, antigravity | cline `skills.ts` flat `fs.readdir`; Qwen `skill-load.ts` flat readdir; hermes single-level subdir probe; augment flat single-level; trae flat (nesting errors, Trae-AI/TRAE#2253); antigravity *"will not recursive scan"* |
| **FLAT** (recursive loader → nesting gives no saving) | cursor, opencode, kilo | cursor walks skills root recursively; opencode `skill/index.ts` glob `skills/**/SKILL.md`; kilo (opencode fork, same `**` glob) |
| **FLAT** (reverted from nested) | claude | anthropics/claude-code#28266 — one-level scan, but Skill-tool errors on unknown names rather than re-routing via the router (#924) |
| **FLAT** (unconfirmed → conservative) | codex, copilot, windsurf, codebuddy | Loader depth not independently verified; kept flat to avoid mis-nesting |
## Plugin / external-skill provision + consumption
Per [ADR-1593 §5](../adr/1593-skill-mapping-converter-methodology.md#5-plugin--external-skill-provision--consumption-methodology), each platform's first-party packaging should provide and consume skills through the platform's *documented, native* mechanism.
| Runtime | Provision model | Consumption model | Phase |
|---------|-----------------|-------------------|-------|
| **claude** | `.claude-plugin/plugin.json` `skills` field / `skills/` dir (ADR-766; today commands+hooks only) | Sub-agent `skills:` preload + runtime `Skill` tool (PR #1261 — merged) | B-provide / D |
| **gemini** | `gemini-extension.json` (today commands-only, #775) | TBD — assess Gemini's extension/skill model | C1 |
| **codex** | Codex extension model | TBD | C2 |
| **opencode / kilo** | Recursive-loader plugin model | TBD | C3 |
| **cursor, copilot, windsurf, codebuddy** | Flat-skill platform models | TBD | C4 |
| **cline, qwen, hermes, augment, trae, antigravity** | Nested `gsd-ns-*` router models | TBD | C5 |
| **kimi** | `kimi-agents` CLI module model | TBD | C6 |
> **Rejected for all platforms:** reading another plugin's ephemeral/undocumented cache (e.g. Claude Code's `${CLAUDE_PLUGIN_ROOT}` / `~/.claude/plugins/cache`). The platform's native mechanism is the contract; cache-reading is a workaround, not a fix.
## Keeping this page in sync
The `capabilities/<runtime>/capability.json` `artifactLayout` descriptors are the source of truth. When a runtime's layout changes, update the descriptor first; this page is the projection. Adding a new runtime requires: (1) a new `capabilities/<runtime>/capability.json` with an `artifactLayout`, (2) a new converter in the closed `ConverterName` enum (ADR-1016), and (3) a new row in this matrix.