Skip to content

fix(integrations): preserve native skill invocation prefixes - #3663

Merged
BenBtg merged 25 commits into
mainfrom
fix/native-invocation-prefixes
Jul 28, 2026
Merged

fix(integrations): preserve native skill invocation prefixes#3663
BenBtg merged 25 commits into
mainfrom
fix/native-invocation-prefixes

Conversation

@BenBtg

@BenBtg BenBtg commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Preserve each integration's native skill invocation syntax when rendering command references:

  • render Codex and ZCode skill invocations as $speckit-<name>
  • retain /speckit-<name> for other skills integrations and /speckit.<name> for command integrations
  • propagate the selected prefix through init, install, switch, upgrade, refresh, extension registration, preset restoration, and shared Bash/PowerShell/Python helpers
  • keep literal documentation examples unchanged while resolving explicit command-reference tokens
  • centralize integration prefix selection to avoid duplicated branching across lifecycle paths

This extracts the invocation-prefix work from #3616 so that PR remains focused on the constitution command guardrail. No constitution template or guardrail test changes are included here.

Validation

  • .venv/bin/python -m pytest tests/integrations/test_base.py tests/integrations/test_cli.py tests/integrations/test_integration_codex.py tests/integrations/test_integration_zcode.py tests/integrations/test_integration_subcommand.py tests/test_extensions.py tests/test_presets.py tests/test_setup_tasks.py -q — 1151 passed
  • uvx ruff check src/specify_cli tests/integrations/test_integration_codex.py tests/integrations/test_integration_zcode.py --quiet
  • git diff --check

Authored autonomously by GitHub Copilot (model: GPT-5.6 Sol) on behalf of @BenBtg.

BenBtg added 11 commits July 22, 2026 18:25
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Resolve generated command references with the active agent prefix instead of rewriting all slash-form text during post-processing.

Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Pass dollar-style skill prefixes through bare-project integration installation and cover the shared template output.

Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Use agent-native invocation prefixes in extension command registration and dynamic shared-script command hints.

Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Escape dollar-prefixed commands embedded in Bash strings and propagate the native prefix into installed Python command helpers.

Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Rewrite installed Bash and PowerShell formatter return expressions so direct callers receive the selected integration's native prefix.

Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Describe hook-derived references as command invocations so dollar-prefixed skills do not receive contradictory slash-command terminology.

Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19
Copilot AI review requested due to automatic review settings July 22, 2026 17:30
@BenBtg
BenBtg requested a review from mnriem as a code owner July 22, 2026 17:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Preserves native $speckit-* invocation syntax for Codex and ZCode across integration rendering and lifecycle operations.

Changes:

  • Centralizes native prefix resolution.
  • Propagates prefixes through shared infrastructure, extensions, presets, and integration lifecycle flows.
  • Adds coverage for dollar-prefixed rendering across Bash, PowerShell, and Python.
Show a summary per file
File Description
src/specify_cli/__init__.py Forwards invocation prefixes to shared infrastructure.
src/specify_cli/agents.py Applies native prefixes during command registration.
src/specify_cli/commands/init.py Supplies the selected prefix during initialization.
src/specify_cli/integration_runtime.py Resolves prefixes by integration mode.
src/specify_cli/integrations/_helpers.py Preserves prefixes when changing defaults.
src/specify_cli/integrations/_install_commands.py Handles prefixes during installation.
src/specify_cli/integrations/_migrate_commands.py Handles prefixes during switch and upgrade.
src/specify_cli/integrations/base.py Renders native skill invocations and hook guidance.
src/specify_cli/presets/__init__.py Preserves prefixes during preset restoration.
src/specify_cli/shared_infra.py Renders prefixes in templates and scripts.
tests/integrations/test_base.py Tests core invocation rendering.
tests/integrations/test_cli.py Tests shared template and script output.
tests/integrations/test_integration_base_skills.py Updates hook-guidance expectations.
tests/integrations/test_integration_codex.py Verifies Codex guidance wording.
tests/integrations/test_integration_subcommand.py Tests install and switch behavior.
tests/integrations/test_integration_zcode.py Cleans up ZCode test formatting.
tests/test_extensions.py Tests Codex extension references.
tests/test_presets.py Tests dollar-prefixed preset restoration.
tests/test_setup_tasks.py Tests Bash and PowerShell formatters.

Review details

Tip

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

  • Files reviewed: 19/19 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment thread src/specify_cli/integrations/base.py Outdated
Comment thread src/specify_cli/presets/__init__.py Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 17:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 19/19 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment thread src/specify_cli/integration_runtime.py Outdated
Comment thread src/specify_cli/shared_infra.py
BenBtg and others added 2 commits July 23, 2026 00:45
- Add SKILL_COLON_AGENTS frozenset and get_invocation_prefix() to
  _invocation_style.py so Kimi resolves to '/skill:' in skills mode
- Switch invoke_prefix_for_integration() to use get_invocation_prefix()
  instead of the binary dollar/slash check
- Update post_process_skill_content docstring (base.py) to cover both
  slash and dollar native invocation forms
- Update _resolve_command_refs_in_skill docstring (presets/__init__.py)
  to document the dollar-prefixed result alongside slash forms

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 65ef91d9-4c31-4f31-a009-ed2093fe7f28
Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Copilot AI review requested due to automatic review settings July 23, 2026 00:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 20/20 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/specify_cli/agents.py Outdated
Replace the binary is_dollar_skills_agent ternary with get_invocation_prefix
so that __SPECKIT_COMMAND_*__ tokens in Kimi skill files resolve to
/skill:speckit-<name> rather than /speckit-<name>.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 65ef91d9-4c31-4f31-a009-ed2093fe7f28
Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Copilot AI review requested due to automatic review settings July 23, 2026 00:08
Comment thread src/specify_cli/agents.py Fixed
Leftover from replacing the inline ternary with get_invocation_prefix.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 65ef91d9-4c31-4f31-a009-ed2093fe7f28
Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 20/20 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Comments suppressed due to low confidence (1)

src/specify_cli/integrations/base.py:854

  • This path still only recognizes dollar-style skills, so Kimi command tokens are first rendered as /speckit-* and are then corrected by KimiIntegration.post_process_skill_content()'s whole-body replacement (integrations/kimi/__init__.py:60-63). That replacement also changes literal /speckit-* documentation examples, contradicting this PR's stated token-only behavior; the same happens for extension/preset skill bodies that call the Kimi post-processor. Resolve the prefix here with get_invocation_prefix(agent_name, invoke_separator == "-"), and narrow/remove Kimi's broad replacement now that explicit tokens and hook notes can be rendered natively.
        invocation_prefix = (
            "$"
            if is_dollar_skills_agent(agent_name, invoke_separator == "-")
            else "/"
        )
  • Files reviewed: 20/20 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/specify_cli/presets/__init__.py Outdated
Add /skill:speckit-<cmd> to the docstring so the contract covers all
three native prefix forms returned by get_invocation_prefix.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 65ef91d9-4c31-4f31-a009-ed2093fe7f28
Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Copilot AI review requested due to automatic review settings July 23, 2026 00:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 20/20 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/specify_cli/_invocation_style.py
- test_skill_colon_prefix_core_command: resolve_command_refs with /skill: prefix
- test_get_invocation_prefix_skill_colon: get_invocation_prefix returns /skill:
  for kimi (skills), / for kimi (non-skills), $ for codex, / for claude
- test_kimi_skill_post_processing_is_idempotent: verifies Kimi's hook-command
  note is injected with /skill: prefix and does not duplicate on re-runs
- test_installed_bash_formatter_uses_skill_colon_prefix: shared-infra bash
  formatter outputs /skill:speckit-plan when installed with /skill: prefix

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 65ef91d9-4c31-4f31-a009-ed2093fe7f28
Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Copilot AI review requested due to automatic review settings July 23, 2026 00:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Comments suppressed due to low confidence (1)

src/specify_cli/integrations/base.py:853

  • Use the centralized prefix resolver here as well. For Kimi this currently renders explicit tokens as /speckit-* and relies on KimiIntegration.post_process_skill_content()'s whole-body replacement to obtain /skill:speckit-*; that replacement also changes literal /speckit-* documentation, contradicting the PR's token-only behavior. Resolve the token directly with get_invocation_prefix(agent_name, invoke_separator == "-") and remove/narrow Kimi's broad replacement.
        invocation_prefix = (
            "$"
            if is_dollar_skills_agent(agent_name, invoke_separator == "-")
            else "/"
  • Files reviewed: 20/20 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

BenBtg and others added 2 commits July 28, 2026 12:06
Resolve import conflict in presets/__init__.py: keep the expanded
_init_options import block from main alongside get_invocation_prefix
from this branch.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 65ef91d9-4c31-4f31-a009-ed2093fe7f28
Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Comments suppressed due to low confidence (1)

src/specify_cli/integrations/base.py:854

  • This path still selects only $ versus / instead of using the centralized native-prefix resolver. For Kimi, explicit tokens are therefore first rendered as /speckit-*, and KimiIntegration.post_process_skill_content() later corrects them with a whole-body .replace("/speckit-", ...), which also rewrites literal documentation examples. That contradicts this PR’s promise to change explicit command-reference tokens while preserving literals. Resolve Kimi’s /skill: prefix here with get_invocation_prefix(...) and remove/narrow the broad Kimi fallback.
        invocation_prefix = (
            "$"
            if is_dollar_skills_agent(agent_name, invoke_separator == "-")
            else "/"
        )
  • Files reviewed: 20/20 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 28, 2026 11:08
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 02f9e138-da58-4a60-93b9-eae659d2aa19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Comments suppressed due to low confidence (1)

src/specify_cli/integrations/base.py:854

  • This dollar-only selection still resolves Kimi tokens as /speckit-*. KimiIntegration.post_process_skill_content() then applies a whole-body /speckit- replacement, so literal examples are rewritten too, contrary to the PR's token-only behavior (the new Kimi idempotency test even includes such a literal without asserting it). Use get_invocation_prefix(agent_name, invoke_separator == "-") here and remove/narrow the Kimi broad replacement so only __SPECKIT_COMMAND_*__ tokens change.
        invocation_prefix = (
            "$"
            if is_dollar_skills_agent(agent_name, invoke_separator == "-")
            else "/"
        )
  • Files reviewed: 20/20 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 28, 2026 11:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Comments suppressed due to low confidence (1)

src/specify_cli/integrations/base.py:854

  • process_template() still bypasses the centralized prefix resolver and handles only dollar-vs-slash output. For Kimi, explicit tokens are first rendered as /speckit-* and repaired by KimiIntegration.post_process_skill_content()'s whole-body replacement; that replacement also rewrites literal /speckit-* documentation examples in generated core, preset, and extension skills, contradicting this PR's token-only behavior. Use get_invocation_prefix(agent_name, invoke_separator == "-") here and remove or narrow the Kimi whole-body fallback.
        invocation_prefix = (
            "$"
            if is_dollar_skills_agent(agent_name, invoke_separator == "-")
            else "/"
        )
  • Files reviewed: 20/20 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

…d replacement

process_template() was still using a binary is_dollar_skills_agent ternary
to select between dollar and slash prefix, so Kimi tokens were emitted as
/speckit-* and then corrected by a broad .replace('/speckit-', '/skill:speckit-')
in KimiIntegration.post_process_skill_content(). That broad replacement would
also rewrite any literal /speckit-* text in generated skill content, contrary
to the PR's token-only behavior.

- Use get_invocation_prefix(agent_name, invoke_separator == '-') in
  process_template() so Kimi tokens are emitted as /skill:speckit-* directly.
- Remove the broad .replace() from KimiIntegration.post_process_skill_content();
  it is now a no-op (tokens are already correctly prefixed at source).
- Add test_process_template_kimi_uses_skill_colon_prefix to guard the fix.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 65ef91d9-4c31-4f31-a009-ed2093fe7f28
Assisted-by: GitHub Copilot (model: claude-sonnet-4.6, autonomous)
Copilot AI review requested due to automatic review settings July 28, 2026 11:28
@BenBtg

BenBtg commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

The suppressed review note about base.py:854 was valid. process_template() was using a binary is_dollar_skills_agent ternary, so Kimi tokens were emitted as /speckit-* and then corrected by a broad .replace("/speckit-", "/skill:speckit-") in KimiIntegration.post_process_skill_content(). That broad replacement would also rewrite any literal /speckit-* text in generated skill content.

Fixed in aaf3725:

  • process_template() now calls get_invocation_prefix(agent_name, invoke_separator == "-") so Kimi tokens are emitted as /skill:speckit-* directly.
  • Removed the broad .replace() from KimiIntegration.post_process_skill_content() -- it is now a no-op.
  • Added test_process_template_kimi_uses_skill_colon_prefix to guard the fix.

Posted on behalf of @BenBtg by GitHub Copilot (model: claude-sonnet-4.6, autonomous).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 21/21 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@BenBtg
BenBtg merged commit 655a3cb into main Jul 28, 2026
16 checks passed
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