feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts#2133
feat(presets): Composition strategies (prepend, append, wrap) for templates, commands, and scripts#2133
Conversation
… 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).
00edba1 to
fa04828
Compare
There was a problem hiding this comment.
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
strategyvalidation 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
- 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)
There was a problem hiding this comment.
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
strategyvalidation 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
There was a problem hiding this comment.
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
strategyvalidation and implements multi-layer composition viaPresetResolver._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’swrapstrategy 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’swrapstrategy 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
- 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()
There was a problem hiding this comment.
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 viaPresetResolver.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
- 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
There was a problem hiding this comment.
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
strategyvalidation 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
- 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
There was a problem hiding this comment.
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
strategyvalidation in preset manifests and implements bottom-up layer composition inPresetResolver.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-TemplateContentcomposes whenever any layer has a non-replacestrategy. As with the Python resolver, this can throw on a lower-prioritywrap(missing{CORE_TEMPLATE}) even when a higher-priorityreplacelayer should override and ignore lower layers. Consider short-circuiting when the highest-priority strategy isreplace(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-replacelayer anywhere in the stack as requiring composition. This can raise wrap-placeholder validation errors (or do unnecessary composition) even when the highest-priority layer isstrategy: replaceand should completely override lower layers. Consider short-circuiting early whenlayers[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
- 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
There was a problem hiding this comment.
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
strategyvalidation in preset manifests and implements full-stack layer collection + bottom-up composition inPresetResolver.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
- 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
There was a problem hiding this comment.
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
strategyvalidation inpreset.yml(with script-specific restrictions) and implements layered composition viaPresetResolver.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
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.
There was a problem hiding this comment.
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
strategyvalidation in preset manifests and adds bottom-up composition viaPresetResolver.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
- 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
There was a problem hiding this comment.
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
strategyvalidation 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 resolveoutput, 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
| 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", | ||
| }) |
| # 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") |
| # 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)}" | ||
| ) |
Presets can now augment lower-priority templates instead of only fully replacing them. A new optional
strategyfield inpreset.ymlcontrols how content is composed across the priority stack.replaceprependappendwrap{CORE_TEMPLATE}/$CORE_SCRIPTplaceholder substitutionMultiple composing presets chain recursively (e.g. security
prepend+ complianceappend→ header + core + footer).Python resolver (
src/specify_cli/presets.py)VALID_PRESET_STRATEGIES/VALID_SCRIPT_STRATEGIESconstants; validation in_validate()rejectsprepend/appendfor scriptsPresetResolver._collect_all_layers()— walks full priority stack, reads strategy from each preset manifestPresetResolver.resolve_content()— bottom-up composition across layersPresetManager._register_commands()— composes command content before writing to agent directoriesShell resolvers
resolve_template_content()inscripts/bash/common.shResolve-TemplateContentinscripts/powershell/common.ps1CLI
specify preset resolveshows composition chain when non-replace strategies are presentDocumentation
presets/scaffold/preset.yml— strategy field docs and composition examplespresets/README.md— composition strategies section; moved implemented items out of future considerationspresets/ARCHITECTURE.md— strategy table and content resolution function referencesTests
resolve_content()for each strategy × type, multi-preset chaining, override precedence, separator behavior,_collect_all_layers()ordering