Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion scripts/generate-skillssh.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';

import { getSkillTemplates, generateSkillContent } from '../dist/core/shared/skill-generation.js';
import { transformToSkillReferences } from '../dist/utils/command-references.js';
import {
cleanSkillSubdirectories,
prepareSkillDirectory,
Expand All @@ -33,7 +34,11 @@ cleanSkillSubdirectories(outDir);

let count = 0;
for (const { template, dirName } of getSkillTemplates()) {
const content = stripVolatileFrontmatter(generateSkillContent(template, 'skills.sh'));
// skills.sh installs SKILL.md files only — no /opsx:* commands exist in
// that channel, so references must point at the skills themselves.
const content = stripVolatileFrontmatter(
generateSkillContent(template, 'skills.sh', transformToSkillReferences)
);
const skillDir = prepareSkillDirectory(outDir, dirName);
writeFileSync(join(skillDir, 'SKILL.md'), content, 'utf8');
count++;
Expand Down
2 changes: 1 addition & 1 deletion skills/openspec-apply-change/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Implement tasks from an OpenSpec change.
- Auto-select if only one active change exists
- If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select

Always announce: "Using change: <name>" and how to override (e.g., `/opsx:apply <other>`).
Always announce: "Using change: <name>" and how to override (e.g., `/openspec-apply-change <other>`).

2. **Check status to understand the schema**
```bash
Expand Down
2 changes: 1 addition & 1 deletion skills/openspec-explore/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ You: [reads codebase]

**User is stuck mid-implementation:**
```
User: /opsx:explore add-auth-system
User: /openspec-explore add-auth-system
The OAuth integration is more complex than expected

You: [reads change artifacts]
Expand Down
2 changes: 1 addition & 1 deletion skills/openspec-ff-change/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ After completing all artifacts, summarize:
- Change name and location
- List of artifacts created with brief descriptions
- What's ready: "All artifacts created! Ready for implementation."
- Prompt: "Run `/opsx:apply` or ask me to implement to start working on the tasks."
- Prompt: "Run `/openspec-apply-change` or ask me to implement to start working on the tasks."

**Artifact Creation Guidelines**

Expand Down
44 changes: 22 additions & 22 deletions skills/openspec-onboard/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ openspec --version 2>&1 || echo "CLI_NOT_INSTALLED"
```

**If CLI not installed:**
> OpenSpec CLI is not installed. Install it first, then come back to `/opsx:onboard`.
> OpenSpec CLI is not installed. Install it first, then come back to `/openspec-onboard`.

Stop here if not installed.

Expand Down Expand Up @@ -154,7 +154,7 @@ Spend 1-2 minutes investigating the relevant code:
│ [Optional: ASCII diagram if helpful] │
└─────────────────────────────────────────┘

Explore mode (`/opsx:explore`) is for this kind of thinking—investigating before implementing. You can use it anytime you need to think through a problem.
Explore mode (`/openspec-explore`) is for this kind of thinking—investigating before implementing. You can use it anytime you need to think through a problem.

Now let's create a change to hold our work.
```
Expand Down Expand Up @@ -470,25 +470,25 @@ This same rhythm works for any size change—a small fix or a major feature.

| Command | What it does |
|-------------------|--------------------------------------------|
| `/opsx:propose` | Create a change and generate all artifacts |
| `/opsx:explore` | Think through problems before/during work |
| `/opsx:apply` | Implement tasks from a change |
| `/opsx:archive` | Archive a completed change |
| `/openspec-propose` | Create a change and generate all artifacts |
| `/openspec-explore` | Think through problems before/during work |
| `/openspec-apply-change` | Implement tasks from a change |
| `/openspec-archive-change` | Archive a completed change |

**Additional commands:**

| Command | What it does |
|--------------------|----------------------------------------------------------|
| `/opsx:new` | Start a new change, step through artifacts one at a time |
| `/opsx:continue` | Continue working on an existing change |
| `/opsx:ff` | Fast-forward: create all artifacts at once |
| `/opsx:verify` | Verify implementation matches artifacts |
| `/openspec-new-change` | Start a new change, step through artifacts one at a time |
| `/openspec-continue-change` | Continue working on an existing change |
| `/openspec-ff-change` | Fast-forward: create all artifacts at once |
| `/openspec-verify-change` | Verify implementation matches artifacts |

---

## What's Next?

Try `/opsx:propose` on something you actually want to build. You've got the rhythm now!
Try `/openspec-propose` on something you actually want to build. You've got the rhythm now!
```

---
Expand All @@ -503,8 +503,8 @@ If the user says they need to stop, want to pause, or seem disengaged:
No problem! Your change is saved at the `changeRoot` reported by `openspec status --change "<name>" --json`.

To pick up where we left off later:
- `/opsx:continue <name>` - Resume artifact creation
- `/opsx:apply <name>` - Jump to implementation (if tasks exist)
- `/openspec-continue-change <name>` - Resume artifact creation
- `/openspec-apply-change <name>` - Jump to implementation (if tasks exist)

The work won't be lost. Come back whenever you're ready.
```
Expand All @@ -522,21 +522,21 @@ If the user says they just want to see the commands or skip the tutorial:

| Command | What it does |
|--------------------------|--------------------------------------------|
| `/opsx:propose <name>` | Create a change and generate all artifacts |
| `/opsx:explore` | Think through problems (no code changes) |
| `/opsx:apply <name>` | Implement tasks |
| `/opsx:archive <name>` | Archive when done |
| `/openspec-propose <name>` | Create a change and generate all artifacts |
| `/openspec-explore` | Think through problems (no code changes) |
| `/openspec-apply-change <name>` | Implement tasks |
| `/openspec-archive-change <name>` | Archive when done |

**Additional commands:**

| Command | What it does |
|---------------------------|-------------------------------------|
| `/opsx:new <name>` | Start a new change, step by step |
| `/opsx:continue <name>` | Continue an existing change |
| `/opsx:ff <name>` | Fast-forward: all artifacts at once |
| `/opsx:verify <name>` | Verify implementation |
| `/openspec-new-change <name>` | Start a new change, step by step |
| `/openspec-continue-change <name>` | Continue an existing change |
| `/openspec-ff-change <name>` | Fast-forward: all artifacts at once |
| `/openspec-verify-change <name>` | Verify implementation |

Try `/opsx:propose` to start your first change.
Try `/openspec-propose` to start your first change.
```

Exit gracefully.
Expand Down
4 changes: 2 additions & 2 deletions skills/openspec-propose/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ I'll create a change with artifacts:
- design.md (how)
- tasks.md (implementation steps)

When ready to implement, run /opsx:apply
When ready to implement, run /openspec-apply-change

---

Expand Down Expand Up @@ -93,7 +93,7 @@ After completing all artifacts, summarize:
- Change name and location
- List of artifacts created with brief descriptions
- What's ready: "All artifacts created! Ready for implementation."
- Prompt: "Run `/opsx:apply` or ask me to implement to start working on the tasks."
- Prompt: "Run `/openspec-apply-change` or ask me to implement to start working on the tasks."

**Artifact Creation Guidelines**

Expand Down
16 changes: 8 additions & 8 deletions skills/openspec-update-change/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Revise a change's existing planning artifacts and keep them coherent. Never edit
- Read the artifact(s) the request touches and the change's other existing artifacts.
- Apply the requested edit. Then check every other existing artifact against it - in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
- Note everything that is now inconsistent, missing, or contradictory.
- Revise only files that already exist (`existingOutputPaths`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and point the user to `/opsx:continue` to create them.
- Revise only files that already exist (`existingOutputPaths`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and point the user to `/openspec-continue-change` to create them.
- If the change is already coherent, say so and make no edits.

5. **Confirm and apply, one artifact at a time**
Expand All @@ -65,21 +65,21 @@ Revise a change's existing planning artifacts and keep them coherent. Never edit
```

6. **Point to the next step (guidance only - NEVER act on it)**
- Artifacts still missing -> suggest `/opsx:continue` to create them.
- Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; suggest `/opsx:apply` to carry the delta into code.
- Everything done and implemented -> suggest `/opsx:archive`.
- Artifacts still missing -> suggest `/openspec-continue-change` to create them.
- Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; suggest `/openspec-apply-change` to carry the delta into code.
- Everything done and implemented -> suggest `/openspec-archive-change`.

**Output**

After each invocation, show:
- Which artifacts were revised (and which proposed revisions were rejected)
- Anything deferred to `/opsx:continue` (not-yet-created artifacts or files)
- Anything deferred to `/openspec-continue-change` (not-yet-created artifacts or files)
- Where the change stands and the recommended next command

**Guardrails**
- Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, stop and point to `/opsx:apply`.
- Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, stop and point to `/openspec-apply-change`.
- Use the artifact ids and paths reported by `openspec status`; never branch on hardcoded artifact names.
- Edit only the concrete files in `existingOutputPaths`; never write to a glob `resolvedOutputPath`.
- Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is `/opsx:continue`'s job.
- Do not advance the build frontier: no new artifacts, no new files under glob artifacts - that is `/openspec-continue-change`'s job.
- Confirm every edit with the user before writing.
- If the request changes the change's *intent* rather than refining it, recommend starting fresh with `/opsx:new` (the "Update vs. Start Fresh" heuristic).
- If the request changes the change's *intent* rather than refining it, recommend starting fresh with `/openspec-new-change` (the "Update vs. Start Fresh" heuristic).
16 changes: 12 additions & 4 deletions src/core/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { createRequire } from 'module';
import { FileSystemUtils } from '../utils/file-system.js';
import { classifyOpenSpecDir, storePointerProblem } from './project-config.js';
import { findRepoPlanningRootSync } from './planning-home.js';
import { getTransformerForTool } from '../utils/command-references.js';
import { getSkillReferenceTransformer, getTransformerForTool } from '../utils/command-references.js';
import {
AI_TOOLS,
OPENSPEC_DIR_NAME,
Expand Down Expand Up @@ -689,7 +689,7 @@ export class InitCommand {
const skillFile = path.join(skillDir, 'SKILL.md');

// Generate SKILL.md content with YAML frontmatter including generatedBy
const transformer = getTransformerForTool(tool.value, delivery);
const transformer = getTransformerForTool(tool.value, delivery, resolveCommandSurfaceCapability(tool.value));
const skillContent = generateSkillContent(template, OPENSPEC_VERSION, transformer);

// Write the skill file
Expand Down Expand Up @@ -868,13 +868,21 @@ export class InitCommand {
const globalCfg = getGlobalConfig();
const activeProfile: Profile = (this.profileOverride as Profile) ?? globalCfg.profile ?? 'core';
const activeWorkflows = [...getProfileWorkflows(activeProfile, globalCfg.workflows)];
// When no tool got /opsx:* commands, point at the skill instead of a
// command that does not exist.
const activeDelivery: Delivery = globalCfg.delivery ?? 'both';
const skillsOnlyHint =
successfulTools.length > 0 &&
!successfulTools.some((tool) => shouldGenerateCommandsForTool(tool.value, activeDelivery));
const startReference = (command: string) =>
skillsOnlyHint ? getSkillReferenceTransformer(successfulTools[0].value)(command) : command;
console.log();
if (activeWorkflows.includes('propose')) {
console.log(chalk.bold('Getting started:'));
console.log(' Start your first change: /opsx:propose "your idea"');
console.log(` Start your first change: ${startReference('/opsx:propose')} "your idea"`);
} else if (activeWorkflows.includes('new')) {
console.log(chalk.bold('Getting started:'));
console.log(' Start your first change: /opsx:new "your idea"');
console.log(` Start your first change: ${startReference('/opsx:new')} "your idea"`);
} else {
console.log("Done. Run 'openspec config profile' to configure your workflows.");
}
Expand Down
9 changes: 8 additions & 1 deletion src/core/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getGlobalConfig, getGlobalConfigPath, saveGlobalConfig, type Delivery }
import { CommandAdapterRegistry } from './command-generation/index.js';
import { WORKFLOW_TO_SKILL_DIR } from './profile-sync-drift.js';
import { ALL_WORKFLOWS } from './profiles.js';
import { getSkillReferenceTransformer } from '../utils/command-references.js';
import path from 'path';
import * as fs from 'fs';

Expand Down Expand Up @@ -207,5 +208,11 @@ export function migrateIfNeeded(projectPath: string, tools: AIToolOption[]): voi
saveGlobalConfig(config);

console.log(`Migrated: custom profile with ${installedWorkflows.length} workflows`);
console.log("New in this version: /opsx:propose. Try 'openspec config profile core' for the streamlined experience.");
// Tools without a command adapter never get /opsx:* commands; point them
// at the skill instead, using the first detected tool's invocation syntax.
const hasCommandSurface = tools.some((tool) => CommandAdapterRegistry.has(tool.value));
const proposeReference = hasCommandSurface
? '/opsx:propose'
: getSkillReferenceTransformer(tools[0]?.value ?? '')('/opsx:propose');
console.log(`New in this version: ${proposeReference}. Try 'openspec config profile core' for the streamlined experience.`);
}
4 changes: 2 additions & 2 deletions src/core/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ export class UpdateCommand {
const skillDir = path.join(skillsDir, dirName);
const skillFile = path.join(skillDir, 'SKILL.md');

const transformer = getTransformerForTool(tool.value, delivery);
const transformer = getTransformerForTool(tool.value, delivery, resolveCommandSurfaceCapability(tool.value));
const skillContent = generateSkillContent(template, OPENSPEC_VERSION, transformer);
await FileSystemUtils.writeFile(skillFile, skillContent);
}
Expand Down Expand Up @@ -855,7 +855,7 @@ export class UpdateCommand {
const skillDir = path.join(skillsDir, dirName);
const skillFile = path.join(skillDir, 'SKILL.md');

const transformer = getTransformerForTool(tool.value, delivery);
const transformer = getTransformerForTool(tool.value, delivery, resolveCommandSurfaceCapability(tool.value));
const skillContent = generateSkillContent(template, OPENSPEC_VERSION, transformer);
await FileSystemUtils.writeFile(skillFile, skillContent);
}
Expand Down
Loading
Loading