OpenSpec Bug Report: Skills-only delivery emits /opsx:* command references
Date: 2026-03-26
OpenSpec version: 1.2.0
Context: Discovered while auditing .claude/ files in a project configured with delivery: 'skills'. All generated openspec-* skills contained /opsx:* cross-references pointing to commands that were never generated.
Bug title
Skills-only delivery generates skill files with /opsx:* command references instead of /openspec-* skill references
Description
When OpenSpec is configured with delivery: 'skills' (skills only, no commands), the generated SKILL.md files contain hardcoded /opsx:* cross-references (e.g., /opsx:apply, /opsx:archive, /opsx:verify). These reference commands that don't exist in a skills-only setup, creating broken workflows.
Expected behavior
When delivery: 'skills', cross-references in generated skills should use the skill namespace: /openspec-apply-change, /openspec-archive-change, /openspec-verify-change, etc.
Actual behavior
All cross-references use the command namespace (/opsx:apply, /opsx:archive, etc.) regardless of the delivery setting.
Affected skills
Every skill with cross-references is affected:
| Skill |
Broken references found |
openspec-propose |
/opsx:apply |
openspec-ff-change |
/opsx:apply |
openspec-apply-change |
/opsx:apply, /opsx:archive |
openspec-explore |
/opsx:explore |
Root cause
-
Skill templates hardcode /opsx:*: The workflow template functions in src/core/templates/workflows/*.ts (e.g., getOpsxProposeSkillTemplate, getApplyChangeSkillTemplate) embed /opsx:* command references directly in the instructions strings.
-
No delivery-aware transformer for skills: generateSkillContent() in src/core/shared/skill-generation.ts accepts a transformInstructions callback, but:
- The only transformer is
transformToHyphenCommands (for OpenCode: /opsx: → /opsx-)
- No transformer exists for the skills-only case (
/opsx:* → /openspec-*)
- In
src/core/init.ts and src/core/update.ts, when delivery === 'skills', no transformer is passed
Suggested fix
The mapping isn't a simple regex — command short names differ from skill directory names:
| Command ref |
Skill ref |
/opsx:apply |
/openspec-apply-change |
/opsx:archive |
/openspec-archive-change |
/opsx:verify |
/openspec-verify-change |
/opsx:continue |
/openspec-continue-change |
/opsx:propose |
/openspec-propose |
/opsx:explore |
/openspec-explore |
/opsx:ff |
/openspec-ff-change |
/opsx:new |
/openspec-new-change |
Options:
- Add a
transformToSkillReferences function in src/utils/command-references.ts with the explicit mapping table above. Apply it in init.ts and update.ts when delivery === 'skills'.
- Or refactor templates to accept a reference-format parameter, emitting correct cross-references at construction time.
Reproduction
- Run
openspec init and choose delivery: 'skills'
- Inspect any generated skill, e.g.,
.claude/skills/openspec-propose/SKILL.md
- Observe
/opsx:apply in the output text — a command that was never generated
OpenSpec Bug Report: Skills-only delivery emits
/opsx:*command referencesDate: 2026-03-26
OpenSpec version: 1.2.0
Context: Discovered while auditing
.claude/files in a project configured withdelivery: 'skills'. All generated openspec-* skills contained/opsx:*cross-references pointing to commands that were never generated.Bug title
Skills-only delivery generates skill files with
/opsx:*command references instead of/openspec-*skill referencesDescription
When OpenSpec is configured with
delivery: 'skills'(skills only, no commands), the generated SKILL.md files contain hardcoded/opsx:*cross-references (e.g.,/opsx:apply,/opsx:archive,/opsx:verify). These reference commands that don't exist in a skills-only setup, creating broken workflows.Expected behavior
When
delivery: 'skills', cross-references in generated skills should use the skill namespace:/openspec-apply-change,/openspec-archive-change,/openspec-verify-change, etc.Actual behavior
All cross-references use the command namespace (
/opsx:apply,/opsx:archive, etc.) regardless of the delivery setting.Affected skills
Every skill with cross-references is affected:
openspec-propose/opsx:applyopenspec-ff-change/opsx:applyopenspec-apply-change/opsx:apply,/opsx:archiveopenspec-explore/opsx:exploreRoot cause
Skill templates hardcode
/opsx:*: The workflow template functions insrc/core/templates/workflows/*.ts(e.g.,getOpsxProposeSkillTemplate,getApplyChangeSkillTemplate) embed/opsx:*command references directly in theinstructionsstrings.No delivery-aware transformer for skills:
generateSkillContent()insrc/core/shared/skill-generation.tsaccepts atransformInstructionscallback, but:transformToHyphenCommands(for OpenCode:/opsx:→/opsx-)/opsx:*→/openspec-*)src/core/init.tsandsrc/core/update.ts, whendelivery === 'skills', no transformer is passedSuggested fix
The mapping isn't a simple regex — command short names differ from skill directory names:
/opsx:apply/openspec-apply-change/opsx:archive/openspec-archive-change/opsx:verify/openspec-verify-change/opsx:continue/openspec-continue-change/opsx:propose/openspec-propose/opsx:explore/openspec-explore/opsx:ff/openspec-ff-change/opsx:new/openspec-new-changeOptions:
transformToSkillReferencesfunction insrc/utils/command-references.tswith the explicit mapping table above. Apply it ininit.tsandupdate.tswhendelivery === 'skills'.Reproduction
openspec initand choosedelivery: 'skills'.claude/skills/openspec-propose/SKILL.md/opsx:applyin the output text — a command that was never generated