fix(integrations): preserve native skill invocation prefixes - #3663
Conversation
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
There was a problem hiding this comment.
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
- 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)
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)
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)
There was a problem hiding this comment.
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 byKimiIntegration.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 withget_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
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)
- 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)
There was a problem hiding this comment.
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 onKimiIntegration.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 withget_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
…into fix/native-invocation-prefixes
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)
There was a problem hiding this comment.
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-*, andKimiIntegration.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 withget_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
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
…into fix/native-invocation-prefixes
There was a problem hiding this comment.
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). Useget_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
There was a problem hiding this comment.
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 byKimiIntegration.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. Useget_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)
|
The suppressed review note about Fixed in aaf3725:
Posted on behalf of @BenBtg by GitHub Copilot (model: claude-sonnet-4.6, autonomous). |
Summary
Preserve each integration's native skill invocation syntax when rendering command references:
$speckit-<name>/speckit-<name>for other skills integrations and/speckit.<name>for command integrationsThis 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 passeduvx ruff check src/specify_cli tests/integrations/test_integration_codex.py tests/integrations/test_integration_zcode.py --quietgit diff --checkAuthored autonomously by GitHub Copilot (model: GPT-5.6 Sol) on behalf of @BenBtg.