Skip to content

feat: implement preset wrap strategy#2189

Open
kennedy-whytech wants to merge 5 commits intogithub:mainfrom
kennedy-whytech:kennedy-whytech-feat-preset-wrap-strategy
Open

feat: implement preset wrap strategy#2189
kennedy-whytech wants to merge 5 commits intogithub:mainfrom
kennedy-whytech:kennedy-whytech-feat-preset-wrap-strategy

Conversation

@kennedy-whytech
Copy link
Copy Markdown

@kennedy-whytech kennedy-whytech commented Apr 12, 2026

Description

Implements strategy: wrap for preset commands, which was listed as a roadmap
item in presets/README.md. When a preset command sets strategy: wrap, the
{CORE_TEMPLATE} placeholder in its body is substituted with the body of the
installed core speckit command template at install time.

This lets preset authors add pre/post logic around core commands without
copy-pasting the entire command body — useful for extending frequently-updated
templates like /speckit.specify or /speckit.tasks. Personally, I find it neccessary.

Changes

  • src/specify_cli/presets.py — adds _substitute_core_template() helper;
    wires substitution into _register_skills (skills-backed agents like Claude)
  • src/specify_cli/agents.py — wires substitution into register_commands
    (all other agent types)
  • presets/self-test/ — adds a speckit.wrap-test command for E2E coverage
  • presets/README.md — marks wrap as implemented for command/template types

Test results

184 tests pass (tests/test_presets.py), including a new TestWrapStrategy
class with unit tests for the helper and an end-to-end install test.

Manual test results

Agent: Claude Code | OS/Shell: macOS/zsh

Command tested Notes
specify preset install with strategy: wrap command {CORE_TEMPLATE} correctly substituted in written skill/command file

End-to-end test with my own presets. The wrapping seems doing good. Also, I feel like "wrap" can cover prepend and append already.
Screenshot 2026-04-13 at 12 10 42 PM

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable)

AI Disclosure

  • I did not use AI assistance for this contribution

  • I did use AI assistance (describe below)

    AI assistance disclosure

    This PR was implemented with AI assistance (Claude Code) for code generation,
    test writing, and commit messages. All changes were reviewed and verified
    manually.

@kennedy-whytech kennedy-whytech requested a review from mnriem as a code owner April 12, 2026 14:35
@kennedy-whytech kennedy-whytech force-pushed the kennedy-whytech-feat-preset-wrap-strategy branch from 604b585 to 444daef Compare April 12, 2026 15:47
@mnriem mnriem requested a review from Copilot April 13, 2026 12:28
@mnriem mnriem self-assigned this Apr 13, 2026
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 support for strategy: wrap on preset-provided commands, enabling preset authors to inject pre/post content around an existing “core” command body via a {CORE_TEMPLATE} placeholder during command/skill registration.

Changes:

  • Introduces _substitute_core_template() and applies it during preset skill registration (_register_skills) and generic agent command registration (CommandRegistrar.register_commands).
  • Extends the self-test preset with a new speckit.wrap-test command and updates docs to mark wrap as implemented for commands.
  • Adds unit + E2E-style tests covering placeholder substitution and install behavior.
Show a summary per file
File Description
tests/test_presets.py Updates self-test manifest expectations; adds new TestWrapStrategy coverage.
src/specify_cli/presets.py Adds _substitute_core_template() and wires it into preset skill generation.
src/specify_cli/agents.py Wires wrap substitution into agent command registration.
presets/self-test/preset.yml Adds a new wrap-strategy command entry to the self-test preset.
presets/self-test/commands/speckit.wrap-test.md Adds a wrap command template using {CORE_TEMPLATE}.
presets/README.md Updates roadmap/docs to reflect wrap implemented for commands/artifacts.

Copilot's findings

Tip

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

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

Copy link
Copy Markdown
Collaborator

@mnriem mnriem left a comment

Choose a reason for hiding this comment

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

Please address Copilot feedback. If not applicable, please explain why

@kennedy-whytech kennedy-whytech force-pushed the kennedy-whytech-feat-preset-wrap-strategy branch from 444daef to 53220f8 Compare April 13, 2026 15:55
@kennedy-whytech
Copy link
Copy Markdown
Author

kennedy-whytech commented Apr 13, 2026

@mnriem that makes sense to me. updated.

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

Implements support for strategy: wrap on preset command templates by substituting {CORE_TEMPLATE} with the installed core command template body during installation/registration, enabling presets to extend core commands without copy/paste.

Changes:

  • Added _substitute_core_template() helper and applied it when generating skills from preset commands (Claude skills flow).
  • Applied the same substitution in CommandRegistrar.register_commands() for non-skill agent command installation.
  • Added a self-test preset wrap command + unit/E2E tests, and updated preset strategy documentation.
Show a summary per file
File Description
src/specify_cli/presets.py Adds {CORE_TEMPLATE} substitution helper and applies it in the skills generation path for wrap-strategy preset commands.
src/specify_cli/agents.py Applies {CORE_TEMPLATE} substitution during normal agent command registration when strategy: wrap is set.
tests/test_presets.py Updates self-test manifest expectations and adds unit + E2E coverage for wrap substitution.
presets/self-test/preset.yml Registers a new wrap-strategy command in the bundled self-test preset.
presets/self-test/commands/speckit.wrap-test.md New wrap command template containing {CORE_TEMPLATE} placeholder.
presets/README.md Updates roadmap/docs to reflect wrap being implemented for commands/artifacts (not scripts).

Copilot's findings

Tip

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

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

@@ -3043,4 +3043,136 @@ def test_bundled_preset_missing_locally_cli_error(self, project_dir):
assert result.exit_code == 1
output = strip_ansi(result.output).lower()
assert "bundled" in output, result.output
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

This test previously asserted the CLI error also suggests how to recover (e.g., a reinstall hint). The CLI code path still prints a "Try reinstalling…" message for missing bundled presets, so dropping the "reinstall" assertion reduces coverage and makes regressions easier to miss. Consider restoring an assertion that the output includes a reinstall hint (or the specific REINSTALL_COMMAND string).

Suggested change
assert "bundled" in output, result.output
assert "bundled" in output, result.output
assert "reinstall" in output, result.output

Copilot uses AI. Check for mistakes.
Comment on lines +3138 to +3140
finally:
registrar.AGENT_CONFIGS = original

Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The test mutates CommandRegistrar.AGENT_CONFIGS (a class variable) but restores it by assigning to the instance (registrar.AGENT_CONFIGS = original). That leaves the class-level dict modified for subsequent tests. Restore via CommandRegistrar.AGENT_CONFIGS (or use patch.dict/monkeypatch) so the mutation is fully undone.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

@mnriem mnriem left a comment

Choose a reason for hiding this comment

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

Please address Copilot feedback

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.

3 participants