fix(forge): use hyphen notation for command refs in Forge integration#2462
Merged
mnriem merged 2 commits intogithub:mainfrom May 6, 2026
Merged
Conversation
- Add invoke_separator = "-" class attribute to ForgeIntegration so effective_invoke_separator() returns "-" for shared-template installs - Add "invoke_separator": "-" to ForgeIntegration.registrar_config so agents.py CommandRegistrar can resolve refs with the correct separator - Pass invoke_separator to process_template() in ForgeIntegration.setup() so all .forge/commands/*.md bodies use /speckit-foo notation - Replace literal /speckit.specify with __SPECKIT_COMMAND_SPECIFY__ in extensions/git/commands/speckit.git.feature.md so every agent resolves the reference through its own separator - Apply resolve_command_refs re.sub in agents.py register_commands() after argument-placeholder substitution so extension commands registered for Forge get /speckit-foo refs; all other agents continue to get /speckit.foo Fixes ZSH compatibility: dot-notation command invocations (/speckit.specify) are misinterpreted by ZSH as file-path operations; hyphen notation (/speckit-specify) works correctly in all shells.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the Forge integration to emit hyphen-based slash command references (e.g., /speckit-plan) instead of dot notation (e.g., /speckit.plan) to avoid ZSH misinterpreting dotted invocations. It also introduces token-based command references in an extension command and updates the command registrar to resolve those tokens per-agent.
Changes:
- Set Forge’s invoke separator to
-and pass it through template processing so generated.forge/commands/*.mdfiles use/speckit-<cmd>references. - Replace a hard-coded
/speckit.specifyreference in the git extension with a__SPECKIT_COMMAND_SPECIFY__token. - Add command-ref token resolution to
CommandRegistrar.register_commands()and extend Forge tests to ensure dot notation does not appear in generated Forge commands.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/specify_cli/integrations/forge/__init__.py |
Configures Forge to use - as the invoke separator and passes it into template processing. |
src/specify_cli/agents.py |
Adds __SPECKIT_COMMAND_*__ token resolution during extension command registration. |
extensions/git/commands/speckit.git.feature.md |
Switches from a hard-coded command ref to a tokenized ref for agent-specific resolution. |
tests/integrations/test_integration_forge.py |
Adds/extends tests to assert Forge command refs are hyphenated and extension command refs resolve correctly for Forge. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…GENT_CONFIGS Skills-based agents (claude, codex, kimi, …) inherit invoke_separator="-" from SkillsIntegration but do not repeat it in their registrar_config dicts. _build_agent_configs() was copying registrar_config verbatim, so register_commands() fell back to "." when resolving __SPECKIT_COMMAND_*__ tokens for those agents — emitting /speckit.specify instead of the correct /speckit-specify for extension commands like speckit.git.feature. Fix: after copying registrar_config, inject invoke_separator from the integration's class attribute when it is not already declared explicitly. This makes the integration class the single source of truth for all agents, without requiring each SkillsIntegration subclass to duplicate the field. Also replace the inline re.sub in register_commands() with a call to IntegrationBase.resolve_command_refs() (deferred import to avoid the existing circular dependency) so token-resolution logic is not duplicated. Adds two tests in test_agent_config_consistency.py: - test_skills_agents_have_hyphen_invoke_separator_in_agent_configs: asserts every /SKILL.md agent has invoke_separator="-" in AGENT_CONFIGS. - test_skills_agent_command_token_resolves_with_hyphen: end-to-end check via CommandRegistrar that the git extension's speckit.git.feature command is installed for Claude with /speckit-specify (not /speckit.specify). Addresses review comment on PR github#2462.
Collaborator
|
Thank you! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Dot-notation command invocations (e.g.
/speckit.specify) generated inside Forge command files are misinterpreted by ZSH as file-path operations, breaking the workflow for ZSH users.Root Cause
The
ForgeIntegrationclass was not declaring aninvoke_separator, so it fell back to the default"."(dot) separator used by all other agents. As a result, every__SPECKIT_COMMAND_*__token and any hard-coded/speckit.fooreference in extension templates resolved to dot-notation inside Forge's generated.forge/commands/files.Changes
src/specify_cli/integrations/forge/__init__.pyinvoke_separator = "-"class attribute toForgeIntegrationsoeffective_invoke_separator()returns"-"for shared-template installs."invoke_separator": "-"toForgeIntegration.registrar_configsoagents.pyCommandRegistrarcan resolve refs with the correct separator.invoke_separatortoprocess_template()inForgeIntegration.setup()so all.forge/commands/*.mdbodies use/speckit-foonotation.extensions/git/commands/speckit.git.feature.md/speckit.specifyreference with the__SPECKIT_COMMAND_SPECIFY__token so every agent resolves the reference through its own separator (dot for most agents, hyphen for Forge).src/specify_cli/agents.pyresolve_command_refsre.subinregister_commands()after argument-placeholder substitution so extension commands registered for Forge get/speckit-foorefs; all other agents continue to get/speckit.foo.tests/integrations/test_integration_forge.pytest_command_refs_use_hyphen_notation: asserts all generated Forge command files contain/speckit-<cmd>and none contain/speckit.<cmd>.test_git_extension_command_uses_hyphen_notation: end-to-end test viaCommandRegistrarthat the git extension'sspeckit.git.featurecommand resolves to/speckit-specifywhen installed for Forge.test_templates_are_processedwith an inline assertion that no dot-notation refs survive template processing.Testing
All 25 Forge integration tests pass:
ZSH Compatibility
Hyphen-notation (
/speckit-specify) works correctly in all shells. Dot-notation (/speckit.specify) causes ZSH to interpret the token as a file-path lookup, silently failing the command invocation.