From 08dfcad5f176992210dc40d2648668a53ca2bca3 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 23 Jun 2026 14:05:49 -0400 Subject: [PATCH 1/2] docs(#1617): correct Antigravity skill layout from nested to flat --- docs/ARCHITECTURE.md | 4 ++-- docs/USER-GUIDE.md | 2 +- docs/reference/skill-mapping-matrix.md | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index c8cfa0a4e..8cfc3b76d 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -123,7 +123,7 @@ User-facing entry points. Each file contains YAML frontmatter (name, description #### Two-stage hierarchical routing (v1.40, [#2792](https://github.com/open-gsd/gsd-core/issues/2792)) -To keep the eager skill-listing token cost low, v1.40 introduces six namespace **meta-skills** (`gsd-workflow`, `gsd-project`, `gsd-quality`, `gsd-context`, `gsd-manage`, `gsd-ideate` — sourced from `commands/gsd/ns-*.md`, but the invocable `name:` is the bare form shown here) layered above the concrete sub-skills. On runtimes with non-recursive skill loaders (claude global, cline, qwen, hermes, augment, trae, antigravity) the installer now realizes this fully: it emits only the 6 namespace router bundles as top-level skills and nests the ~61 concrete skills under `/skills//SKILL.md`, so the eager listing is ≈6 entries instead of ≈67. The model selects a namespace router, which instructs it to read the nested concrete skill file via a routing table embedded in the router body. On these runtimes concrete skills are **not** directly invocable by bare name via the Skill tool; they are reachable through the router. Slash commands (`/gsd-*`, via the separate commands surface) are unaffected where the runtime has one. On runtimes with recursive or unconfirmed skill loaders (cursor, codex, copilot, windsurf, codebuddy, opencode, kilo) the layout remains flat — all skills emitted at the top level as before. +To keep the eager skill-listing token cost low, v1.40 introduces six namespace **meta-skills** (`gsd-workflow`, `gsd-project`, `gsd-quality`, `gsd-context`, `gsd-manage`, `gsd-ideate` — sourced from `commands/gsd/ns-*.md`, but the invocable `name:` is the bare form shown here) layered above the concrete sub-skills. On runtimes with non-recursive skill loaders (claude global, cline, qwen, hermes, augment, trae) the installer now realizes this fully: it emits only the 6 namespace router bundles as top-level skills and nests the ~61 concrete skills under `/skills//SKILL.md`, so the eager listing is ≈6 entries instead of ≈67. The model selects a namespace router, which instructs it to read the nested concrete skill file via a routing table embedded in the router body. On these runtimes concrete skills are **not** directly invocable by bare name via the Skill tool; they are reachable through the router. Slash commands (`/gsd-*`, via the separate commands surface) are unaffected where the runtime has one. On runtimes with recursive or unconfirmed skill loaders (cursor, codex, copilot, windsurf, codebuddy, opencode, kilo, antigravity) the layout remains flat — all skills emitted at the top level as before. Antigravity moved from nested to flat in #1614: `agy` scans only `skills//SKILL.md`, so nested sub-skills were unreachable. The router descriptions use pipe-separated keyword tags (≤ 60 chars) per the Tool Attention research showing keyword-dense tags outperform prose for routing at ~40 % the token cost. @@ -840,7 +840,7 @@ The migration-specific ownership and source snapshots live in | Kimi CLI | First-existing generic root: `~/.config/agents` recommended, then `~/.agents` when `~/.agents/skills` exists and `~/.config/agents/skills` does not | Deferred and guarded | `skills/gsd-*/SKILL.md` (flat) invoked as `/skill:gsd-*` | `agents/gsd.yaml`, `agents/gsd.md`, and `agents/subagents/gsd-*` YAML/prompt pairs | Explicit `kimi --agent-file /agents/gsd.yaml`; no GSD hooks or statusline | | Codex | `~/.codex` | `./.codex` | `skills/gsd-*/SKILL.md` (flat) | `agents/` source markdown plus per-agent TOML | `config.toml` `[agents.gsd-*]`, `[features].hooks` (canonical; legacy alias `codex_hooks` is recognized and migrated forward on reinstall, #3566), and hook tables | | GitHub Copilot | `~/.copilot` | `./.github` | `skills/gsd-*/SKILL.md` (flat), `copilot-instructions.md`, and `AGENTS.md` (repo root, local) | `.agent.md` files | Self-contained `sessionStart` hook (`hooks/gsd-session.json`, inline `command` type); no statusline | -| Antigravity | auto-detected: `~/.gemini/antigravity`, `~/.gemini/antigravity-ide`, or `~/.gemini/antigravity-cli` | `./.agent` | `skills/gsd-ns-*/SKILL.md` (6 routers) + `skills/gsd-ns-*/skills//SKILL.md` (nested concretes) | `agents/gsd-*.md` | Gemini-style `settings.json` hook entries when installed by GSD | +| Antigravity | auto-detected: `~/.gemini/antigravity`, `~/.gemini/antigravity-ide`, or `~/.gemini/antigravity-cli` | `./.agent` | `skills/gsd-*/SKILL.md` (flat, #1614) | `agents/gsd-*.md` | Gemini-style `settings.json` hook entries when installed by GSD | | Cursor | `~/.cursor` | `./.cursor` | `skills/gsd-*/SKILL.md` (flat) | `agents/gsd-*.md` | Rule references under `rules/`; `hooks.json` with sessionStart context injection and postToolUse STATE.md monitor (#777) | | Windsurf | `~/.codeium/windsurf` | `./.devin` (canonical, #1085); `./.windsurf` legacy recognized | `skills/gsd-*/SKILL.md` (flat) | `agents/gsd-*.md` | Rule references under `rules/`; no GSD hooks | | Augment Code | `~/.augment` | `./.augment` | `skills/gsd-ns-*/SKILL.md` (6 routers) + `skills/gsd-ns-*/skills//SKILL.md` (nested concretes) | `agents/gsd-*.md` | No GSD hooks or statusline | diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md index 1ae10c207..aa6b1ac93 100644 --- a/docs/USER-GUIDE.md +++ b/docs/USER-GUIDE.md @@ -48,7 +48,7 @@ GSD ships six **namespace router bundles** (`gsd-ns-workflow`, `gsd-ns-project`, Each router's body contains a routing table. When the model receives a request, it reads the router, identifies the relevant sub-skill by name, then opens `skills//SKILL.md` via a file-path `Read`. The concrete skill is fully available — it is not invocable by bare name through the Skill tool's top-level listing, but is reachable through the router. -The nested layout applies only to runtimes with confirmed non-recursive skill loaders: **Claude (global), Cline, Qwen, Hermes, Augment, Trae, Antigravity**. Recursive or unconfirmed loaders (Cursor, Codex, Copilot, Windsurf, CodeBuddy, OpenCode, Kilo) retain the flat layout unchanged. +The nested layout applies only to runtimes with confirmed non-recursive skill loaders: **Claude (global), Cline, Qwen, Hermes, Augment, Trae**. Antigravity's loader is also non-recursive, but #1614 moved it flat because `agy` scans only `skills//SKILL.md` — nested sub-skills were unreachable. Other recursive or unconfirmed loaders (Cursor, Codex, Copilot, Windsurf, CodeBuddy, OpenCode, Kilo) retain the flat layout unchanged. | Namespace | Router bundle | Routes to | |-----------|--------------|-----------| diff --git a/docs/reference/skill-mapping-matrix.md b/docs/reference/skill-mapping-matrix.md index af3e6a699..91e25c27c 100644 --- a/docs/reference/skill-mapping-matrix.md +++ b/docs/reference/skill-mapping-matrix.md @@ -31,7 +31,7 @@ For the transform each converter applies, see [ADR-1593 §3 — converter transf | **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"*. | +| **antigravity** | `skills/` | `gsd-` | flat | non-recursive (one-level) | `convertClaudeCommandToAntigravitySkill` | `dot-home-nested` config home. Scope-aware converter. Loader confirmed: *"will not recursive scan"*. Flattened by #1614 — `agy` scans only `skills//SKILL.md`, so nesting hid sub-skills. | | **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. | @@ -44,8 +44,8 @@ For the transform each converter applies, see [ADR-1593 §3 — converter transf ### 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). +- **Five runtimes nest** (cline, qwen, hermes, augment, trae) 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). +- **Nine runtimes stay flat**: three because their loaders recurse (cursor, opencode, kilo — nesting saves nothing), two because nesting was reverted (claude — the Skill tool errors on unknown names rather than re-routing, #924; antigravity — `agy` scans only `skills//SKILL.md`, so nested sub-skills were unreachable, #1614), 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) @@ -54,9 +54,9 @@ The nesting flag is set per the verified loader behavior of each runtime. Source | 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"* | +| **NEST** (non-recursive / one-level scan) | cline, qwen, hermes, augment, trae | 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) | | **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** (reverted from nested) | claude, antigravity | claude: anthropics/claude-code#28266 — one-level scan, but Skill-tool errors on unknown names rather than re-routing via the router (#924). antigravity: `agy` scans only `skills//SKILL.md`; nesting made sub-skills unreachable, reverted to flat (#1614) | | **FLAT** (unconfirmed → conservative) | codex, copilot, windsurf, codebuddy | Loader depth not independently verified; kept flat to avoid mis-nesting | ## Plugin / external-skill provision + consumption From e32eac56a6dfcfabe57f7b36264b62c172fefc17 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 23 Jun 2026 14:11:22 -0400 Subject: [PATCH 2/2] docs(#1618): correct Claude skill layout from nested to flat --- docs/ARCHITECTURE.md | 4 ++-- docs/USER-GUIDE.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 8cfc3b76d..acd269a02 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -123,7 +123,7 @@ User-facing entry points. Each file contains YAML frontmatter (name, description #### Two-stage hierarchical routing (v1.40, [#2792](https://github.com/open-gsd/gsd-core/issues/2792)) -To keep the eager skill-listing token cost low, v1.40 introduces six namespace **meta-skills** (`gsd-workflow`, `gsd-project`, `gsd-quality`, `gsd-context`, `gsd-manage`, `gsd-ideate` — sourced from `commands/gsd/ns-*.md`, but the invocable `name:` is the bare form shown here) layered above the concrete sub-skills. On runtimes with non-recursive skill loaders (claude global, cline, qwen, hermes, augment, trae) the installer now realizes this fully: it emits only the 6 namespace router bundles as top-level skills and nests the ~61 concrete skills under `/skills//SKILL.md`, so the eager listing is ≈6 entries instead of ≈67. The model selects a namespace router, which instructs it to read the nested concrete skill file via a routing table embedded in the router body. On these runtimes concrete skills are **not** directly invocable by bare name via the Skill tool; they are reachable through the router. Slash commands (`/gsd-*`, via the separate commands surface) are unaffected where the runtime has one. On runtimes with recursive or unconfirmed skill loaders (cursor, codex, copilot, windsurf, codebuddy, opencode, kilo, antigravity) the layout remains flat — all skills emitted at the top level as before. Antigravity moved from nested to flat in #1614: `agy` scans only `skills//SKILL.md`, so nested sub-skills were unreachable. +To keep the eager skill-listing token cost low, v1.40 introduces six namespace **meta-skills** (`gsd-workflow`, `gsd-project`, `gsd-quality`, `gsd-context`, `gsd-manage`, `gsd-ideate` — sourced from `commands/gsd/ns-*.md`, but the invocable `name:` is the bare form shown here) layered above the concrete sub-skills. On runtimes with non-recursive skill loaders (cline, qwen, hermes, augment, trae) the installer now realizes this fully: it emits only the 6 namespace router bundles as top-level skills and nests the ~61 concrete skills under `/skills//SKILL.md`, so the eager listing is ≈6 entries instead of ≈67. The model selects a namespace router, which instructs it to read the nested concrete skill file via a routing table embedded in the router body. On these runtimes concrete skills are **not** directly invocable by bare name via the Skill tool; they are reachable through the router. Slash commands (`/gsd-*`, via the separate commands surface) are unaffected where the runtime has one. On runtimes with recursive or unconfirmed skill loaders (claude global, cursor, codex, copilot, windsurf, codebuddy, opencode, kilo, antigravity) the layout remains flat — all skills emitted at the top level as before. Antigravity moved from nested to flat in #1614: `agy` scans only `skills//SKILL.md`, so nested sub-skills were unreachable. Claude was reverted to flat in #924: the Skill tool hard-errors on unknown names rather than re-routing via the router, so nested concrete skills were uninvokable. The router descriptions use pipe-separated keyword tags (≤ 60 chars) per the Tool Attention research showing keyword-dense tags outperform prose for routing at ~40 % the token cost. @@ -833,7 +833,7 @@ The migration-specific ownership and source snapshots live in | Runtime | Global root | Local root | Invocation surface | Agent surface | Config and hooks | | --- | --- | --- | --- | --- | --- | -| Claude Code | `~/.claude` | `./.claude` | Global `skills/gsd-ns-*/SKILL.md` (6 routers) + `skills/gsd-ns-*/skills//SKILL.md` (nested concretes); local `commands/gsd/*.md` | `agents/gsd-*.md` | `settings.json` hook and statusLine entries | +| Claude Code | `~/.claude` | `./.claude` | Global `skills/gsd-*/SKILL.md` (flat, #924); local `commands/gsd/*.md` | `agents/gsd-*.md` | `settings.json` hook and statusLine entries | | OpenCode | `~/.config/opencode` | `./.opencode` | `command/gsd-*.md` | `agents/gsd-*.md` | `opencode.json` or `opencode.jsonc`; no GSD hooks | | Kilo | `~/.config/kilo` | `./.kilo` | `command/gsd-*.md` | `agents/gsd-*.md` | `kilo.json` or `kilo.jsonc`; no GSD hooks | | Gemini CLI | `~/.gemini` | `./.gemini` | `commands/gsd/*.toml` | `agents/gsd-*.md` | `settings.json` feature flag, hooks, and statusline | diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md index aa6b1ac93..3245a38be 100644 --- a/docs/USER-GUIDE.md +++ b/docs/USER-GUIDE.md @@ -48,7 +48,7 @@ GSD ships six **namespace router bundles** (`gsd-ns-workflow`, `gsd-ns-project`, Each router's body contains a routing table. When the model receives a request, it reads the router, identifies the relevant sub-skill by name, then opens `skills//SKILL.md` via a file-path `Read`. The concrete skill is fully available — it is not invocable by bare name through the Skill tool's top-level listing, but is reachable through the router. -The nested layout applies only to runtimes with confirmed non-recursive skill loaders: **Claude (global), Cline, Qwen, Hermes, Augment, Trae**. Antigravity's loader is also non-recursive, but #1614 moved it flat because `agy` scans only `skills//SKILL.md` — nested sub-skills were unreachable. Other recursive or unconfirmed loaders (Cursor, Codex, Copilot, Windsurf, CodeBuddy, OpenCode, Kilo) retain the flat layout unchanged. +The nested layout applies only to runtimes with confirmed non-recursive skill loaders: **Cline, Qwen, Hermes, Augment, Trae**. Claude's loader is also non-recursive, but #924 reverted it flat because the Skill tool hard-errors on unknown names rather than re-routing via the router. Antigravity's loader is also non-recursive, but #1614 moved it flat because `agy` scans only `skills//SKILL.md` — nested sub-skills were unreachable. Other recursive or unconfirmed loaders (Cursor, Codex, Copilot, Windsurf, CodeBuddy, OpenCode, Kilo) retain the flat layout unchanged. | Namespace | Router bundle | Routes to | |-----------|--------------|-----------|