Skip to content

feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts#2133

Open
Copilot wants to merge 16 commits intomainfrom
copilot/add-composition-strategies-to-presets
Open

feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts#2133
Copilot wants to merge 16 commits intomainfrom
copilot/add-composition-strategies-to-presets

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 8, 2026

Presets can now augment lower-priority templates instead of only fully replacing them. A new optional strategy field in preset.yml controls how content is composed across the priority stack.

provides:
  templates:
    - type: "template"
      name: "spec-template"
      file: "templates/spec-addendum.md"
      strategy: "append"  # new field; default: "replace"
Strategy Behavior Templates Commands Scripts
replace Full replacement (existing default)
prepend Insert before lower-priority content
append Insert after lower-priority content
wrap {CORE_TEMPLATE} / $CORE_SCRIPT placeholder substitution

Multiple composing presets chain recursively (e.g. security prepend + compliance append → header + core + footer).

Python resolver (src/specify_cli/presets.py)

  • VALID_PRESET_STRATEGIES / VALID_SCRIPT_STRATEGIES constants; validation in _validate() rejects prepend/append for scripts
  • PresetResolver._collect_all_layers() — walks full priority stack, reads strategy from each preset manifest
  • PresetResolver.resolve_content() — bottom-up composition across layers
  • PresetManager._register_commands() — composes command content before writing to agent directories

Shell resolvers

  • resolve_template_content() in scripts/bash/common.sh
  • Resolve-TemplateContent in scripts/powershell/common.ps1

CLI

  • specify preset resolve shows composition chain when non-replace strategies are present

Documentation

  • presets/scaffold/preset.yml — strategy field docs and composition examples
  • presets/README.md — composition strategies section; moved implemented items out of future considerations
  • presets/ARCHITECTURE.md — strategy table and content resolution function references

Tests

  • 26 new tests: strategy validation (valid/invalid/script restrictions), resolve_content() for each strategy × type, multi-preset chaining, override precedence, separator behavior, _collect_all_layers() ordering

Copilot AI requested review from Copilot and removed request for Copilot April 8, 2026 20:55
Copilot AI requested review from Copilot and removed request for Copilot April 8, 2026 21:05
Comment thread src/specify_cli/presets.py Fixed
Copilot AI requested review from Copilot and removed request for Copilot April 8, 2026 21:08
Copilot AI changed the title [WIP] Add composition strategies for templates, commands, and scripts feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts Apr 8, 2026
Copilot AI requested a review from mnriem April 8, 2026 21:09
Copilot AI review requested due to automatic review settings April 20, 2026 18:51
Copilot AI and others added 3 commits April 20, 2026 13:52
… templates, commands, and scripts

- Add strategy field validation in PresetManifest._validate()
- Add VALID_PRESET_STRATEGIES and VALID_SCRIPT_STRATEGIES constants
- Add PresetResolver.resolve_content() for composed content resolution
- Add PresetResolver._collect_all_layers() for full priority stack
- Update _register_commands() to compose before writing
- Update CLI preset resolve command to show composition chain
- Add resolve_template_content() to bash common.sh
- Add Resolve-TemplateContent to PowerShell common.ps1
- Update scaffold preset.yml with strategy documentation
- Update presets/README.md and ARCHITECTURE.md
- Add 26 unit tests covering validation, composition, and chaining

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/c285c51b-f00b-480a-9eb2-ae70e3cbcb72

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
…, improve default strategy test

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/c285c51b-f00b-480a-9eb2-ae70e3cbcb72

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Address code-quality review: explain why PresetValidationError is
intentionally caught and ignored (falls back to default 'replace'
strategy so layer resolution continues).
@mnriem mnriem force-pushed the copilot/add-composition-strategies-to-presets branch from 00edba1 to fa04828 Compare April 20, 2026 18:53
@mnriem mnriem review requested due to automatic review settings April 20, 2026 18:54
@mnriem mnriem marked this pull request as ready for review April 20, 2026 19:02
Copilot AI review requested due to automatic review settings April 20, 2026 19:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds composition strategies to the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of always fully replacing them.

Changes:

  • Introduces strategy validation in preset manifests and a new Python composition resolver (_collect_all_layers() + resolve_content()).
  • Updates command registration to attempt composing command content before writing into agent directories.
  • Adds shell (bash/PowerShell) “resolve composed content” helpers plus docs and extensive new tests for strategy behavior.
Show a summary per file
File Description
tests/test_presets.py Adds strategy validation + composition resolver unit tests (including multi-preset chaining).
src/specify_cli/presets.py Adds strategy constants/validation, command composition during registration, and composition-aware resolution APIs.
src/specify_cli/init.py Enhances specify preset resolve output to show the composition chain when applicable.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent to compose template layers using strategies.
scripts/bash/common.sh Adds resolve_template_content to compose template layers using strategies.
presets/scaffold/preset.yml Documents the new strategy field and shows composition examples.
presets/README.md Documents strategy semantics, supported combinations, and chaining behavior.
presets/ARCHITECTURE.md Documents strategy table and where composition resolution is implemented across runtimes.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 8

Comment thread src/specify_cli/presets.py Outdated
Comment thread src/specify_cli/presets.py
Comment thread src/specify_cli/presets.py Outdated
Comment thread scripts/bash/common.sh
Comment thread scripts/bash/common.sh Outdated
Comment thread scripts/powershell/common.ps1 Outdated
Comment thread presets/scaffold/preset.yml
Comment thread presets/README.md
- Fix bash newline handling: use printf instead of literal \n\n
  in prepend/append string concatenation (common.sh)
- Fix PowerShell wrap: use .Replace() instead of -replace to avoid
  $ capture-group interpolation in replacement strings (common.ps1)
- Fix layer collection to use manifest file path when available,
  falling back to convention-based path (presets.py, common.sh, common.ps1)
- Fix install ordering: pre-register preset before command/skill
  registration so resolve_content() sees it in the priority stack
- Fix skills divergence: use composed content from .composed/ dir
  when available instead of original command file for skill generation
- Add fallback directory scan in bash resolve_template_content when
  python3/registry is unavailable, matching resolve_template() behavior
- Clarify doc examples: note that file field can differ from convention
  path (scaffold/preset.yml, presets/README.md)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds composition strategies to the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of always fully replacing them.

Changes:

  • Introduces strategy validation in preset manifests and adds Python composition resolution across the full priority stack.
  • Updates command registration to write composed command content before registering with agent directories; adds CLI output to display a composition chain.
  • Adds bash/PowerShell template-content composition helpers, documentation updates, and a large set of new tests.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, layer collection, composed content resolver, and command registration changes to use composed content.
src/specify_cli/__init__.py Enhances specify preset resolve output to display a composition chain.
scripts/bash/common.sh Adds resolve_template_content() to compose template content in bash using the same strategy concepts.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent to compose template content in PowerShell.
presets/scaffold/preset.yml Documents the new strategy field and provides composition examples.
presets/README.md Documents composition strategies and supported combinations; updates future-considerations list.
presets/ARCHITECTURE.md Adds strategy table and references to the new composition resolution functions.
tests/test_presets.py Adds extensive coverage for strategy validation, composition behavior, chaining, and layer collection ordering.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 3

Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/presets.py
Comment thread src/specify_cli/presets.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds composition strategies to preset-provided templates/commands/scripts so higher-priority presets can augment (prepend/append/wrap) lower-priority content rather than only replacing it, and updates CLI/docs/tests accordingly.

Changes:

  • Introduces strategy validation and implements multi-layer composition via PresetResolver._collect_all_layers() + resolve_content().
  • Updates command registration to optionally register composed command content and adds post-removal reconciliation.
  • Adds Bash/PowerShell composed-template resolvers plus docs and extensive pytest coverage for composition logic.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, layer collection + composition resolver, composed-command registration, and removal reconciliation logic.
tests/test_presets.py Adds tests for strategy validation, resolve_content() behavior, multi-preset chaining, and layer ordering.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chains when applicable.
scripts/bash/common.sh Adds resolve_template_content() to compose template content across layers in bash.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent to compose template content across layers in PowerShell.
presets/scaffold/preset.yml Documents strategy usage and provides composition examples in the scaffold.
presets/README.md Documents composition strategies, supported combinations, and examples.
presets/ARCHITECTURE.md Documents strategy semantics and references the new resolution functions across implementations.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

scripts/bash/common.sh:554

  • resolve_template_content’s wrap strategy does not validate that {CORE_TEMPLATE} is present. If a wrapper file omits the placeholder, the function will return the wrapper unchanged and silently drop the lower-priority content. This diverges from the Python resolver (which raises on missing placeholder) and can produce incorrect output without an error; add an explicit placeholder check and fail with a non-zero exit code when it’s missing.
            case "$strat" in
                replace) content="$layer_content" ;;
                prepend) content="$(printf '%s\n\n%s' "$layer_content" "$content")" ;;
                append)  content="$(printf '%s\n\n%s' "$content" "$layer_content")" ;;
                wrap)    content="${layer_content//\{CORE_TEMPLATE\}/$content}" ;;
            esac

scripts/powershell/common.ps1:520

  • Resolve-TemplateContent’s wrap strategy uses .Replace('{CORE_TEMPLATE}', $content) without checking that the placeholder exists. If the wrapper omits {CORE_TEMPLATE}, the lower-priority content is silently dropped and the wrapper is returned unchanged. Add an explicit placeholder presence check and fail fast (or at least warn) to match the Python resolver’s behavior.
            switch ($strat) {
                'replace' { $content = $layerContent }
                'prepend' { $content = "$layerContent`n`n$content" }
                'append'  { $content = "$content`n`n$layerContent" }
                'wrap'    { $content = $layerContent.Replace('{CORE_TEMPLATE}', $content) }
            }
  • Files reviewed: 8/8 changed files
  • Comments generated: 3

Comment thread src/specify_cli/presets.py
Comment thread scripts/bash/common.sh
Comment thread scripts/powershell/common.ps1
- Reconcile all commands from full priority stack after install so
  install order doesn't determine the winning command file
- Fix bash wrap substitution: use split-and-rejoin (%%/# parameter
  expansion) instead of //pattern/replacement to avoid & expansion
  corrupting content containing ampersands
- Support python/py/py-3 fallbacks in PowerShell Resolve-TemplateContent
  via Get-Python3Command helper, matching Windows environments where
  python3 may not be available
- Reconciliation skips skill-based agents to avoid overwriting properly
  formatted SKILL.md files written by _register_skills()
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds composition strategies to the preset system so higher-priority presets can augment (not only replace) lower-priority templates/commands/scripts, with consistent resolution across Python + shell helpers and expanded test coverage.

Changes:

  • Introduces strategy (replace/prepend/append/wrap) validation in preset manifests and implements bottom-up composition via PresetResolver.resolve_content().
  • Updates command registration to write composed command content before registering, plus reconciliation on install/remove to keep agent command files aligned with the current priority stack.
  • Adds Bash/PowerShell “resolve composed template content” helpers and documents the new behaviors in preset docs/scaffold.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, collects layered sources, composes content, and reconciles command registrations across priority changes.
src/specify_cli/__init__.py Enhances specify preset resolve output to show top layer + composition chain when applicable.
scripts/bash/common.sh Adds resolve_template_content() to compose template content across layers in Bash.
scripts/powershell/common.ps1 Adds Python3 discovery and Resolve-TemplateContent for composed template content on PowerShell.
tests/test_presets.py Adds composition strategy validation + resolver behavior tests, including chaining and override precedence.
presets/scaffold/preset.yml Documents strategy and provides composition examples in the scaffold preset manifest.
presets/README.md Documents composition strategies and updates “Future Considerations.”
presets/ARCHITECTURE.md Documents strategy matrix and points to the resolution implementations.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 5

Comment thread scripts/bash/common.sh
Comment thread scripts/powershell/common.ps1
Comment thread scripts/powershell/common.ps1 Outdated
Comment thread src/specify_cli/presets.py
Comment thread src/specify_cli/presets.py
- Validate {CORE_TEMPLATE} placeholder in bash wrap strategy: fail
  with clear error if placeholder is missing in wrapper content
- Validate {CORE_TEMPLATE} placeholder in PowerShell wrap strategy:
  throw if placeholder is missing, matching Python resolver behavior
- Fix PowerShell pyCmd arg slicing: build extra-args array based on
  actual Count to avoid out-of-range $null arguments
- Narrow exception catch in _register_for_non_skill_agents(): catch
  only ValueError instead of broad Exception
- Add _reconcile_skills() post-removal: re-register SKILL.md files
  from the next winning preset so skills stay in sync with the
  effective command stack after removing a top-priority preset
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds composition strategies to the presets system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only fully replacing them.

Changes:

  • Introduces strategy validation in preset manifests and a new Python composition resolver (_collect_all_layers() + resolve_content()).
  • Updates command registration to register composed command content and reconciles command outputs after install/remove.
  • Adds shell (bash/PowerShell) template-content composition helpers plus documentation + tests for strategy behavior.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, layer collection + bottom-up composition, and command reconciliation/registration updates.
tests/test_presets.py Adds unit tests for strategy validation and composition behaviors across types and multi-preset chains.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chain details.
scripts/bash/common.sh Adds resolve_template_content() for composed template content in bash workflows.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent (and Python discovery) for composed template content in PowerShell workflows.
presets/scaffold/preset.yml Documents the new strategy field and provides examples.
presets/README.md Adds user-facing documentation for composition strategies and supported combinations.
presets/ARCHITECTURE.md Documents the strategy matrix and points to the new resolution implementations.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 3

Comment thread src/specify_cli/presets.py
Comment thread scripts/bash/common.sh
Comment thread scripts/powershell/common.ps1
- Strip frontmatter from command layers during composition: parse each
  layer into (frontmatter, body), compose bodies only, then reattach
  the highest-priority frontmatter to avoid leaking YAML metadata
- Filter disabled presets in bash resolve_template and
  resolve_template_content: skip presets with enabled=false
- Filter disabled presets in PowerShell Resolve-Template and
  Resolve-TemplateContent: add Where-Object enabled filter to match
  Python resolver behavior
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds composition strategies to the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, aligning Python + shell resolvers and improving CLI visibility into resolution chains.

Changes:

  • Introduces strategy validation in preset manifests and implements bottom-up layer composition in PresetResolver.resolve_content().
  • Updates command registration to write composed command content and adds reconciliation on install/remove to keep agent command files consistent with the current priority stack.
  • Adds bash/PowerShell content resolvers for composed templates, expands docs/scaffold guidance, and adds extensive test coverage for strategies and layering.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, layer collection, composed resolution, and command reconciliation/registration updates.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chains.
scripts/bash/common.sh Adds resolve_template_content() with strategy-aware composition for templates.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent and Python 3 discovery helper for strategy-aware template composition.
tests/test_presets.py Adds new test suites for strategy validation, content composition, chaining, and layer collection ordering.
presets/scaffold/preset.yml Documents the new strategy field and provides composition examples.
presets/README.md Documents composition strategies and supported combinations; updates future considerations.
presets/ARCHITECTURE.md Documents strategy semantics and points to resolver implementations.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

scripts/powershell/common.ps1:509

  • Resolve-TemplateContent composes whenever any layer has a non-replace strategy. As with the Python resolver, this can throw on a lower-priority wrap (missing {CORE_TEMPLATE}) even when a higher-priority replace layer should override and ignore lower layers. Consider short-circuiting when the highest-priority strategy is replace (return that file directly) and only composing when the top layer is non-replace.
    # Check if any layer uses a non-replace strategy
    $hasComposition = $false
    foreach ($s in $layerStrategies) {
        if ($s -ne 'replace') { $hasComposition = $true; break }
    }

    if (-not $hasComposition) {
        return (Get-Content $layerPaths[0] -Raw)
    }

src/specify_cli/presets.py:2326

  • resolve_content() treats any non-replace layer anywhere in the stack as requiring composition. This can raise wrap-placeholder validation errors (or do unnecessary composition) even when the highest-priority layer is strategy: replace and should completely override lower layers. Consider short-circuiting early when layers[0]['strategy'] == 'replace' (return that file verbatim) and only composing when the top layer is non-replace (or when a non-replace layer appears above the highest-priority replace that wins).
        # Check if any layer uses a non-replace strategy
        has_composition = any(layer["strategy"] != "replace" for layer in layers)

        if not has_composition:
            # Pure replacement — just read the highest-priority file
            return layers[0]["path"].read_text(encoding="utf-8")

  • Files reviewed: 8/8 changed files
  • Comments generated: 4

Comment thread scripts/powershell/common.ps1 Outdated
Comment thread tests/test_presets.py
Comment thread src/specify_cli/presets.py Outdated
Comment thread scripts/bash/common.sh
- Hoist Get-Python3Command call out of preset loop in PowerShell
  Resolve-TemplateContent to avoid repeated Get-Command/version checks
- Short-circuit composition when top layer is replace: in resolve_content,
  _reconcile_composed_commands, and bash resolve_template_content, return
  the top layer directly when its strategy is replace, ignoring irrelevant
  lower-priority composition layers
- Add test: replace-over-wrap verifies that a high-priority replace preset
  wins without evaluating a lower-priority wrap that lacks a placeholder
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds preset “composition strategies” so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, with consistent resolution across Python and shell helpers.

Changes:

  • Introduces strategy validation in preset manifests and implements full-stack layer collection + bottom-up composition in PresetResolver.resolve_content().
  • Updates command registration/removal flows to generate and reconcile composed command content across agents.
  • Updates CLI output, shell helpers, docs, and expands test coverage for strategy behavior and multi-layer chaining.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, layer collection, content composition, and command reconciliation logic.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chain details.
scripts/bash/common.sh Adds resolve_template_content() and filters disabled presets from registry enumeration.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent, Python discovery helper, and filters disabled presets.
tests/test_presets.py Adds extensive tests for strategy validation, composition behaviors, chaining, ordering, and reconciliation.
presets/scaffold/preset.yml Documents the new strategy field and provides composition examples.
presets/README.md Documents composition strategies and updates future-considerations section.
presets/ARCHITECTURE.md Documents strategy semantics and points to implementation entry points.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 3

Comment thread scripts/powershell/common.ps1
Comment thread src/specify_cli/presets.py
Comment thread src/specify_cli/__init__.py
- Add top-replace short-circuit in PowerShell Resolve-TemplateContent:
  return top layer directly when its strategy is replace, matching
  Python and bash resolver behavior
- Reconcile skills after install: call _reconcile_skills() for affected
  command names so SKILL.md files reflect the actual priority winner
- Promote _collect_all_layers to public collect_all_layers: the method
  is used by the CLI (preset resolve command), so it should be a public
  API rather than a private helper
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds preset “composition strategies” so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, with consistent resolution across Python and shell helpers.

Changes:

  • Introduces strategy validation in preset.yml (with script-specific restrictions) and implements layered composition via PresetResolver.collect_all_layers() + resolve_content().
  • Updates command registration to write composed command content and reconciles command/skill outputs after install/remove so results reflect the current priority stack.
  • Adds shell helpers and extensive test coverage for strategy validation and composition behavior.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, layer collection + bottom-up composition, and reconciles composed commands/skills on install/remove.
tests/test_presets.py Adds tests for strategy validation, resolve_content(), multi-preset chaining, ordering, and reconciliation behavior.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chain when applicable.
scripts/bash/common.sh Filters disabled presets and adds resolve_template_content() to compose template output in bash.
scripts/powershell/common.ps1 Filters disabled presets, adds Python3 discovery, and adds Resolve-TemplateContent for composed template output.
presets/scaffold/preset.yml Documents strategy field options and provides composition examples.
presets/README.md Documents composition strategies and supported combinations; updates future considerations.
presets/ARCHITECTURE.md Adds strategy table and references to composition resolution functions.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 1

Comment thread src/specify_cli/presets.py
Instead of hardcoding source_id='reconciled', pass through the actual
layer source (e.g., 'core', 'project override', 'extension:<id>') from
collect_all_layers() so rendered command files show accurate provenance.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds composition strategies to the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, and updates CLI/docs/tests accordingly.

Changes:

  • Introduces strategy validation in preset manifests and adds bottom-up composition via PresetResolver.collect_all_layers() + PresetResolver.resolve_content().
  • Updates command registration/removal to resolve and (re)register composed command content across the priority stack.
  • Adds shell parity helpers for composed template resolution plus extensive new test coverage and documentation updates.
Show a summary per file
File Description
src/specify_cli/presets.py Implements strategy validation, layer collection, content composition, and composed command reconciliation.
tests/test_presets.py Adds strategy validation and composition tests (templates/commands/scripts + chaining + ordering).
src/specify_cli/__init__.py Enhances specify preset resolve output with composition-chain visibility.
scripts/bash/common.sh Adds enabled-preset filtering + composed template resolution helper in bash.
scripts/powershell/common.ps1 Adds enabled-preset filtering + composed template resolution helper in PowerShell (with YAML parsing via Python when available).
presets/scaffold/preset.yml Documents strategy options and provides composition examples in the scaffold.
presets/README.md Documents composition strategies and supported combinations; updates future considerations.
presets/ARCHITECTURE.md Documents strategy semantics and points to the new resolution functions across implementations.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 4

Comment thread tests/test_presets.py
Comment thread src/specify_cli/presets.py Outdated
Comment thread scripts/bash/common.sh Outdated
Comment thread scripts/bash/common.sh Outdated
- Fix bash wrap to replace all {CORE_TEMPLATE} occurrences using a
  while loop, matching Python str.replace and PowerShell .Replace behavior
- Fail fast when composition has no base: raise PresetValidationError
  instead of silently degrading to implicit replace when a non-replace
  strategy command has no lower-priority base to compose onto
- Strengthen remove reconciliation test: create a gemini commands dir
  and verify on-disk command file content switches from hi to lo
  after removing the top-priority preset
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds preset “composition strategies” so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, with aligned behavior across Python + shell resolvers and updated docs/tests.

Changes:

  • Introduces strategy validation in preset manifests and adds resolver support for collecting layers + composing content across the priority stack.
  • Updates command registration to write composed command content into agent directories and reconciles command files after install/remove.
  • Adds Bash/PowerShell composed-template resolvers, expands specify preset resolve output, and documents the new strategies with extensive tests.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy constants/validation, layer collection + composition resolver, and command registration/reconciliation changes.
tests/test_presets.py Adds validation/composition/reconciliation tests for the new strategy behaviors.
src/specify_cli/__init__.py Enhances specify preset resolve to show composition chain details.
scripts/bash/common.sh Adds resolve_template_content() and filters disabled presets when reading .registry.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent, Python 3 discovery helper, and filters disabled presets in .registry.
presets/scaffold/preset.yml Documents strategy usage and provides composition examples in the scaffold manifest.
presets/README.md Documents composition strategies and supported combinations; updates “future considerations”.
presets/ARCHITECTURE.md Adds strategy table and references to the new composition resolution functions.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/8 changed files
  • Comments generated: 3

Comment on lines +2294 to +2312
core = None
if template_type == "template":
c = self.templates_dir / f"{template_name}.md"
if c.exists():
core = c
elif template_type == "command":
c = self.templates_dir / "commands" / f"{template_name}.md"
if c.exists():
core = c
elif template_type == "script":
c = self.templates_dir / "scripts" / f"{template_name}{ext}"
if c.exists():
core = c
if core:
layers.append({
"path": core,
"source": "core",
"strategy": "replace",
})
Comment thread tests/test_presets.py
Comment on lines +3432 to +3435
# Create core command
commands_dir = project_dir / ".specify" / "templates" / "commands"
commands_dir.mkdir(parents=True, exist_ok=True)
(commands_dir / "speckit.plan.md").write_text("# Core Plan Command\n")
Comment on lines +157 to +168
# Validate strategy field (optional, defaults to "replace")
strategy = tmpl.get("strategy", "replace")
if strategy not in VALID_PRESET_STRATEGIES:
raise PresetValidationError(
f"Invalid strategy '{strategy}': "
f"must be one of {sorted(VALID_PRESET_STRATEGIES)}"
)
if tmpl["type"] == "script" and strategy not in VALID_SCRIPT_STRATEGIES:
raise PresetValidationError(
f"Invalid strategy '{strategy}' for script: "
f"scripts only support {sorted(VALID_SCRIPT_STRATEGIES)}"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts

3 participants