* feat(#3840): generate docs/FEATURES.md from per-feature fragments docs/FEATURES.md was hand-maintained, and every feature PR wrote into two shared mutable cells: the '### N.' heading whose integer was hand-allocated at authoring time, and the hand-maintained table of contents. Concurrent PRs all picked the same next integer, and two PRs adding differently numbered features still collided on the TOC. #3831 was renumbered 165 -> 166 -> 167 -> 168 across successive rebases, each collision also costing a full matrix verification run because the sha-keyed pass marker dies with the rebase. Mechanism: one fragment per feature at docs/features/<slug>.md carrying id/title/group (and an optional order) in frontmatter, consolidated by scripts/gen-features.cjs --write|--check into a marker-delimited region of docs/FEATURES.md that holds BOTH the TOC and every section body. Group headings and their order are derived too - a group sorts by its lowest-ordered member - so there is no shared registry to edit either; optional per-group prose lives in docs/features/_groups/<slug>.md. A contributor adds exactly one new file. Wired into regen:derived and lint:generated-sync alongside the eight existing generators, matching gen-adr-index.cjs's CLI shape and typed-REASON reporting. Migration froze all 168 existing numbers verbatim: identical section set, identical order, identical bodies. Two defects found in the tree are fixed inline rather than carried forward - the '## Related' block had been spliced into the middle of the document, orphaning §142's Reference line, and four inbound anchors were already broken on next (FEATURES.md#runtime-identity in two files, and #143-spec-phase-edge-completeness-probe off by one). Since the repo has no link checker, --check now validates every inbound FEATURES.md#anchor by resolved target, so that class cannot ship silently again; locale FEATURES.md files resolve elsewhere and stay out of scope. Refs #3840 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(#3840): carry upstream §69 delta into its fragment and harden the generator Review found section 69 missing '[--strict]' and REQ-STATE-05/06 versus origin/next. Root cause was a stale base, not extraction loss: those lines landed in394bf384b(#3844) AFTER this branch forked at63abcface, and 'git diff63abcfaceorigin/next -- docs/FEATURES.md' is exactly that hunk. Merging origin/next auto-applied the hunk into the GENERATED region, which --check immediately reported as stale; the delta is now carried in docs/features/statemd-consistency-gates.md and regenerated from there. --write is now fail-closed. It previously rendered the region even with violations outstanding, warning only on stderr and exiting 0, so a '--write && git commit' chain could commit a FEATURES.md carrying two colliding sections. It now refuses and exits 1; --force is the explicit override and says so in the report. The test that pinned the old behavior now pins the refusal, plus the --force override and its scoping. Marker forgery is rejected at two layers. A fragment body containing '<!-- FEATURES:START' or '<!-- FEATURES:END' is a typed body_forges_region_marker violation (fragments and group notes alike), and spliceIntoFeatures anchors the end boundary with lastIndexOf instead of indexOf, so a marker that reaches the document by any other route can only make the generated region grow, never shrink. Matching is on marker PREFIXES, so a decorated variant comment cannot slip past. Symlinked corpus entries are refused with a typed dirent_not_regular_file rather than read. A fork PR could otherwise commit docs/features/evil.md as a symlink to any readable path and have the generator inline those bytes into the committed docs/FEATURES.md on the next regen. Equivalence re-verified with a method that cannot cancel out. The first check extracted both operands with the same body-normalising helper, so anything that helper dropped was dropped on both sides. The replacement runs two independent passes: a global content-line multiset diff with no per-section logic at all (0 gained, 19 lost, all 19 the stale hand-written mini-TOC links this change deliberately deletes), and a per-section byte-exact body diff carrying a coverage assertion that fails loudly per file when the extractor accounts for fewer lines than the file contains. That assertion caught two blind spots in the checker itself. 168/168 sections present, order identical, one intended body difference (§142 regains the Reference line orphaned by the misplaced '## Related' block). Refs #3840 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(#3840): backfill changeset PR number Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: sim <sim@local> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
5.0 KiB
5.0 KiB
id, title, group
| id | title | group |
|---|---|---|
| 36 | Multi-Runtime Support | Infrastructure Features |
Purpose: Run GSD across multiple AI coding agent runtimes.
Requirements:
- REQ-RUNTIME-01: System MUST support Claude Code, OpenCode, Kilo, Codex, Copilot, Antigravity, Trae, Cline, Augment Code, CodeBuddy, Qwen Code
- REQ-RUNTIME-02: Installer MUST transform content per runtime (tool names, paths, frontmatter)
- REQ-RUNTIME-03: Installer MUST support interactive and non-interactive (
--claude --global) modes - REQ-RUNTIME-04: Installer MUST support both global and local installation
- REQ-RUNTIME-05: Uninstall MUST cleanly remove all GSD files without affecting other configurations
- REQ-RUNTIME-06: Installer MUST handle platform differences (Windows, macOS, Linux, WSL, Docker)
- REQ-RUNTIME-07: Runtimes with lifecycle hook support MUST register per-turn context-headroom tracking events at install time
- REQ-RUNTIME-08: Native packaging manifests MUST be version-stamped and enable runtime-native install/update/uninstall flows
Runtime Transformations:
| Aspect | Claude Code | OpenCode | Kilo | Codex | Copilot | Antigravity | Cursor | Trae | Cline | Augment | CodeBuddy | Qwen Code |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Commands | Slash commands | Slash commands | Slash commands | Skills (TOML) | Slash commands | Skills | Skills + Slash commands | Skills | Rules | Skills + Slash commands | Slash commands | Skills |
| Agent format | Claude native | mode: subagent |
mode: subagent |
Skills | Tool mapping | Skills | Skills | Skills | Rules | Skills | Skills | Skills |
| Skills emission | N/A | On-demand SKILL.md (1.4.0) | On-demand SKILL.md (1.4.0) | /skills picker (1.4.0) |
N/A | N/A | SKILL.md | N/A | On-demand SKILL.md (1.4.0) | N/A | N/A | N/A |
| Hook events | SessionStart, PreToolUse, PostToolUse, SubagentStop, Stop, PreCompact, FileChanged |
N/A | N/A | SessionStart, SubagentStart, Stop, PostToolUse |
sessionStart |
N/A | sessionStart, postToolUse |
N/A | PreToolUse |
N/A | N/A | SessionStart, PreToolUse, PostToolUse, SubagentStop, Stop, PreCompact |
| Config | settings.json |
opencode.json(c) |
kilo.json(c) |
TOML | Instructions | Config | Config | Config | .clinerules |
Config | Config | Config |
Cursor artifact surfaces: gsd install --cursor writes two artifact kinds:
~/.cursor/skills/gsd-<name>/SKILL.md— rich skills with YAML frontmatter, Cursor tool-name mapping, and adapter context header (existing surface)~/.cursor/commands/gsd-<name>.md— plain markdown slash commands (no frontmatter) invocable via/in the Agent input (Cursor 1.6+)
Native skills emission (1.4.0): Three runtimes now emit GSD as on-demand native skills (skills/<name>/SKILL.md) at install time, in addition to their existing command and agent surfaces. Skills respect the active install profile and are removed on uninstall.
- Cline (global installs, Cline >= v3.48.0) — emits skills alongside the existing
.clinerules/directory - Kilo — emits skills alongside
command/andagents/ - OpenCode — emits skills alongside its existing surfaces
New slash-command surfaces (1.4.0):
- CodeBuddy —
/gsd-*slash commands written to~/.codebuddy/commands/ - Augment —
commands/gsd-<name>.mdwritten to~/.augment/commands/ - Cursor (Cursor >= 1.6) —
.cursor/commands/gsd-<name>.mdso GSD appears in the/command menu
Cross-runtime lifecycle hooks (1.4.0): Each supported runtime registers lifecycle hook events for per-turn context-headroom tracking and workflow state management. Notable registrations:
- Claude Code:
SubagentStop,Stop,PreCompact(context-headroom warnings),FileChanged(hot-reloads.planning/config.jsonmid-session) - Qwen Code:
SubagentStop,Stop,PreCompact - Codex:
SubagentStart,Stop,PostToolUse(new in 1.4.0); on Windows theSessionStarthook entry gains acommandWindowsfield so the.cmdshim is used for native execution - Cline:
PreToolUse - Cursor:
sessionStart(injects workflow state),postToolUse(nudges.planningupdates) - Copilot:
sessionStart
Runtime-specific enrichments (1.4.0):
- Codex emits
service_tier: flexfor light-tier agents; GSD skills appear in the Codex/skillspicker viaSKILL.md(noagents/openai.yamlsidecar is emitted — doing so caused duplicate autocomplete entries, #1326)
Native packaging:
- Claude Code: GSD Core ships a
.claude-plugin/plugin.jsonmanifest, enabling installation and lifecycle management viaclaude plugin install|enable|disable|update gsd-core. Commands load under the/gsd-core:namespace (e.g./gsd-core:plan-phase), avoiding slash-command collisions with the classic npm installer which uses/gsd:. Always-on guard and update hooks are wired automatically viahooks/hooks.json. The plugin path is additive — the npm installer (npx @opengsd/gsd-core) remains fully supported.