Skip to content

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

Open
Copilot wants to merge 25 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 25 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 the preset system so higher-priority presets can augment (prepend/append/wrap) lower-priority templates/commands/scripts instead of only replacing them, with matching CLI output, shell parity, and expanded test coverage.

Changes:

  • Introduces strategy validation in preset manifests and implements bottom-up composition via PresetResolver.collect_all_layers() + PresetResolver.resolve_content().
  • Updates command registration to write composed command content into agent directories and reconciles agent outputs on install/remove.
  • Extends Bash/PowerShell resolvers plus preset docs and scaffolding; adds extensive unit tests for strategy behavior and 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 chains.
scripts/bash/common.sh Adds resolve_template_content() and filters out disabled presets in registry traversal.
scripts/powershell/common.ps1 Adds YAML-strategy parsing (via Python) and Resolve-TemplateContent; filters disabled presets.
tests/test_presets.py Adds strategy validation and composition behavior tests (templates/commands/scripts + chaining + reconciliation).
presets/scaffold/preset.yml Documents strategy usage and provides composition examples.
presets/README.md Documents composition strategies and supported combinations.
presets/ARCHITECTURE.md Documents strategy semantics and references 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 (1)

scripts/bash/common.sh:540

  • layer_content=$(cat "$path") uses command substitution, which strips trailing newlines from the file content. That means composed output can differ from the underlying files (and from the Python resolver) in subtle ways. If exact content preservation matters, read/compose in a way that preserves trailing newlines or explicitly normalize behavior across implementations.
        layer_content=$(cat "$path")

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

Comment thread src/specify_cli/__init__.py Outdated
Comment thread scripts/bash/common.sh Outdated
Comment thread scripts/powershell/common.ps1 Outdated
Comment thread src/specify_cli/presets.py
- Persist normalized strategy: write lowercase value back to tmpl dict
  so downstream composition logic always sees lowercase
- Normalize strategy in PowerShell: .ToLowerInvariant() after parsing
- Fix bash tab parsing: use IFS+read instead of parameter expansion to
  avoid trailing newline in manifest_file; normalize with ${strategy,,}
- Gate CLI composition message: only show 'Final output is composed...'
  when the top layer is non-replace (top replace wins outright)
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 lower-priority templates/commands/scripts (prepend/append/wrap) rather than only fully replacing them, with consistent resolution across Python + shell helpers and updated CLI/docs/tests.

Changes:

  • Add strategy validation to preset manifests and implement multi-layer composition via PresetResolver.collect_all_layers() + resolve_content().
  • Update command registration to register composed command content (and reconcile after install/remove so priority stack, not install order, determines active agent command files).
  • Add shell helpers + CLI output + documentation + tests for the strategy behaviors.
Show a summary per file
File Description
src/specify_cli/presets.py Implements strategy validation, layered resolution + composition, and command registration/reconciliation behavior.
tests/test_presets.py Adds validation + resolver tests for strategies, chaining, ordering, and removal reconciliation.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chain when applicable.
scripts/bash/common.sh Adds template content composition resolver in Bash + skips disabled presets from registry.
scripts/powershell/common.ps1 Adds template content composition resolver in PowerShell + skips disabled presets from registry.
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 the new 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: 5

Comment thread scripts/bash/common.sh Outdated
Comment thread src/specify_cli/presets.py Outdated
Comment thread src/specify_cli/presets.py Outdated
Comment thread src/specify_cli/__init__.py
Comment thread tests/test_presets.py
- Add frontmatter composition test: verify core+preset command layers
  with frontmatter produce only one frontmatter block in composed output
- Defer resolve_with_source: only call when collect_all_layers returns
  empty, avoiding redundant filesystem walk
- Reuse CommandRegistrar.parse_frontmatter: replace local
  _strip_frontmatter helper with _split_frontmatter that delegates to
  the shared parse_frontmatter method
- Fix removed_cmd_names collection: gather ALL command names before
  filtering out skill agents so reconciliation covers all affected
  commands including those only registered for skill-based agents
- Preserve trailing newlines in bash: use sentinel character technique
  (cat + printf x + strip) to avoid command substitution stripping
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 instead of only replacing it, updating resolvers across Python + shell implementations and documenting the behavior.

Changes:

  • Add strategy validation to preset.yml entries and implement bottom-up composition in PresetResolver.resolve_content() (with multi-layer chaining and command frontmatter handling).
  • Update command registration to materialize composed command content to disk and reconcile command/skill outputs after install/remove so results don’t depend on operation order.
  • Add shell helpers (bash/pwsh) for composed template resolution, expand docs, and add extensive test coverage for strategy behavior.
Show a summary per file
File Description
src/specify_cli/presets.py Core implementation: strategy validation, layer collection, composition resolver, and command/skill reconciliation logic.
tests/test_presets.py Adds validation + resolver + chaining + reconciliation tests for the new strategies.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chain when relevant.
scripts/bash/common.sh Adds composed template resolver and filters disabled presets in registry iteration.
scripts/powershell/common.ps1 Adds composed template resolver, Python discovery, and filters disabled presets in registry iteration.
presets/scaffold/preset.yml Documents the new strategy field and provides usage examples in scaffold preset.
presets/README.md Documents composition strategies and updates “future enhancements” section accordingly.
presets/ARCHITECTURE.md Describes strategy semantics and points to implementation entrypoints across languages.

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: 2

Comment thread scripts/bash/common.sh Outdated
Comment thread src/specify_cli/presets.py
- Extract stable source_id from display label in reconciliation: parse
  'extension:foo v1.0' to 'foo' instead of passing the human-facing
  display string as source_id
- Fix bash lowercase to be POSIX-compatible: use tr instead of ${,,}
  which requires Bash 4+ and fails on macOS default Bash 3.2
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 resolution 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 and shell resolvers accordingly.

Changes:

  • Introduces strategy validation in preset.yml and bottom-up multi-layer composition via PresetResolver.collect_all_layers() / resolve_content().
  • Updates command registration to write composed command content into agent directories and reconciles command files after install/remove.
  • Extends CLI specify preset resolve output, adds Bash/PowerShell template-content composition helpers, and documents the new feature with extensive tests.
Show a summary per file
File Description
tests/test_presets.py Adds coverage for strategy validation, composition behavior, chaining, ordering, and reconciliation scenarios.
src/specify_cli/presets.py Implements strategy validation, layer collection, content composition, command registration composition, and reconciliation logic.
src/specify_cli/init.py Enhances preset resolve to display layer stack and composition chain.
scripts/bash/common.sh Adds resolve_template_content() and updates preset sorting to ignore disabled presets.
scripts/powershell/common.ps1 Adds Resolve-TemplateContent and updates preset sorting to ignore disabled presets; adds Python 3 discovery helper.
presets/scaffold/preset.yml Documents strategy field and provides composition examples in the scaffold preset.
presets/README.md Documents composition strategies and supported combinations; updates future considerations.
presets/ARCHITECTURE.md Documents composition strategies 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.

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

Comment thread src/specify_cli/presets.py
Comment thread src/specify_cli/__init__.py Outdated
Comment thread scripts/bash/common.sh Outdated
Comment thread scripts/powershell/common.ps1
- Warn on missing PyYAML in bash/PS1: emit stderr warning when manifest
  contains strategy: but YAML parsing failed, so users know composition
  strategies may be silently ignored
- Fix composition chain base labeling: only mark the lowest layer as
  'base', keep 'replace' label for non-effective replace layers above it
- Clear frontmatter on replace layers: replace strategy resets
  top_frontmatter_text (even to None) since it replaces the whole command
  including metadata, preventing lower-layer frontmatter from leaking
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 resolution stack so presets can augment lower-priority templates/commands/scripts (instead of only replacing), and updates CLI/docs/tests to support and explain the new behavior.

Changes:

  • Introduces strategy validation in preset manifests and bottom-up composition in PresetResolver.resolve_content() / collect_all_layers().
  • Updates command registration to materialize composed command content and reconciles command/skill outputs after install/remove.
  • Adds shell-side template composition helpers plus extensive test coverage and documentation updates.
Show a summary per file
File Description
src/specify_cli/presets.py Implements strategy validation, layer collection + composition, and command reconciliation/registration changes.
tests/test_presets.py Adds validation + composition + reconciliation test suite for the new strategy behavior.
src/specify_cli/__init__.py Enhances specify preset resolve output to show composition chain details.
scripts/bash/common.sh Adds composed template content resolver and filters disabled presets in registry scanning.
scripts/powershell/common.ps1 Adds composed template content resolver (with Python 3 discovery) and filters disabled presets.
presets/scaffold/preset.yml Documents strategy field and provides composition examples.
presets/README.md Documents composition strategies and updates future-considerations section.
presets/ARCHITECTURE.md Adds strategy table and links to resolver functions across Python/Bash/PowerShell.

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 src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/presets.py Outdated
- Remove dead has_composition branch in resolve_content: after the
  top-replace early return, the top layer is guaranteed non-replace
  so the any() check was always true
- Fix CLI composition chain base labeling: compute effective base index
  using same logic as resolve_content (last consecutive replace from
  bottom before first non-replace) instead of always labeling i==0
- Support extension manifest file paths in collect_all_layers: when
  convention lookup fails for commands, parse extension.yml to find
  the actual file path, enabling composition onto extension commands
  that use non-convention filenames
Comment thread src/specify_cli/presets.py Fixed
Replace broad 'except Exception: pass' with specific exception types
(ExtValidationError, yaml.YAMLError) and add explanatory comment for
the intentional fallback to convention-based lookup.
Copilot AI review requested due to automatic review settings April 21, 2026 14:55
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/template resolution system so presets can augment lower-priority content (prepend/append/wrap) instead of only replacing, and updates CLI/docs/tests accordingly.

Changes:

  • Introduces strategy validation in preset manifests and implements layered composition via PresetResolver.collect_all_layers() + resolve_content().
  • Updates command registration to pre-compose command content (and reconcile after install/remove) so agent command files reflect the effective priority stack.
  • Adds shell equivalents for composed template resolution, expands documentation, and adds extensive test coverage for the new behaviors.
Show a summary per file
File Description
src/specify_cli/presets.py Adds strategy validation, layer collection + content composition, and command registration/reconciliation updates.
src/specify_cli/__init__.py Enhances specify preset resolve output to display 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, a Python3 locator helper, and filters disabled presets when reading registry.
tests/test_presets.py Adds new tests for strategy validation, composition behaviors, layer ordering, and remove-time reconciliation.
presets/scaffold/preset.yml Documents the new strategy field and provides examples.
presets/README.md Adds a “Composition Strategies” section and updates future considerations.
presets/ARCHITECTURE.md Documents supported strategies and points to the new composition resolvers.

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 Outdated
Comment thread src/specify_cli/presets.py Outdated
Comment thread src/specify_cli/presets.py Outdated
- Add public register_commands_for_non_skill_agents() on CommandRegistrar:
  reconciliation no longer accesses private _ensure_configs() or iterates
  AGENT_CONFIGS directly
- Cache parsed preset manifests in PresetResolver: _get_manifest() caches
  by pack_dir to avoid re-parsing YAML on each collect_all_layers() call
- Fix frontmatter detection for empty dicts: detect based on --- fence
  presence rather than parsed dict truthiness, so empty frontmatter
  blocks are properly stripped during command composition
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 lower-priority layers (instead of always replacing), spanning Python resolution, shell helpers, CLI output, docs, and tests.

Changes:

  • Introduces strategy validation in preset manifests and implements bottom-up composition (replace/prepend/append/wrap) via PresetResolver.collect_all_layers() + resolve_content().
  • Updates command registration to register composed command content and adds post-install/remove reconciliation so agent command files reflect the current priority stack.
  • Extends bash/powershell helpers, CLI preset resolve output, scaffold/docs, and adds extensive tests for composition behavior.
Show a summary per file
File Description
src/specify_cli/presets.py Core implementation: strategy validation, layer collection, composition, and command reconciliation/registration updates.
src/specify_cli/agents.py Adds a registrar helper to register commands while skipping SKILL.md-based agents.
src/specify_cli/__init__.py Enhances specify preset resolve to show composition chain using the new layer collector.
scripts/bash/common.sh Adds resolve_template_content() and filters disabled presets from registry traversal.
scripts/powershell/common.ps1 Adds YAML-aware Resolve-TemplateContent, Python 3 detection, and filters disabled presets.
tests/test_presets.py Adds a large new test suite covering validation, composition behavior, ordering, and removal reconciliation.
presets/scaffold/preset.yml Documents the new strategy field and provides composition examples.
presets/README.md Adds a Composition Strategies section and updates “future considerations”.
presets/ARCHITECTURE.md Documents strategy semantics and points to new resolution/composition functions.

Copilot's findings

Tip

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

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

Comment thread src/specify_cli/agents.py
Comment on lines +623 to +661
def register_commands_for_non_skill_agents(
self,
commands: List[Dict[str, Any]],
source_id: str,
source_dir: Path,
project_root: Path,
) -> Dict[str, List[str]]:
"""Register commands for all non-skill agents in the project.
Like register_commands_for_all_agents but skips skill-based agents
(those with extension '/SKILL.md'). Used by reconciliation to avoid
overwriting properly formatted SKILL.md files.
Args:
commands: List of command info dicts
source_id: Identifier of the source
source_dir: Directory containing command source files
project_root: Path to project root
Returns:
Dictionary mapping agent names to list of registered commands
"""
results = {}
self._ensure_configs()
for agent_name, agent_config in self.AGENT_CONFIGS.items():
if agent_config.get("extension") == "/SKILL.md":
continue
agent_dir = project_root / agent_config["dir"]
if agent_dir.exists():
try:
registered = self.register_commands(
agent_name, commands, source_id,
source_dir, project_root,
)
if registered:
results[agent_name] = registered
except ValueError:
continue
return results
Comment on lines +2599 to +2629
layers = resolver.collect_all_layers(template_name)

if layers:
# Use the highest-priority layer for display because the final output
# may be composed and may not map to resolve_with_source()'s single path.
display_layer = layers[0]
console.print(f" [bold]{template_name}[/bold]: {display_layer['path']}")
console.print(f" [dim](top layer from: {display_layer['source']})[/dim]")

has_composition = (
layers[0]["strategy"] != "replace"
and any(layer["strategy"] != "replace" for layer in layers)
)
if has_composition:
console.print(" [dim]Final output is composed from multiple preset layers; the path above is the highest-priority contributing layer.[/dim]")
console.print("\n [bold]Composition chain:[/bold]")
# Compute the effective base: the last consecutive replace layer
# from the bottom before the first non-replace (same logic as
# PresetResolver.resolve_content).
reversed_display = list(reversed(layers))
effective_base_idx = 0
for idx, lyr in enumerate(reversed_display):
if lyr["strategy"] == "replace":
effective_base_idx = idx
else:
break
for i, layer in enumerate(reversed_display):
strategy_label = layer["strategy"]
if strategy_label == "replace" and i == effective_base_idx:
strategy_label = "base"
console.print(f" {i + 1}. [{strategy_label}] {layer['source']} → {layer['path']}")
Comment on lines +768 to +782
def _register_for_non_skill_agents(
self,
registrar: Any,
commands: List[Dict[str, Any]],
source_id: str,
source_dir: Path,
) -> None:
"""Register commands for all non-skill agents.

Used during reconciliation to avoid overwriting properly formatted
SKILL.md files that were written by _register_skills().
"""
registrar.register_commands_for_non_skill_agents(
commands, source_id, source_dir, self.project_root
)
- Keep non-skill agent reconciliation: reconciliation uses
  register_commands_for_non_skill_agents to avoid overwriting formatted
  SKILL.md content; _unregister_skills restores core/extension skills
  and _reconcile_skills handles lower-priority preset skills
- Show composition error in CLI resolve: when has_composition is true,
  call resolve_content() and warn if composition cannot produce output
  (no base layer) instead of showing a misleading 'resolved' path
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