Skip to content

fix: use skill references in SKILL.md for skills-only delivery#1194

Merged
clay-good merged 7 commits into
Fission-AI:mainfrom
mc856:fix/skills-only-references
Jul 18, 2026
Merged

fix: use skill references in SKILL.md for skills-only delivery#1194
clay-good merged 7 commits into
Fission-AI:mainfrom
mc856:fix/skills-only-references

Conversation

@mc856

@mc856 mc856 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #881, closes #879.

When delivery: 'skills' is configured, generated SKILL.md files contained hardcoded /opsx:* command references pointing to commands that were never generated. This implements the fix outlined in #881: adds transformToSkillReferences() with the explicit 11-entry command-to-skill mapping and wires it at every generateSkillContent call site — init.ts, both sites in update.ts (including upgradeLegacyTools), and both sites in workspace/skills.ts.

Deviations from the issue snapshot

  • Kept the existing pi branch in the transformer condition. The issue snippet only checks opencode, but main already routes pi through transformToHyphenCommands; copying the snippet verbatim would regress pi.
  • workspace/skills.ts wired in addition to the files listed in the issue. It generates SKILL.md from the same globalConfig.delivery and is itself a skills-only surface, so the bug persisted there. Regression test included (verified to fail against the unwired code).
  • Note: WORKFLOW_TO_SKILL_DIR exists in both init.ts (local copy) and profile-sync-drift.ts (exported); the two are identical and COMMAND_TO_SKILL_REFERENCE matches both.

Open question for maintainers

In skills-only mode, opencode/pi still take the transformToHyphenCommands branch, so their SKILL.md files contain /opsx-* references to commands that were also never generated — same class of bug. I didn't expand scope because it's unclear whether /openspec-<skill> slash references resolve in those tools. Happy to file a follow-up issue. The legacy-upgrade path also lacks a skills-only content assertion; same offer.

Testing

  • npx eslint src/ clean
  • transformToSkillReferences unit tests: per-mapping assertions for all 11 commands, multi-reference, backtick, unknown-command, and bulk-archive/archive boundary cases
  • Integration: init + update skills-only cases assert generated SKILL.md contains no /opsx: and does contain /openspec- (explore template verified to contain /opsx: references, so the assertion is discriminative); new workspace test mutation-verified
  • Full vitest suite passing

Generated with Claude (Cowork) using claude-fable-5.

Summary by CodeRabbit

  • Bug Fixes
    • Skill setup and update flows now generate the correct command/skill references for skills-only delivery.
    • Generated SKILL.md files no longer include unsupported /opsx: markers and instead link to the expected /openspec- skill references.
    • Reference rewriting is now chosen consistently by delivery mode, improving output across supported tools.
  • Tests
    • Expanded coverage to assert the correct reference markers in init and update SKILL.md outputs, plus command reference transformation behavior.

@mc856
mc856 requested a review from TabishB as a code owner June 10, 2026 03:27
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds delivery-aware reference transformation for skills-only delivery, wires it into init and update SKILL.md generation, re-exports the helpers, and expands unit and integration coverage.

Changes

Skills-Only Delivery Reference Transformation

Layer / File(s) Summary
Skill reference transformer utility
src/utils/command-references.ts, src/utils/index.ts, .changeset/skills-only-references.md
Maps /opsx:<command> tokens to /openspec-* references, selects transformers by tool and delivery, re-exports the utilities, and documents the patch.
Core module transformer wiring
src/core/init.ts, src/core/update.ts
Init and update pass delivery-aware transformers into SKILL.md generation in main and legacy setup paths.
Transformer and SKILL.md tests
test/utils/command-references.test.ts, test/core/init.test.ts, test/core/update.test.ts
Tests reference conversion, transformer selection, and generated skills-only SKILL.md content.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant InitCommand
  participant UpdateCommand
  participant getTransformerForTool
  participant generateSkillContent
  InitCommand->>getTransformerForTool: resolve transformer(tool.value, delivery)
  getTransformerForTool-->>InitCommand: return delivery-appropriate transformer
  InitCommand->>generateSkillContent: generate transformed SKILL.md
  UpdateCommand->>getTransformerForTool: resolve transformer(tool.value, delivery)
  getTransformerForTool-->>UpdateCommand: return delivery-appropriate transformer
  UpdateCommand->>generateSkillContent: generate transformed SKILL.md
Loading

Possibly related PRs

Suggested reviewers: tabishb

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: using skill references in SKILL.md for skills-only delivery.
Linked Issues check ✅ Passed The PR implements the required skill-reference mapping, wires it into init/update flows, and adds tests for skills-only delivery.
Out of Scope Changes check ✅ Passed The extra changes are limited to tests, docs, and a changeset note, which are all directly supportive of the fix.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
src/utils/command-references.ts (1)

22-26: ⚖️ Poor tradeoff

Sync burden: mapping duplicated across files.

The comment warns that COMMAND_TO_SKILL_REFERENCE must stay in sync with WORKFLOW_TO_SKILL_DIR in two other locations. This creates a maintenance risk: if one copy is updated without updating the others, skill references will break at runtime. Consider consolidating these mappings into a single source of truth (e.g., exporting WORKFLOW_TO_SKILL_DIR from a shared module and deriving the skill reference map from it).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/command-references.ts` around lines 22 - 26, The duplicate mapping
risk: consolidate the source of truth by exporting WORKFLOW_TO_SKILL_DIR from a
single shared module and derive COMMAND_TO_SKILL_REFERENCE from that exported
mapping instead of maintaining separate copies; update code that currently
defines COMMAND_TO_SKILL_REFERENCE (and the local copies of
WORKFLOW_TO_SKILL_DIR) to import the shared WORKFLOW_TO_SKILL_DIR and build the
command-to-skill map (e.g., compute COMMAND_TO_SKILL_REFERENCE by mapping
keys/values from WORKFLOW_TO_SKILL_DIR) so only one mapping needs to be
maintained.
src/core/init.ts (1)

540-546: ⚡ Quick win

Extract duplicated transformer selection logic into a helper function.

The transformer selection conditional appears identically in 5 locations across 3 files. This violates DRY and creates maintenance risk: if the logic needs to change (e.g., adding a new delivery mode or tool-specific behavior), all 5 sites must be updated consistently.

Extract this logic into a shared helper function in src/utils/command-references.ts:

♻️ Proposed refactor
/**
 * Selects the appropriate command-reference transformer based on tool and delivery mode.
 * `@param` toolId - The AI tool identifier (e.g., 'claude', 'opencode', 'pi')
 * `@param` delivery - The delivery mode ('skills', 'commands', or 'both')
 * `@returns` The transformer function or undefined
 */
export function getTransformerForTool(
  toolId: string,
  delivery: 'skills' | 'commands' | 'both'
): ((text: string) => string) | undefined {
  if (toolId === 'opencode' || toolId === 'pi') {
    return transformToHyphenCommands;
  }
  if (delivery === 'skills') {
    return transformToSkillReferences;
  }
  return undefined;
}

Then replace each of the 5 duplicated blocks with:

const transformer = getTransformerForTool(tool.value, delivery);
// or for workspace/skills.ts:
const transformer = getTransformerForTool(tool.value, profileContext.delivery);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/init.ts` around lines 540 - 546, Duplicate transformer-selection
logic used in multiple places should be pulled into a helper; create a function
getTransformerForTool(toolId: string, delivery: 'skills' | 'commands' | 'both')
that returns transformToHyphenCommands when toolId === 'opencode' || toolId ===
'pi', returns transformToSkillReferences when delivery === 'skills', and
otherwise returns undefined, then replace the inline conditional in
src/core/init.ts (the const transformer assignment) and the four other
occurrences with calls to getTransformerForTool(tool.value, delivery) (or
getTransformerForTool(tool.value, profileContext.delivery) where appropriate) so
all sites use the single shared implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/core/init.ts`:
- Around line 540-546: Duplicate transformer-selection logic used in multiple
places should be pulled into a helper; create a function
getTransformerForTool(toolId: string, delivery: 'skills' | 'commands' | 'both')
that returns transformToHyphenCommands when toolId === 'opencode' || toolId ===
'pi', returns transformToSkillReferences when delivery === 'skills', and
otherwise returns undefined, then replace the inline conditional in
src/core/init.ts (the const transformer assignment) and the four other
occurrences with calls to getTransformerForTool(tool.value, delivery) (or
getTransformerForTool(tool.value, profileContext.delivery) where appropriate) so
all sites use the single shared implementation.

In `@src/utils/command-references.ts`:
- Around line 22-26: The duplicate mapping risk: consolidate the source of truth
by exporting WORKFLOW_TO_SKILL_DIR from a single shared module and derive
COMMAND_TO_SKILL_REFERENCE from that exported mapping instead of maintaining
separate copies; update code that currently defines COMMAND_TO_SKILL_REFERENCE
(and the local copies of WORKFLOW_TO_SKILL_DIR) to import the shared
WORKFLOW_TO_SKILL_DIR and build the command-to-skill map (e.g., compute
COMMAND_TO_SKILL_REFERENCE by mapping keys/values from WORKFLOW_TO_SKILL_DIR) so
only one mapping needs to be maintained.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9c67c585-1070-4587-8421-be46f4b1dcbb

📥 Commits

Reviewing files that changed from the base of the PR and between 1b06fdd and 45f3e56.

📒 Files selected for processing (10)
  • .changeset/skills-only-references.md
  • src/core/init.ts
  • src/core/update.ts
  • src/core/workspace/skills.ts
  • src/utils/command-references.ts
  • src/utils/index.ts
  • test/core/init.test.ts
  • test/core/update.test.ts
  • test/core/workspace/skills.test.ts
  • test/utils/command-references.test.ts

@mc856

mc856 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 4ef4c48 addressing the CodeRabbit review: extracted the duplicated transformer selection into getTransformerForTool() in command-references.ts (with JSDoc and unit tests locking the selection matrix), replacing all five call sites.

On consolidating the WORKFLOW_TO_SKILL_DIR copies: agreed in principle, but deriving the map in src/utils from src/core/profile-sync-drift.ts would invert the utils ← core layering, and moving the canonical map into utils touches profile-sync-drift.ts typing and init.ts beyond this bugfix's scope. Happy to do it as a follow-up PR if maintainers agree.

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for tightening this up. The Claude/init/update/workspace path is in much better shape, but I found one remaining skills-only edge case before this can merge.

getTransformerForTool() currently returns transformToHyphenCommands for OpenCode and Pi before it checks delivery === 'skills'. That means delivery: 'skills' still generates OpenCode/Pi SKILL.md files that point at /opsx-* commands even though command files were removed or never generated. For skills-only delivery, the missing-command fix needs to win for every tool, including OpenCode and Pi. Please make delivery === 'skills' return skill references first, then keep the hyphen transform for OpenCode/Pi when commands are actually generated, and add focused coverage for those two tools.

Checked: focused command-reference/init/update/workspace tests pass locally.

@mc856

mc856 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Done in 8c66688delivery === 'skills' now wins for every tool: getTransformerForTool checks skills-only delivery first and only falls back to the hyphen transform for opencode/pi when commands are actually generated. Added unit coverage for the opencode/pi selection matrix and an opencode skills-only init integration test asserting the generated SKILL.md contains no /opsx: or /opsx- references. This also closes out the open question from the PR description — thanks for the call.

@mc856
mc856 requested a review from alfred-openspec June 12, 2026 02:22

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving latest head. I verified the skills-only transformer now wins for every tool, including OpenCode/Pi, and init/update/workspace skill generation have focused regression coverage. Targeted install, tsc, lint on src, and the relevant Vitest suites all pass.

@mc856

mc856 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@alfred-openspec I rebased this onto the latest upstream main and resolved the merge conflict; GitHub now reports it as mergeable and CodeRabbit is green again. The previous approval was marked stale after the force-push, so could you please re-confirm when you have a chance?

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-approved after the rebase. I rechecked the diff: skills-only delivery now emits skill references for all tools, OpenCode/Pi precedence is covered, and the affected init/update paths plus transformer helper have focused regression tests. Verified locally with install, tsc, eslint on src, and targeted Vitest suites.

mc856 added 5 commits July 13, 2026 03:00
When delivery is configured as 'skills', generated SKILL.md files
contained hardcoded /opsx:* command references pointing to commands
that were never generated, breaking cross-skill workflows.

Add transformToSkillReferences() with the explicit command-to-skill
mapping (kept in sync with WORKFLOW_TO_SKILL_DIR) and wire it in
init and update wherever skill content is generated, following the
approach outlined in Fission-AI#881.

Closes Fission-AI#881
Closes Fission-AI#879

Generated with Claude (Cowork) using claude-fable-5; verified with the
full vitest suite (1683 tests passing).
Review follow-up for the skills-only delivery fix: workspace skill
setup (src/core/workspace/skills.ts) generates SKILL.md via the same
generateSkillContent path but was not wired with
transformToSkillReferences, leaving dangling /opsx:* references when
delivery is 'skills'. Wire both call sites, add a regression test
(verified to fail against the unwired code), strengthen the update
skills-only test with content assertions, and correct the
COMMAND_TO_SKILL_REFERENCE comment (WORKFLOW_TO_SKILL_DIR exists in
both profile-sync-drift.ts and init.ts).

Generated with Claude (Cowork) using claude-fable-5; verified with
eslint and targeted vitest suites (144 tests passing).
…rTool

Address CodeRabbit review: the tool/delivery transformer selection was
duplicated at five call sites across init.ts, update.ts, and
workspace/skills.ts. Extract it into a documented helper in
command-references.ts with unit tests locking the selection matrix
(opencode/pi precedence, skills-only delivery, default).

Generated with Claude (Cowork) using claude-fable-5; verified with
eslint, tsc, and targeted vitest suites (147 tests passing).
…ls-only delivery

Address review: getTransformerForTool returned transformToHyphenCommands
for opencode/pi before checking delivery, so skills-only delivery still
emitted /opsx-* references to commands that were never generated. Check
delivery === 'skills' first so skill references win for every tool, and
keep the hyphen transform for opencode/pi only when commands are
generated. Add unit coverage for the opencode/pi selection matrix and an
opencode skills-only init integration test asserting no /opsx: or /opsx-
references remain.

Generated with Claude (Cowork) using claude-fable-5; verified with
eslint, tsc, and targeted vitest suites (148 tests passing).

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/core/init.test.ts`:
- Around line 746-750: Update the Claude skillContent assertions in the test to
also reject references containing "/opsx-" alongside the existing "/opsx:"
check, matching the OpenCode case while preserving the "/openspec-" expectation.

In `@test/core/update.test.ts`:
- Around line 1490-1496: Update the skillContent assertions in the update test
to reject both legacy reference formats, adding coverage for `/opsx-` alongside
the existing `/opsx:` check while preserving the `/openspec-` expectation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 498aa762-dc4e-4381-a593-1bacac251d92

📥 Commits

Reviewing files that changed from the base of the PR and between 3e62cf9 and 3c8c30a.

📒 Files selected for processing (8)
  • .changeset/skills-only-references.md
  • src/core/init.ts
  • src/core/update.ts
  • src/utils/command-references.ts
  • src/utils/index.ts
  • test/core/init.test.ts
  • test/core/update.test.ts
  • test/utils/command-references.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • .changeset/skills-only-references.md
  • src/utils/index.ts
  • src/utils/command-references.ts
  • src/core/init.ts
  • test/utils/command-references.test.ts
  • src/core/update.ts

Comment thread test/core/init.test.ts
Comment thread test/core/update.test.ts
@mc856

mc856 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

I rebased this onto the latest upstream main and resolved the merge conflicts from the v1.6.0 changes — the transformer selection now also covers the newly added oh-my-pi tool, with matching test coverage. GitHub reports the PR as mergeable again. I also added docstrings to the touched entry points to clear the docstring coverage warning. @alfred-openspec the rebase marked your approval as stale — could you re-confirm when you get a chance?

@clay-good

Copy link
Copy Markdown
Collaborator

Nice fix, and the opencode/pi precedence is now handled correctly. One gap before this is complete:

The new COMMAND_TO_SKILL_REFERENCE map is missing the update command. It has 11 entries, but the canonical WORKFLOW_TO_SKILL_DIR (which the map's own comment says to stay in sync with) has 12 — it also includes update.

Why it matters: update is a core workflow, so openspec-update-change/SKILL.md is generated by default, and that template references /opsx:update (src/core/templates/workflows/update-change.ts:104). In skills-only mode the transformer leaves unknown commands untouched, so that skill still ships a broken /opsx:update reference — the exact bug this PR fixes, just for one more command.

The current tests miss it because they only assert against the explore skill, which has no /opsx:update.

Suggested fix:

  • Add 'update': '/openspec-update-change', to COMMAND_TO_SKILL_REFERENCE.
  • Add an assertion against the openspec-update-change skill (or any skill containing an update reference) so not.toContain('/opsx:') would catch a future omission.

Everything else looks good to go.

COMMAND_TO_SKILL_REFERENCE was missing the update workflow, so a
/opsx:update reference in any skill template would survive skills-only
transformation untouched. Align the map with the canonical 12-entry
WORKFLOW_TO_SKILL_DIR and assert the generated openspec-update-change
skill carries no raw command references.
@mc856

mc856 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Good catch — added the update entry in bb81a67, so the map now mirrors all 12 entries of WORKFLOW_TO_SKILL_DIR. One note: the skill variant of update-change drops the /opsx:update self-reference (only the command template at update-change.ts:104 carries it), so no generated skill currently ships the raw reference — the gap was latent. Covered it anyway: a unit test asserting the /opsx:update mapping, plus not.toContain('/opsx:') assertions on the generated openspec-update-change skill in both the init and update suites, so a future template that does reference update can't ship untransformed.

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified at bb81a67: the skill-reference map now matches all 12 canonical workflows, including update, and skills-only delivery wins over hyphen command references for every tool. The 172 focused transformer, init, and update tests pass locally, and the full cross-platform CI suite is green.

@clay-good
clay-good added this pull request to the merge queue Jul 18, 2026
Merged via the queue into Fission-AI:main with commit b7c85c7 Jul 18, 2026
11 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.

[Fix] Add transformToSkillReferences for skills-only delivery mode [Bug] Skills-only delivery emits /opsx:* command references

3 participants