docs: add typed contribution templates and tighten contributor guidelines (#1673)

Overhaul CONTRIBUTING.md and all GitHub issue/PR templates to enforce a
structured, approval-gated contribution process that cuts down on drive-by
feature submissions.

Changes:
- CONTRIBUTING.md: add Types of Contributions section defining Fix,
  Enhancement, and Feature with escalating requirements and explicit
  rejection criteria; add Issue-First Rule section making clear that
  enhancements require approved-enhancement and features require
  approved-feature label before any code is written; backport gsd-2
  testing standards (t.after() per-test cleanup, array join() fixture
  pattern, Node 24 as primary CI target, test requirements by change type,
  reviewer standards)

- .github/ISSUE_TEMPLATE/enhancement.yml: new template requiring current
  vs. proposed behavior, reason/benefit narrative, full scope of changes,
  and breaking changes assessment; cannot be clicked through

- .github/ISSUE_TEMPLATE/feature_request.yml: full rewrite requiring solo-
  developer problem statement, what is being added, full file-level scope,
  user stories, acceptance criteria, maintenance burden assessment, and
  alternatives considered; incomplete specs are closed, not revised

- .github/pull_request_template.md: converted from general template to a
  routing page directing contributors to the correct typed template;
  using the default template for a feature or enhancement is a rejection
  reason

- .github/PULL_REQUEST_TEMPLATE/fix.md: new typed template requiring
  confirmed-bug label on linked issue and regression test confirmation

- .github/PULL_REQUEST_TEMPLATE/enhancement.md: new typed template with
  hard gate on approved-enhancement label and scope confirmation section

- .github/PULL_REQUEST_TEMPLATE/feature.md: new typed template requiring
  file inventory, spec compliance checklist from the issue, and scope
  confirmation that nothing beyond the approved spec was added

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-04 14:03:56 -04:00
committed by GitHub
parent 085f5b9c5b
commit e66f7e889e
7 changed files with 795 additions and 78 deletions

160
.github/ISSUE_TEMPLATE/enhancement.yml vendored Normal file
View File

@@ -0,0 +1,160 @@
---
name: Enhancement Proposal
description: Propose an improvement to an existing feature. Read the full instructions before opening this issue.
labels: ["enhancement", "needs-review"]
body:
- type: markdown
attributes:
value: |
## ⚠️ Read this before you fill anything out
An enhancement improves something that already exists — better output, expanded edge-case handling, improved performance, cleaner UX. It does **not** add new commands, new workflows, or new concepts. If you are proposing something new, use the [Feature Request](./feature_request.yml) template instead.
**Before opening this issue:**
- Confirm the thing you want to improve actually exists and works today.
- Read [CONTRIBUTING.md](../../CONTRIBUTING.md#-enhancement) — understand what `approved-enhancement` means and why you must wait for it before writing any code.
**What happens after you submit:**
A maintainer will review this proposal. If it is incomplete or out of scope, it will be **closed**. If approved, it will be labeled `approved-enhancement` and you may begin coding.
**Do not open a PR until this issue is labeled `approved-enhancement`.**
- type: checkboxes
id: preflight
attributes:
label: Pre-submission checklist
description: You must check every box. Unchecked boxes are an immediate close.
options:
- label: I have confirmed this improves existing behavior — it does not add a new command, workflow, or concept
required: true
- label: I have searched existing issues and this enhancement has not already been proposed
required: true
- label: I have read CONTRIBUTING.md and understand I must wait for `approved-enhancement` before writing any code
required: true
- label: I can clearly describe the concrete benefit — not just "it would be nicer"
required: true
- type: input
id: what_is_being_improved
attributes:
label: What existing feature or behavior does this improve?
description: Name the specific command, workflow, output, or behavior you are enhancing.
placeholder: "e.g., `/gsd:plan` output, phase status display in statusline, context summary format"
validations:
required: true
- type: textarea
id: current_behavior
attributes:
label: Current behavior
description: |
Describe exactly how the thing works today. Be specific. Include example output or commands if helpful.
placeholder: |
Currently, `/gsd:status` shows:
```
Phase 2/5 — In Progress
```
It does not show the phase name, making it hard to know what phase you are actually in without
opening STATE.md.
validations:
required: true
- type: textarea
id: proposed_behavior
attributes:
label: Proposed behavior
description: |
Describe exactly how it should work after the enhancement. Be specific. Include example output or commands.
placeholder: |
After the enhancement, `/gsd:status` would show:
```
Phase 2/5 — In Progress — "Implement core auth module"
```
The phase name is pulled from STATE.md and appended to the existing output.
validations:
required: true
- type: textarea
id: reason_and_benefit
attributes:
label: Reason and benefit
description: |
Answer both of these clearly:
1. **Why is the current behavior a problem?** (Not just inconvenient — what goes wrong, what is harder than it should be, or what is confusing?)
2. **What is the concrete benefit of the proposed behavior?** (What becomes easier, faster, less error-prone, or clearer?)
Vague answers like "it would be better" or "it's more user-friendly" are not sufficient.
placeholder: |
**Why the current behavior is a problem:**
When working in a long session, the AI agent frequently loses track of which phase is active
and must re-read STATE.md. The numeric-only status gives no semantic context.
**Concrete benefit:**
Showing the phase name means the agent can confirm the active phase from the status output
alone, without an extra file read. This reduces context consumption in long sessions.
validations:
required: true
- type: textarea
id: scope
attributes:
label: Scope of changes
description: |
List the files and systems this enhancement would touch. Be complete.
An enhancement should have a narrow, well-defined scope. If your list is long, this might be a feature, not an enhancement.
placeholder: |
Files modified:
- `get-shit-done/commands/gsd/status.md` — update output format description
- `get-shit-done/bin/lib/state.cjs` — expose phase name in status() return value
- `tests/status.test.cjs` — update snapshot and add test for phase name in output
- `CHANGELOG.md` — user-facing change entry
No new files created. No new dependencies.
validations:
required: true
- type: textarea
id: breaking_changes
attributes:
label: Breaking changes
description: |
Does this change existing command output, file formats, or behavior that users or AI agents might depend on?
If yes, describe exactly what changes and how it stays backward compatible (or why it cannot).
Write "None" only if you are certain.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: |
What other ways could this be improved? Why is your proposed approach the right one?
If you haven't considered alternatives, take a moment before submitting.
validations:
required: true
- type: dropdown
id: area
attributes:
label: Area affected
options:
- Core workflow (init, plan, build, verify)
- Planning system (phases, roadmap, state)
- Context management (context engineering, summaries)
- Runtime integration (hooks, statusline, settings)
- Installation / setup
- Output / formatting
- Documentation
- Other
validations:
required: true
- type: textarea
id: additional_context
attributes:
label: Additional context
description: Screenshots, related issues, or anything else that helps explain the proposal.
validations:
required: false

View File

@@ -1,44 +1,165 @@
---
name: Feature Request
description: Suggest a new feature or improvement
labels: ["enhancement"]
description: Propose a new feature. Read the full instructions before opening this issue.
labels: ["feature-request", "needs-review"]
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a feature! Please describe what you'd like to see.
## ⚠️ Read this before you fill anything out
- type: textarea
id: problem
A feature adds something new to GSD — a new command, workflow, concept, or integration. Features have the **highest bar** for acceptance because every feature adds permanent maintenance burden to a project built for solo developers.
**Before opening this issue:**
- Check [Discussions](https://github.com/gsd-build/get-shit-done/discussions) — has this been proposed and declined before?
- Read [CONTRIBUTING.md](../../CONTRIBUTING.md#-feature) — understand what "approved-feature" means and why you must wait for it before writing code.
- Ask yourself: *does this solve a real problem for a solo developer working with an AI coding tool, or is it a feature I personally want?*
**What happens after you submit:**
A maintainer will review this spec. If it is incomplete, it will be **closed**, not revised. If it conflicts with GSD's design philosophy, it will be declined. If it is approved, it will be labeled `approved-feature` and you may begin coding.
**Do not open a PR until this issue is labeled `approved-feature`.**
- type: checkboxes
id: preflight
attributes:
label: Problem or motivation
description: What problem does this solve? Why do you want this?
placeholder: "I'm frustrated when..."
label: Pre-submission checklist
description: You must check every box. Unchecked boxes are an immediate close.
options:
- label: I have searched existing issues and discussions — this has not been proposed and declined before
required: true
- label: I have read CONTRIBUTING.md and understand that I must wait for `approved-feature` before writing any code
required: true
- label: I have read the existing GSD commands and workflows and confirmed this feature does not duplicate existing behavior
required: true
- label: This feature solves a problem for solo developers using AI coding tools, not a personal preference or workflow I happen to like
required: true
- type: input
id: feature_name
attributes:
label: Feature name
description: A short, concrete name for this feature (not a sales pitch — just what it is).
placeholder: "e.g., Phase rollback command, Auto-archive completed phases, Cross-project state sync"
validations:
required: true
- type: dropdown
id: feature_type
attributes:
label: Type of addition
description: What kind of thing is this feature adding?
options:
- New command (slash command or CLI flag)
- New workflow (multi-step process)
- New runtime integration
- New planning concept (phase type, state, etc.)
- New installation/setup behavior
- New output or reporting format
- Other (describe in spec)
validations:
required: true
- type: textarea
id: solution
id: problem_statement
attributes:
label: Proposed solution
description: How do you think this should work? Include example commands or workflows if possible.
label: The solo developer problem
description: |
Describe the concrete problem this solves for a solo developer using an AI coding tool. Be specific.
Good: "When a phase fails mid-way, there is no way to roll back state without manually editing STATE.md. This causes the AI agent to continue from a corrupted state, producing wrong plans."
Bad: "It would be nice to have a rollback feature." / "Other tools have this." / "I need this for my workflow."
placeholder: |
A new command `/gsd:example` that...
When [specific situation], the developer cannot [specific thing], which causes [specific negative outcome].
validations:
required: true
- type: textarea
id: what_is_added
attributes:
label: What this feature adds
description: |
Describe exactly what is being added. Be specific about commands, output, behavior, and user interaction.
Include example commands or example output where possible.
placeholder: |
A new command `/gsd:rollback` that:
1. Reads the current phase from STATE.md
2. Reverts STATE.md to the previous phase's snapshot
3. Outputs a confirmation with the rolled-back state
Example usage:
```
/gsd:rollback
> Rolled back from Phase 3 (failed) to Phase 2 (completed)
```
validations:
required: true
- type: textarea
id: full_scope
attributes:
label: Full scope of changes
description: |
List every file, system, and area of the codebase this feature would touch. Be exhaustive.
If you cannot fill this out, you do not understand the codebase well enough to propose this feature yet.
placeholder: |
Files that would be created:
- `get-shit-done/commands/gsd/rollback.md` — new slash command definition
Files that would be modified:
- `get-shit-done/bin/lib/state.cjs` — add rollback() function
- `get-shit-done/bin/lib/phases.cjs` — expose phase snapshot API
- `tests/rollback.test.cjs` — new test file
- `docs/COMMANDS.md` — document new command
- `CHANGELOG.md` — entry for this feature
Systems affected:
- STATE.md schema (must remain backward compatible)
- Phase lifecycle state machine
validations:
required: true
- type: textarea
id: user_stories
attributes:
label: User stories
description: Write at least two user stories in the format "As a [user], I want [thing] so that [outcome]."
placeholder: |
1. As a solo developer, I want to roll back a failed phase so that I can re-attempt it without corrupting my project state.
2. As a solo developer, I want rollback to be undoable so that I don't accidentally lose completed work.
validations:
required: true
- type: textarea
id: acceptance_criteria
attributes:
label: Acceptance criteria
description: |
List the specific, testable conditions that must be true for this feature to be considered complete.
These become the basis for reviewer sign-off. Vague criteria ("it works") are not acceptable.
placeholder: |
- [ ] `/gsd:rollback` reverts STATE.md to the previous phase when current phase status is `failed`
- [ ] `/gsd:rollback` exits with an error if there is no previous phase to roll back to
- [ ] `/gsd:rollback` outputs the before/after phase names in its confirmation message
- [ ] Rollback is logged in the phase history so the AI agent can see it happened
- [ ] All existing tests still pass
- [ ] New tests cover the happy path, no-previous-phase case, and STATE.md corruption case
validations:
required: true
- type: dropdown
id: scope
attributes:
label: Which area does this affect?
label: Which area does this primarily affect?
options:
- Core workflow (init, plan, build, verify)
- Planning system (phases, roadmap, state)
- Context management (context engineering, summaries)
- Runtime integration (hooks, statusline, settings)
- Installation / setup
- Documentation
- Other
- Documentation only
- Multiple areas (describe in scope section above)
validations:
required: true
@@ -46,7 +167,7 @@ body:
id: runtimes
attributes:
label: Applicable runtimes
description: Which runtimes should this work with?
description: Which runtimes must this work with? Check all that apply.
options:
- label: Claude Code
- label: Gemini CLI
@@ -58,18 +179,72 @@ body:
- label: Windsurf
- label: All runtimes
- type: textarea
id: breaking_changes
attributes:
label: Breaking changes assessment
description: |
Does this feature change existing behavior, command output, file formats, or APIs?
If yes, describe exactly what breaks and how existing users would migrate.
Write "None" only if you are certain.
placeholder: |
None — this adds a new command and does not modify any existing command behavior or file schemas.
OR:
STATE.md will gain a new `phase_history` array field. Existing STATE.md files without this field
will be treated as having an empty history (backward compatible). The rollback command will
decline gracefully if history is empty.
validations:
required: true
- type: textarea
id: maintenance_burden
attributes:
label: Maintenance burden
description: |
Every feature is code that must be maintained forever. Describe the ongoing cost:
- How does this interact with future changes to phases, state, or commands?
- Does this add external dependencies?
- Does this require documentation updates across multiple files?
- Will this create edge cases or interactions with other features?
placeholder: |
- No new dependencies
- The rollback function must be updated if the STATE.md schema ever changes
- Will need to be tested on each new Node.js LTS release
- The command definition must be kept in sync with any future command format changes
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: Have you considered other approaches?
description: |
What other approaches did you consider? Why did you reject them?
If the answer is "I didn't consider any alternatives", this issue will be closed.
placeholder: |
1. Manual STATE.md editing — rejected because it requires the developer to understand the schema
and is error-prone. The AI agent cannot reliably guide this.
2. A `/gsd:reset` command that wipes all state — rejected because it is too destructive and
loses all completed phase history.
validations:
required: true
- type: textarea
id: prior_art
attributes:
label: Prior art and references
description: |
Does any other tool, project, or GSD discussion address this? Link to anything relevant.
If you are aware of a prior declined proposal for this feature, explain why this proposal is different.
validations:
required: false
- type: textarea
id: context
id: additional_context
attributes:
label: Additional context
description: Any other information, screenshots, or examples.
description: Anything else — screenshots, recordings, related issues, or links.
validations:
required: false

View File

@@ -0,0 +1,86 @@
## Enhancement PR
> **Using the wrong template?**
> — Bug fix: use [fix.md](?template=fix.md)
> — New feature: use [feature.md](?template=feature.md)
---
## Linked Issue
> **Required.** This PR will be auto-closed if no valid issue link is found.
> The linked issue **must** have the `approved-enhancement` label. If it does not, this PR will be closed without review.
Closes #
> ⛔ **No `approved-enhancement` label on the issue = immediate close.**
> Do not open this PR if a maintainer has not yet approved the enhancement proposal.
---
## What this enhancement improves
<!-- Name the specific command, workflow, or behavior being improved. -->
## Before / After
**Before:**
<!-- Describe or show the current behavior. Include example output if applicable. -->
**After:**
<!-- Describe or show the behavior after this enhancement. Include example output if applicable. -->
## How it was implemented
<!-- Brief description of the approach. Point to the key files changed. -->
## Testing
### How I verified the enhancement works
<!-- Manual steps or automated tests. -->
### Platforms tested
- [ ] macOS
- [ ] Windows (including backslash path handling)
- [ ] Linux
- [ ] N/A (not platform-specific)
### Runtimes tested
- [ ] Claude Code
- [ ] Gemini CLI
- [ ] OpenCode
- [ ] Other: ___
- [ ] N/A (not runtime-specific)
---
## Scope confirmation
<!-- Confirm the implementation matches the approved proposal. -->
- [ ] The implementation matches the scope approved in the linked issue — no additions or removals
- [ ] If scope changed during implementation, I updated the issue and got re-approval before continuing
---
## Checklist
- [ ] Issue linked above with `Closes #NNN`**PR will be auto-closed if missing**
- [ ] Linked issue has the `approved-enhancement` label — **PR will be closed if missing**
- [ ] Changes are scoped to the approved enhancement — nothing extra included
- [ ] All existing tests pass (`npm test`)
- [ ] New or updated tests cover the enhanced behavior
- [ ] CHANGELOG.md updated
- [ ] Documentation updated if behavior or output changed
- [ ] No unnecessary dependencies added
## Breaking changes
<!-- Does this enhancement change any existing behavior, output format, or API?
If yes, describe exactly what changes and confirm backward compatibility.
Write "None" if not applicable. -->
None

113
.github/PULL_REQUEST_TEMPLATE/feature.md vendored Normal file
View File

@@ -0,0 +1,113 @@
## Feature PR
> **Using the wrong template?**
> — Bug fix: use [fix.md](?template=fix.md)
> — Enhancement to existing behavior: use [enhancement.md](?template=enhancement.md)
---
## Linked Issue
> **Required.** This PR will be auto-closed if no valid issue link is found.
> The linked issue **must** have the `approved-feature` label. If it does not, this PR will be closed without review — no exceptions.
Closes #
> ⛔ **No `approved-feature` label on the issue = immediate close.**
> Do not open this PR if a maintainer has not yet approved the feature spec.
> Do not open this PR if you wrote code before the issue was approved.
---
## Feature summary
<!-- One paragraph. What does this feature add? Assume the reviewer has read the issue spec. -->
## What changed
### New files
<!-- List every new file added and its purpose. -->
| File | Purpose |
|------|---------|
| | |
### Modified files
<!-- List every existing file modified and what changed in it. -->
| File | What changed |
|------|-------------|
| | |
## Implementation notes
<!-- Describe any decisions made during implementation that were not specified in the issue.
If any part of the implementation differs from the approved spec, explain why. -->
## Spec compliance
<!-- For each acceptance criterion in the linked issue, confirm it is met. Copy them here and check them off. -->
- [ ] <!-- Acceptance criterion 1 from issue -->
- [ ] <!-- Acceptance criterion 2 from issue -->
- [ ] <!-- Add all criteria from the issue -->
## Testing
### Test coverage
<!-- Describe what is tested and where. New features require new tests — no exceptions. -->
### Platforms tested
- [ ] macOS
- [ ] Windows (including backslash path handling)
- [ ] Linux
### Runtimes tested
- [ ] Claude Code
- [ ] Gemini CLI
- [ ] OpenCode
- [ ] Codex
- [ ] Copilot
- [ ] Other: ___
- [ ] N/A — specify which runtimes are supported and why others are excluded
---
## Scope confirmation
- [ ] The implementation matches the scope approved in the linked issue exactly
- [ ] No additional features, commands, or behaviors were added beyond what was approved
- [ ] If scope changed during implementation, I updated the issue spec and received re-approval
---
## Checklist
- [ ] Issue linked above with `Closes #NNN`**PR will be auto-closed if missing**
- [ ] Linked issue has the `approved-feature` label — **PR will be closed if missing**
- [ ] All acceptance criteria from the issue are met (listed above)
- [ ] Implementation scope matches the approved spec exactly
- [ ] All existing tests pass (`npm test`)
- [ ] New tests cover the happy path, error cases, and edge cases
- [ ] CHANGELOG.md updated with a user-facing description of the feature
- [ ] Documentation updated — commands, workflows, references, README if applicable
- [ ] No unnecessary external dependencies added
- [ ] Works on Windows (backslash paths handled)
## Breaking changes
<!-- Describe any behavior, output format, file schema, or API changes that affect existing users.
For each breaking change, describe the migration path.
Write "None" only if you are certain. -->
None
## Screenshots / recordings
<!-- If this feature has any visual output or changes the user experience, include before/after screenshots
or a short recording. Delete this section if not applicable. -->

74
.github/PULL_REQUEST_TEMPLATE/fix.md vendored Normal file
View File

@@ -0,0 +1,74 @@
## Fix PR
> **Using the wrong template?**
> — Enhancement: use [enhancement.md](?template=enhancement.md)
> — Feature: use [feature.md](?template=feature.md)
---
## Linked Issue
> **Required.** This PR will be auto-closed if no valid issue link is found.
Fixes #
> The linked issue must have the `confirmed-bug` label. If it doesn't, ask a maintainer to confirm the bug before continuing.
---
## What was broken
<!-- One or two sentences. What was the incorrect behavior? -->
## What this fix does
<!-- One or two sentences. How does this fix the broken behavior? -->
## Root cause
<!-- Brief explanation of why the bug existed. Skip for trivial typo/doc fixes. -->
## Testing
### How I verified the fix
<!-- Describe manual steps or point to the automated test that proves this is fixed. -->
### Regression test added?
- [ ] Yes — added a test that would have caught this bug
- [ ] No — explain why: <!-- e.g., environment-specific, non-deterministic -->
### Platforms tested
- [ ] macOS
- [ ] Windows (including backslash path handling)
- [ ] Linux
- [ ] N/A (not platform-specific)
### Runtimes tested
- [ ] Claude Code
- [ ] Gemini CLI
- [ ] OpenCode
- [ ] Other: ___
- [ ] N/A (not runtime-specific)
---
## Checklist
- [ ] Issue linked above with `Fixes #NNN`**PR will be auto-closed if missing**
- [ ] Linked issue has the `confirmed-bug` label
- [ ] Fix is scoped to the reported bug — no unrelated changes included
- [ ] Regression test added (or explained why not)
- [ ] All existing tests pass (`npm test`)
- [ ] CHANGELOG.md updated if this is a user-facing fix
- [ ] No unnecessary dependencies added
## Breaking changes
<!-- Does this fix change any existing behavior, output format, or API that users might depend on?
If yes, describe. Write "None" if not applicable. -->
None

View File

@@ -1,59 +1,38 @@
## Linked Issue
## ⚠️ Wrong template — please use the correct one for your PR type
> **Required.** PRs without a linked issue are closed without review.
> Open an issue first if one doesn't exist: https://github.com/gsd-build/get-shit-done/issues/new/choose
Every PR must use a typed template. Using this default template is a reason for rejection.
Closes #
Select the template that matches your PR:
## What
| PR Type | When to use | Template link |
|---------|-------------|---------------|
| **Fix** | Correcting a bug, crash, or behavior that doesn't match documentation | [Use fix template](?template=PULL_REQUEST_TEMPLATE/fix.md) |
| **Enhancement** | Improving an existing feature — better output, expanded edge cases, performance | [Use enhancement template](?template=PULL_REQUEST_TEMPLATE/enhancement.md) |
| **Feature** | Adding something new — new command, workflow, concept, or integration | [Use feature template](?template=PULL_REQUEST_TEMPLATE/feature.md) |
<!-- One sentence: what does this PR do? -->
---
## Why
### Not sure which type applies?
<!-- One sentence: why is this change needed? -->
- If it **corrects broken behavior** → Fix
- If it **improves existing behavior** without adding new commands or concepts → Enhancement
- If it **adds something that doesn't exist today** → Feature
- If you are not sure → open a [Discussion](https://github.com/gsd-build/get-shit-done/discussions) first
## How
---
<!-- Brief description of the approach taken. Skip for trivial changes. -->
### Reminder: Issues must be approved before PRs
## Testing
For **enhancements**: the linked issue must have the `approved-enhancement` label before you open this PR.
### Platforms tested
For **features**: the linked issue must have the `approved-feature` label before you open this PR.
- [ ] macOS
- [ ] Windows (including backslash path handling)
- [ ] Linux
PRs that arrive without a labeled, approved issue are closed without review.
### Runtimes tested
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full process.
- [ ] Claude Code
- [ ] Gemini CLI
- [ ] OpenCode
- [ ] Codex
- [ ] Copilot
- [ ] N/A (not runtime-specific)
---
### Test details
<!-- How did you verify this works? Manual steps, automated tests, etc. -->
## Checklist
- [ ] Issue linked above (`Closes #NNN`) — **PR will be auto-closed if missing**
- [ ] Follows GSD style (no enterprise patterns, no filler)
- [ ] Updates CHANGELOG.md for user-facing changes
- [ ] No unnecessary dependencies added
- [ ] Works on Windows (backslash paths tested)
- [ ] Templates/references updated if behavior changed
- [ ] Existing tests pass (`npm test`)
## Breaking Changes
<!-- List any breaking changes, or write "None" -->
None
## Screenshots / recordings
<!-- If this is a visual change, add before/after screenshots. Delete this section if not applicable. -->
<!-- If you believe your PR genuinely does not fit any of the above categories (e.g., CI/tooling changes,
dependency updates, or doc-only fixes with no linked issue), delete this file and describe your PR below.
Add a note explaining why none of the typed templates apply. -->