Skip to content

Commit 840fb8d

Browse files
docs: document __SPECKIT_COMMAND_ token for portable cross-command references (#3503)
* docs: document __SPECKIT_COMMAND_ token for cross-command references the development guide's 'Body (Markdown)' section listed $ARGUMENTS and {SCRIPT} but never mentioned __SPECKIT_COMMAND_<NAME>__, the agent-neutral token that resolve_command_refs() renders into each agent's invocation syntax. with no signal the token exists, an author naturally hard-codes a literal like /speckit.my-ext.prepare — correct for one agent, broken on the rest (the root cause behind #3451). added it to the placeholder list plus a 'Referencing other commands' subsection: why a literal isn't portable, the name->token encoding, and a worked example showing the same token render as /speckit.bug.fix for a slash agent and /speckit-bug-fix for a skills agent. examples verified against resolve_command_refs and the first-party bug/git extensions. phase 1 of the plan in #3474; addresses the discoverability gap for #3451. * address review: describe separator-based token rendering accurately Copilot flagged (and mnriem asked me to address) that the section implied __SPECKIT_COMMAND_<NAME>__ always resolves to each agent's native invocation, including $speckit-* for Codex/ZCode. the resolver (resolve_command_refs) only emits /speckit<separator>... based on the active integration's invoke_separator; the $ and /skill: prefixes come from later skills-output post-processing, not the token resolver itself. reworded both the placeholder-list entry and the two explanatory paragraphs to describe separator-based rendering, and moved the prefix-in-skills-mode detail to a parenthetical example rather than stating it as the token's guaranteed output. * address review: qualify token portability for skills-mode extensions Copilot correctly noted the __SPECKIT_COMMAND_<NAME>__ token is not yet resolved for extension-generated skills: _register_extension_skills() calls resolve_skill_placeholders() and post_process_skill_content() but never resolve_command_refs(), so the token reaches Codex/ZCode/Kimi verbatim in skills mode. Token resolution only runs in the command-file rendering path (CommandRegistrar). Add an explicit limitation note so the guidance no longer implies universal portability.
1 parent 0d2e3b5 commit 840fb8d

1 file changed

Lines changed: 35 additions & 0 deletions

File tree

extensions/EXTENSION-DEVELOPMENT-GUIDE.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ Use standard Markdown with special placeholders:
252252

253253
- `$ARGUMENTS`: User-provided arguments
254254
- `{SCRIPT}`: Replaced with script path during registration
255+
- `__SPECKIT_COMMAND_<NAME>__`: Replaced with the invocation of another command, rendered using the active integration's separator (see [Referencing other commands](#referencing-other-commands))
255256

256257
**Example**:
257258

@@ -267,6 +268,40 @@ echo "Running with args: $args"
267268
```
268269
````
269270

271+
### Referencing other commands
272+
273+
A command body is a *template* that Spec Kit renders once per agent. Different agents invoke commands with different surface syntax — for example `/speckit.plan` (dot separator) or `/speckit-plan` (hyphen separator). Some agents also use different prefixes in skills mode (e.g. Kimi `/skill:speckit-plan`, Codex/ZCode `$speckit-plan`). So when you reference a sibling command from a body, **do not hard-code a literal invocation** like `/speckit.my-ext.prepare`. A literal is correct for exactly one agent and breaks on the rest.
274+
275+
Instead use the agent-neutral token `__SPECKIT_COMMAND_<NAME>__`. Spec Kit resolves it to a `/speckit<separator>...` invocation using the active integration's `invoke_separator` (and integrations may post-process that further in skills output).
276+
277+
Encode the command name in upper case, dropping the `speckit.` prefix and turning each dotted segment separator into an underscore:
278+
279+
| Command file | Token |
280+
| --- | --- |
281+
| `speckit.plan.md` | `__SPECKIT_COMMAND_PLAN__` |
282+
| `speckit.bug.fix.md` | `__SPECKIT_COMMAND_BUG_FIX__` |
283+
| `speckit.git.commit.md` | `__SPECKIT_COMMAND_GIT_COMMIT__` |
284+
285+
The resolver maps each underscore back to the active agent's separator, so use tokens to reference commands whose name segments are single words. (Command names are dotted segments like `git.commit`; the token scheme rebuilds those dots and does not carry hyphens within a segment.)
286+
287+
**Example** — a command body that points the user at the next step:
288+
289+
```markdown
290+
Once the assessment exists, the next step is `__SPECKIT_COMMAND_BUG_FIX__ slug=<slug>`.
291+
```
292+
293+
This renders as `/speckit.bug.fix slug=<slug>` for a slash-based agent, `/speckit-bug-fix slug=<slug>` for a skills-based agent, and so on — the author writes it once and it stays portable. The first-party `bug` and `git` extensions use this token exclusively; see `extensions/bug/commands/` for working examples.
294+
295+
> **Current limitation — skills mode.** Token resolution runs in the
296+
> command-rendering path (`CommandRegistrar`), so it applies when an extension
297+
> installs *command files*. It does **not** yet run when an extension is
298+
> registered as *skills* for a skills-based agent: `_register_extension_skills`
299+
> resolves placeholders and post-processes content but never calls
300+
> `resolve_command_refs`, so a `__SPECKIT_COMMAND_<NAME>__` token reaches
301+
> agents such as Codex, ZCode, and Kimi verbatim in that mode. Until that
302+
> rendering step lands, prefer the token for command-file extensions and avoid
303+
> relying on it inside skill bodies destined for skills-based agents.
304+
270305
### Script Path Rewriting
271306

272307
Extension commands use relative paths that get rewritten during registration:

0 commit comments

Comments
 (0)