Skip to content

fix(init): use skill references for tools without a command adapter#1404

Open
clay-good wants to merge 9 commits into
mainfrom
fix/adapterless-skill-references
Open

fix(init): use skill references for tools without a command adapter#1404
clay-good wants to merge 9 commits into
mainfrom
fix/adapterless-skill-references

Conversation

@clay-good

@clay-good clay-good commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Status

Ready for review. Fixes #1155. Hardened by five rounds of independent adversarial review passes (thirteen total); full suite green locally (2,046 passed; the only failures are the 17 known environment-only zsh-installer ones covered by #1400).

What was wrong

Tools with no command adapter — Kimi Code, Mistral Vibe, Hermes, ForgeCode, CodeArts Agent — skip command generation even under the default both delivery (Commands skipped for: kimi (no adapter)). But the skills generated for them still told agents to run /opsx:apply, /opsx:archive, /opsx:continue, … — commands that were never created — and the init summary ended with Start your first change: /opsx:propose. The committed skills/ tree (the npx skills add Fission-AI/OpenSpec channel) had the same problem: it ships SKILL.md files only, yet referenced /opsx:* throughout. Reported in #1155 (the "5 commands" count from that report was already fixed on main; the references and the hint were not).

#1194 fixed this for the global delivery: skills setting, but the per-tool case (delivery both, tool has no adapter) was left out: getTransformerForTool only looked at delivery, not at the tool's command surface.

How it was fixed

  • getTransformerForTool now also takes the tool's command-surface capability (type-only import of CommandSurfaceCapability) and returns a skill-reference transform when the capability is none, honoring each tool's documented invocation syntax (Kimi Code: /skill:openspec-*; all others: /openspec-* per fix: use skill references in SKILL.md for skills-only delivery #1194). All three call sites (init + update ×2) pass resolveCommandSurfaceCapability(tool.value).
  • The init getting-started hint is derived per tool from the surface that tool actually got: command tools keep /opsx:propose, skill-only tools get their documented skill invocation (Kimi Code: /skill:openspec-propose "your idea"), and Codex — skills-invocable, no slash surface — gets a syntax-neutral line (Start your first change with the openspec-propose skill). Mixed selections print one labeled hint per distinct form (including adapter-backed + skill-only mixes like claude+kimi), so every advertised instruction is usable by the tool it names; the one-time migration message stays syntax-neutral on disagreement and no longer advertises /opsx:propose under an explicit delivery: skills. A tool that got no artifacts at all (delivery: commands + no adapter) gets a configuration correction naming it (openspec config set delivery both), even when other selected tools did generate; when nothing was generated for anyone, the hint and restart line are suppressed entirely. The restart line only claims slash commands when commands were generated (otherwise: "Restart your IDE for the new skills to take effect.").
  • The one-time profile-migration message ("New in this version: /opsx:propose") derives its reference per detected tool and stays syntax-neutral when tools disagree — including command tools mixed with skill-only tools (Claude + Kimi) and explicit delivery: skills, where /opsx:* will never exist. The legacy-upgrade getting-started menu in update does the same (a legacy Codex upgrade previously advertised the /opsx:* prompts Codex lost in feat(codex): make Codex skills-only and retire managed custom prompts #1283); command-tool upgrades keep byte-identical output.
  • scripts/generate-skillssh.mjs and its parity test apply the transform, and skills/ is regenerated — the diff there is purely the reference swap (35 lines).

Codex SKILL.md content is deliberately unchanged (skills-invocable never triggers the new branch) — #1143 owns codex reference rewriting. The shared getting-started hint does improve for codex-only setups too, since codex lost its /opsx prompts in #1283 and the old hint pointed at them.

Replication / proof

Before (clean build of main):

$ openspec init --tools kimi
6 skills in .kimi-code/
Commands skipped for: kimi (no adapter)
  Start your first change: /opsx:propose "your idea"
$ grep -rn "/opsx:" .kimi-code/skills/ | wc -l
      12

After (this branch):

$ openspec init --tools kimi
6 skills in .kimi-code/
Commands skipped for: kimi (no adapter)
  Start your first change: /skill:openspec-propose "your idea"
$ grep -rn "/opsx" .kimi-code/skills/ | wc -l
       0
$ grep -rn "/skill:openspec-" .kimi-code/skills/ | wc -l
      12
$ grep -rn "/opsx" skills/ | wc -l
       0

Regression tests: adapterless tool under default delivery gets skill references and the skill-based hint; adapter-backed tool (claude) keeps /opsx:* in both skills and hint; the kimi update-path test asserts refreshed skills contain no /opsx (mutation-verified: reverting the update.ts change now fails tests); transformer unit tests cover all three capabilities; skills.sh parity test pins the transformed output.

Notes

  • No template changes — golden-hash template parity is unaffected; the skills.sh parity test was updated alongside its generator, and the regenerated skills/ diff is reference-swaps only.
  • Verified no published-API break: the package exports only dist/index.js, which never re-exports getTransformerForTool.
  • A changeset is included (patch bump). Pre-existing issues found during review, deliberately out of scope: delivery: commands + adapterless-only tools still generates nothing (the misleading hint is now replaced with a configuration correction, but whether that delivery setting should fall back to skills for such tools is a design question — worth its own issue; openspec update in that same config silently removes the skills and reports success, also pre-existing); core-profile skills reference workflows outside the profile (affects adapter-backed tools identically); the interactive welcome screen's /opsx examples; inferDelivery treating an adapterless project's lack of commands as a skills-only preference; the summary counts line (6 skills in .codex, .kimi-code/) listing directories for tools that got nothing (toolDirs predates this PR); the hint printing /opsx:propose for hyphen-command tools (opencode/pi/oh-my-pi) whose commands are invoked as /opsx-*.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed “Getting started” and “Start your first change” hints to route to the correct command/skill invocation that matches what was actually generated.
    • Updated “Restart your IDE” and “New in this version” messaging to appear only when relevant, and to use the right /opsx-* vs /openspec-*//skill:openspec-* targets.
  • Documentation
    • Regenerated and updated OpenSpec skills and examples to consistently use openspec-*/skill:openspec-* references instead of unused /opsx:* variants.
  • Tests
    • Expanded coverage for adapterless vs adapter-backed tools, migration behavior, and skills distribution parity.

Adapterless tools (kimi, vibe, hermes, forgecode, codeartsagent, agents)
skip command generation even under the default 'both' delivery, but their
generated SKILL.md files still told agents to run /opsx:* commands that
were never created, and the init summary suggested /opsx:propose. Route
the existing skill-reference transform by command-surface capability so
these tools get /openspec-* references, and point the getting-started
hint at the skill when no selected tool got commands.

Fixes #1155

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clay-good
clay-good requested a review from TabishB as a code owner July 21, 2026 03:02
@coderabbitai

coderabbitai Bot commented Jul 21, 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

Skill and command reference transformation now accounts for each tool’s command-surface capability. Initialization, update, migration, and skills.sh generation produce skill-compatible references when commands are unavailable.

Changes

Capability-aware skill reference generation

Layer / File(s) Summary
Transformer contract and selection
src/utils/command-references.ts, src/utils/index.ts, test/utils/command-references.test.ts
getTransformerForTool accepts command-surface capability, selects skill references for adapterless tools, preserves hyphen-command handling, and tests the selection paths.
Capability-aware generation and guidance
src/core/init.ts, src/core/update.ts, src/core/migration.ts, test/core/init.test.ts, test/core/update.test.ts
Initialization, update, legacy setup, and migration pass capability information and rewrite guidance or generated skills when commands are unavailable.
Published skill output and documentation
scripts/generate-skillssh.mjs, test/core/templates/skillssh-parity.test.ts, skills/openspec-*/SKILL.md, .changeset/adapterless-skill-references.md
skills.sh generation and parity checks apply skill-reference transformation, committed skill instructions use /openspec-* routes, and the patch release describes the updated references.

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

Possibly related issues

  • Fission-AI/OpenSpec issue 1155 — Directly addresses adapterless Kimi/Vibe guidance and generated references for unavailable /opsx:* commands.

Possibly related PRs

Suggested reviewers: tabishb, alfred-openspec

Sequence Diagram(s)

sequenceDiagram
  participant InitCommand
  participant CapabilityResolver
  participant TransformerSelector
  participant SkillGenerator
  participant ConsoleOutput
  InitCommand->>CapabilityResolver: resolve tool command surface
  CapabilityResolver->>TransformerSelector: provide delivery and capability
  TransformerSelector->>SkillGenerator: select skill or command reference transformation
  SkillGenerator-->>InitCommand: generate transformed skill content
  InitCommand->>ConsoleOutput: print matching start reference
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: using skill references for tools without a command adapter.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/adapterless-skill-references

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.

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

The capability-only transform breaks Kimi’s documented invocation contract: Kimi skills use /skill:openspec-* (see docs/supported-tools.md, docs/how-commands-work.md, and docs/commands.md), but this head rewrites both generated cross-references and the getting-started hint to /openspec-*. Please make the skill-reference transform tool-specific and add an end-to-end Kimi assertion for the actual invocation syntax.

clay-good and others added 2 commits July 20, 2026 22:27
…references

- transform the committed skills.sh distribution too: pass
  transformToSkillReferences in generate-skillssh.mjs and the parity
  test, regenerate skills/ (that channel installs SKILL.md files only,
  so /opsx:* commands never exist there)
- key the getting-started hint purely on whether any selected tool got
  commands, so the delivery=commands + adapterless corner can no longer
  print /opsx:propose
- make the one-time profile-migration message capability-aware for
  projects whose detected tools have no command adapter
- import CommandSurfaceCapability type-only instead of duplicating the
  union inline (a value import would close a module cycle)
- cover the update path: the kimi migration test now asserts refreshed
  skills contain no /opsx references

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per review: the blanket /openspec-* rewrite contradicted Kimi's
documented invocation contract (/skill:openspec-*, see
docs/supported-tools.md). Skill-reference transforms are now selected
per tool via getSkillReferenceTransformer, with Kimi mapped to
/skill:<name> and every other tool keeping the documented /<name>
form; the getting-started hint and migration message use the same
per-tool syntax. End-to-end Kimi assertions cover generated skill
content, the refreshed update path, and the hint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clay-good

Copy link
Copy Markdown
Collaborator Author

Addressed in 881d893: skill-reference transforms are now selected per tool via getSkillReferenceTransformer. Kimi Code gets its documented /skill:openspec-* invocations everywhere (generated skill cross-references, the getting-started hint, and the migration message); vibe/hermes/forgecode/codeartsagent keep the /openspec-* form their docs specify. End-to-end Kimi assertions added for generated content (init), refreshed content (update path), and the hint. Verified live:

$ openspec init --tools kimi
  Start your first change: /skill:openspec-propose "your idea"
$ grep -rho "/skill:openspec-[a-z-]*" .kimi-code/skills/ | sort -u | head -2
/skill:openspec-apply-change
/skill:openspec-archive-change

Note this also fixes a pre-existing docs mismatch: under delivery: skills, Kimi previously got /openspec-* references from the blanket transform.

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

The Kimi /skill: prefix is fixed at 881d893, but the commands-only adapterless corner still prints a dead getting-started instruction. Reproduced with global delivery=commands plus openspec init --tools kimi: setup creates neither skills nor commands, then tells the user to run /skill:openspec-propose. Please gate the hint on an actually generated surface (or print a configuration correction) and add an end-to-end commands-only adapterless assertion.

Per review: with delivery=commands and only adapterless tools selected,
init generated neither skills nor commands yet still advertised an
invocation. Print a configuration correction instead, with the exact
'openspec config set delivery both' remedy, covered by an end-to-end
commands-only adapterless test. Also from the adversarial review round:
mixed selections that disagree on invocation syntax (kimi + vibe) now
fall back to the default /openspec-* form in the shared hint and
migration message instead of picking the first tool's syntax; add the
missing changeset; correct the codex doc comment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clay-good

Copy link
Copy Markdown
Collaborator Author

Addressed in 8f6d324:

  • Commands-only adapterless corner (your review): when delivery: commands is set and every selected tool lacks a command adapter, init now prints a configuration correction instead of a dead invocation hint, and no "Start your first change" line is shown. Covered by an end-to-end test (delivery=commands + --tools kimi asserts nothing is generated, no hint, and the openspec config set delivery both remedy is printed).
$ openspec init --tools kimi   # global delivery: commands
No skills or commands were generated: delivery is set to 'commands' but Kimi Code supports only skills. Run 'openspec config set delivery both' to generate skills.
  • From a parallel adversarial review round: mixed selections that disagree on invocation syntax (--tools kimi,vibe) now fall back to the default /openspec-* form in the shared hint and migration message rather than using the first tool's syntax (each tool's own SKILL.md files always keep their documented form); added the missing changeset; corrected an inaccurate code comment about codex handling.

@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 `@src/core/migration.ts`:
- Around line 215-217: Update the transformer-selection logic around
skillTransformers in migration.ts and the corresponding initialization logic in
init.ts to compare each transformer’s output for the same dummy input rather
than function identity. Use the shared transformer when all outputs agree,
including independently created closures with the same prefix; otherwise retain
the transformToSkillReferences fallback and existing command-surface behavior.

In `@test/core/init.test.ts`:
- Line 986: The delivery=commands test at test/core/init.test.ts:986-986 and the
mixed adapterless tools test at test/core/init.test.ts:1013-1013 each declare
logCalls twice consecutively; remove one duplicate declaration from each test
while retaining the single declaration used by its assertions.
🪄 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: fbf35083-deb1-46a4-ab0b-b5064d9d50bf

📥 Commits

Reviewing files that changed from the base of the PR and between 881d893 and 8f6d324.

📒 Files selected for processing (5)
  • .changeset/adapterless-skill-references.md
  • src/core/init.ts
  • src/core/migration.ts
  • src/utils/command-references.ts
  • test/core/init.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/utils/command-references.ts
  • src/core/init.ts

Comment thread src/core/migration.ts Outdated
Comment thread test/core/init.test.ts
From the third adversarial review round: the 'Restart your IDE for
slash commands' line printed directly after the message saying nothing
was generated. Gate it on an actually generated surface and pin that in
the commands-only adapterless test. Also: use randomUUID() for init
test temp dirs (matches update.test.ts, removes a theoretical Date.now
collision), and clarify the changeset wording about the skills.sh
channel's default reference form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clay-good

Copy link
Copy Markdown
Collaborator Author

Third adversarial review round complete (three independent passes: newest-commit correctness, cross-file consistency, break-nothing gate — all MERGE-SAFE/SHIP). Residual fixes in 70617b3: the 'Restart your IDE' line is now suppressed when nothing was generated (it printed directly after the configuration correction), init test temp dirs use randomUUID(), and the changeset wording clarifies the skills.sh channel uses the default /openspec-* form. The PR description's proof block was re-measured against a real build of main (12 /opsx: lines before, 0 after, 12 /skill:openspec-* after). Verified out of scope and pre-existing: dangling core-profile references (identical on main for claude), and openspec update with delivery: commands silently removing skills — both noted in the description.

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

The commands-only dead hint is fixed at 86155d0, but the new mixed-syntax fallback deliberately reintroduces an invalid instruction for Kimi. Reproduced openspec init --tools kimi,vibe: both skill trees are generated correctly, then the shared setup summary says /openspec-propose, which Vibe accepts but Kimi does not (Kimi requires /skill:openspec-propose). Please emit per-tool hints or a syntax-neutral instruction instead of choosing a form that is wrong for one configured tool; the current mixed-tool test should assert every advertised instruction is usable, not codify the fallback.

Per review: the mixed-syntax fallback advertised /openspec-propose,
which Mistral Vibe accepts but Kimi Code does not. Group successful
tools by their transformed reference and print one labeled hint line
per distinct form, so every advertised instruction is usable by the
tool it names; the mixed-tool test asserts exactly that. The migration
message compares transformed outputs instead of function identities
(also per review) and stays syntax-neutral ('the openspec-propose
skill') when detected tools disagree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clay-good

Copy link
Copy Markdown
Collaborator Author

Addressed in 36997e8:

  • Mixed-syntax hint (alfred): the fallback is gone. Successful tools are grouped by their transformed reference and init prints one labeled hint per distinct form, so every advertised instruction is usable by the tool it names. The mixed-tool test now asserts exactly that (two lines, each pinned to its tool's documented syntax, no /opsx:):
$ openspec init --tools kimi,vibe
  Start your first change: /skill:openspec-propose "your idea" (Kimi Code)
  Start your first change: /openspec-propose "your idea" (Mistral Vibe)
  • Transformer comparison (CodeRabbit, migration.ts): now compares transformed outputs rather than function identities; when detected tools disagree, the migration message stays syntax-neutral (New in this version: the openspec-propose skill.).
  • Duplicate logCalls (CodeRabbit, init.test.ts): false positive — the two declarations at lines 987 and 1016 are in two different it() blocks, each declared once per scope. A same-scope redeclaration would be a SyntaxError, and the file runs green (59/59 locally, CI green on the previous push).

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

One remaining capability mismatch: openspec init --tools codex now prints /openspec-propose even though Codex has no slash-command surface and the repo docs intentionally direct users to .codex/skills/openspec-*. I reproduced it at 36997e8; the same capability-blind branch also prints Restart your IDE for slash commands. Please make the hint syntax-neutral or Codex-specific for skills-invocable tools and pin the Codex end-to-end case.

clay-good and others added 2 commits July 21, 2026 10:00
…h surface)

Codex has no slash-command surface: docs direct users to
.codex/skills/openspec-*. The getting-started hint and the one-time
migration message now name the skill ('the openspec-propose skill')
instead of advertising a /openspec-* form Codex does not accept, and the
restart line only claims slash commands when commands were generated.

Hint lines are also limited to tools that actually got skills: under
delivery=commands, codex+kimi previously advertised /skill:openspec-propose
for Kimi while .kimi-code was never created.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adversarial-review round fixes:

- Mixed adapter-backed + skill-only selections (claude+kimi, claude+codex)
  printed a single unlabeled /opsx:propose hint that the skill-only tool
  cannot use; hints are now derived per tool from its generated surface
  and labeled when the selection disagrees.
- The delivery=commands configuration correction keyed on the global
  aggregate, so a tool that got zero artifacts lost its correction as
  soon as any other tool generated something; it is now per-tool.
- The migration message advertised /opsx:propose under an explicit
  'delivery: skills' config where commands will never exist; the command
  form is now gated on the effective delivery.
- Migration-message coverage extended (kimi, codex+kimi, delivery=skills,
  commands-installed); profile-describe init tests use randomUUID temp
  dirs like the first describe block.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clay-good

Copy link
Copy Markdown
Collaborator Author

Addressed in efda4c3 + 3f681cd:

  • Codex capability mismatch (your review): the hint is now syntax-neutral for skills-invocable tools, and the restart line only claims slash commands when commands were generated. The same fix is applied to the one-time migration message (codex-only detection previously printed /openspec-propose there too). Codex end-to-end cases are pinned: codex-only init, codex+vibe mixed labeling, codex+kimi under delivery: commands, and the codex-only migration message.
  • Went one step further on the same finding class (fourth adversarial review round): hints are now derived per tool from the surface it actually got, and the delivery: commands correction is per-tool instead of keyed on the global aggregate — previously --tools claude,kimi with delivery: commands gave Kimi zero artifacts, no correction, and a dead /opsx:propose instruction. Mixed adapter+skill-only selections (claude+kimi, claude+codex) now label each line. The migration message also stops advertising /opsx:propose under an explicit delivery: skills.

Real output on this head (delivery: both unless noted):

$ openspec init --tools codex
  Start your first change with the openspec-propose skill
Restart your IDE for the new skills to take effect.

$ openspec init --tools claude,codex
  Start your first change: /opsx:propose "your idea" (Claude Code)
  Start your first change with the openspec-propose skill (Codex)
Restart your IDE for slash commands to take effect.

$ openspec init --tools codex,kimi,vibe
  Start your first change with the openspec-propose skill (Codex)
  Start your first change: /skill:openspec-propose "your idea" (Kimi Code)
  Start your first change: /openspec-propose "your idea" (Mistral Vibe)

$ openspec config set delivery commands && openspec init --tools claude,kimi
No skills or commands were generated for Kimi Code: delivery is set to 'commands' but it supports only skills. Run 'openspec config set delivery both' to generate skills.
  Start your first change: /opsx:propose "your idea"

Codex SKILL.md content remains byte-identical to main (still owned by #1143). Full suite green except the 17 known environment-only zsh-installer failures (#1400); lint and typecheck clean. The CodeRabbit duplicate-logCalls thread was a false positive (two separate it() blocks) — replied and resolved.

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

The Codex hint is fixed and the expanded init coverage passes, but the one-time migration path still collapses mixed command and skill-only tools to the command form. I reproduced a project with Claude commands plus a Kimi openspec-propose skill at 3f681cd: migrateIfNeeded prints only /opsx:propose, which Kimi cannot invoke, despite the changeset and code comment promising usable guidance when detected tools disagree. Please make the migration message syntax-neutral or per-tool for mixed command-surface selections and add the Claude plus Kimi regression case.

…surface

The one-time migration message collapsed mixed command + skill-only
selections to /opsx:propose (Claude commands + a Kimi skill told the
Kimi user to run a command it cannot invoke); the reference is now
computed per detected tool and falls back to the syntax-neutral form on
disagreement. The legacy-upgrade getting-started menu had the same
capability blindness with hard-coded /opsx:new/continue/apply — a legacy
Codex upgrade advertised commands Codex lost in #1283; menu lines are
now derived the same way (byte-identical for command-tool upgrades).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clay-good

Copy link
Copy Markdown
Collaborator Author

Addressed in f5c2de1:

  • Mixed command + skill-only migration (your review): the propose reference is now derived per detected tool — /opsx:propose only for tools whose commands will exist under the effective delivery, the documented skill invocation for skill-only tools — and the shared message goes syntax-neutral when they disagree. Your exact repro (Claude commands + Kimi openspec-propose skill, pre-profile config):
$ openspec update --force
Migrated: custom profile with 1 workflows
New in this version: the openspec-propose skill. Try 'openspec config profile core' for the streamlined experience.

Claude-only still prints /opsx:propose; kimi-only prints /skill:openspec-propose. Regression tests pin claude+kimi (your ask), claude commands-installed, kimi-only, codex-only, codex+kimi, and explicit delivery: skills.

  • Same class, one surface further: the legacy-upgrade "Getting started" menu in update hard-coded /opsx:new//opsx:continue//opsx:apply. A legacy Codex upgrade (managed opsx-*.md prompt in $CODEX_HOME/prompts with codex unconfigured) advertised the very prompts Codex lost in feat(codex): make Codex skills-only and retire managed custom prompts #1283. Menu lines are now derived per newly configured tool with the same rules:
$ openspec update --force   # legacy Codex prompt detected, codex newly configured
Getting started:
  the openspec-new-change skill       Start a new change
  the openspec-continue-change skill  Create the next artifact
  the openspec-apply-change skill     Implement tasks

Command-tool legacy upgrades (claude, cursor, …) keep byte-identical output — verified with cat -ve against the old hard-coded lines. That was the last hard-coded /opsx:* instruction outside the pre-selection welcome screen; a sweep of every printed instruction surface (init, update, migration, legacy-cleanup summaries, doctor/config) found no other capability-blind reference. Full suite green except the 17 known environment-only zsh-installer failures (#1400); lint and typecheck clean.

@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-review at f5c2de1: mixed command and skill-only migration guidance now falls back to a syntax-neutral skill reference, and the legacy Codex upgrade menu uses the same capability-aware contract. I reproduced the Claude plus Kimi case successfully; 218 focused tests, clean skill regeneration, build, and the full exact-head CI and CodeQL matrix pass.

clay-good added a commit that referenced this pull request Jul 21, 2026
Addresses alfred's review: the legacy-upgrade hint pinned a dead Codex
instruction. resolveCommandSurfaceCapability('codex') is 'skills-invocable',
so shouldGenerateCommandsForTool is false for every delivery mode and Codex
never receives an /opsx:* file. Skills-only delivery does the same for every
tool. Both cases were still told to run /opsx:<workflow>.

labelOnboardingCommand() renders a hint the configured tools can actually
invoke, falling back to the skill name via the existing
transformToSkillReferences. Applied to the `update` legacy-upgrade summary
and the `init` completion hint, which both know their tools.

Left alone deliberately: the welcome screen renders before tool selection
and its two-column layout cannot fit skill names (70 cols against a 59
budget); and tool-specific skill syntax (Kimi's /skill: prefix) belongs to
getSkillReferenceTransformer in #1404, which this does not duplicate.
clay-good added a commit that referenced this pull request Jul 21, 2026
Fixes #1409. The `openspec init` welcome screen and the `openspec update`
legacy-upgrade menu hardcoded /opsx:new and /opsx:continue. The default core
profile is propose/explore/apply/update/sync/archive, so it never generates
them and users were told to run commands that did not exist.

getOnboardingCommands() holds the hints in lifecycle order and returns only
those whose workflow is installed; both surfaces print its result. In
`update` the set is what the newly configured tools actually received, since
a legacy upgrade installs an inferred subset for Codex.

Stacked on #1404, which decides how each hint is spelled per tool. This
commit decides which hints appear; #1404's referenceFor/printStartHints
decide the reference form, so Kimi still gets /skill:openspec-*.

The welcome screen's quick-start block is width-constrained: it renders
beside a 24-column art column and only animates at MIN_WIDTH (60) or wider,
and the animation moves the cursor up a fixed count of logical lines. A
wrapped line desyncs it, so descriptions are capped at DESCRIPTION_BUDGET
and a test asserts no rendered line exceeds 59.

Also validates --profile before the welcome screen rather than casting it,
so an invalid value fails before the user presses Enter.
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.

Kimi/Vibe 1.4.0 init generates skills that still reference /opsx commands

2 participants