diff --git a/README.md b/README.md
index b8af8ca15..7329d0726 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ Our philosophy:
> [!TIP]
> **New workflow now available!** We've rebuilt OpenSpec with a new artifact-guided workflow.
>
-> Run `/opsx:propose "your idea"` to get started. → [Learn more here](docs/opsx.md)
+> Run `/openspec:propose "your idea"` to get started. → [Learn more here](docs/opsx.md)
Follow @0xTab on X for updates · Join the OpenSpec Discord for help and questions.
@@ -46,12 +46,12 @@ Our philosophy:
Using OpenSpec in a team? [Email here](mailto:teams@openspec.dev) for access to our Slack channel.
-
+
## See it in action
```text
-You: /opsx:propose add-dark-mode
+You: /openspec:propose add-dark-mode
AI: Created openspec/changes/add-dark-mode/
✓ proposal.md — why we're doing this, what's changing
✓ specs/ — requirements and scenarios
@@ -59,7 +59,7 @@ AI: Created openspec/changes/add-dark-mode/
✓ tasks.md — implementation checklist
Ready for implementation!
-You: /opsx:apply
+You: /openspec:apply
AI: Implementing tasks...
✓ 1.1 Add theme context provider
✓ 1.2 Create toggle component
@@ -67,7 +67,7 @@ AI: Implementing tasks...
✓ 2.2 Wire up localStorage
All tasks complete!
-You: /opsx:archive
+You: /openspec:archive
AI: Archived to openspec/changes/archive/2025-01-23-add-dark-mode/
Specs updated. Ready for the next feature.
```
@@ -98,9 +98,9 @@ cd your-project
openspec init
```
-Now tell your AI: `/opsx:propose `
+Now tell your AI: `/openspec:propose `
-If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:sync`, `/opsx:bulk-archive`, `/opsx:onboard`), select it with `openspec config profile` and apply with `openspec update`.
+If you want the expanded workflow (`/openspec:new`, `/openspec:continue`, `/openspec:ff`, `/openspec:verify`, `/openspec:sync`, `/openspec:bulk-archive`, `/openspec:onboard`), select it with `openspec config profile` and apply with `openspec update`.
> [!NOTE]
> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 20+ tools and growing.
diff --git a/docs/cli.md b/docs/cli.md
index ebbb847eb..88a56782e 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -1,6 +1,6 @@
# CLI Reference
-The OpenSpec CLI (`openspec`) provides terminal commands for project setup, validation, status inspection, and management. These commands complement the AI slash commands (like `/opsx:propose`) documented in [Commands](commands.md).
+The OpenSpec CLI (`openspec`) provides terminal commands for project setup, validation, status inspection, and management. These commands complement the AI slash commands (like `/openspec:propose`) documented in [Commands](commands.md).
## Summary
@@ -928,7 +928,7 @@ openspec completion uninstall
## Related Documentation
-- [Commands](commands.md) - AI slash commands (`/opsx:propose`, `/opsx:apply`, etc.)
+- [Commands](commands.md) - AI slash commands (`/openspec:propose`, `/openspec:apply`, etc.)
- [Workflows](workflows.md) - Common patterns and when to use each command
- [Customization](customization.md) - Create custom schemas and templates
- [Getting Started](getting-started.md) - First-time setup guide
diff --git a/docs/commands.md b/docs/commands.md
index fd4bb7fe1..1bc9a7eb3 100644
--- a/docs/commands.md
+++ b/docs/commands.md
@@ -10,22 +10,22 @@ For workflow patterns and when to use each command, see [Workflows](workflows.md
| Command | Purpose |
|---------|---------|
-| `/opsx:propose` | Create a change and generate planning artifacts in one step |
-| `/opsx:explore` | Think through ideas before committing to a change |
-| `/opsx:apply` | Implement tasks from the change |
-| `/opsx:archive` | Archive a completed change |
+| `/openspec:propose` | Create a change and generate planning artifacts in one step |
+| `/openspec:explore` | Think through ideas before committing to a change |
+| `/openspec:apply` | Implement tasks from the change |
+| `/openspec:archive` | Archive a completed change |
### Expanded Workflow Commands (custom workflow selection)
| Command | Purpose |
|---------|---------|
-| `/opsx:new` | Start a new change scaffold |
-| `/opsx:continue` | Create the next artifact based on dependencies |
-| `/opsx:ff` | Fast-forward: create all planning artifacts at once |
-| `/opsx:verify` | Validate implementation matches artifacts |
-| `/opsx:sync` | Merge delta specs into main specs |
-| `/opsx:bulk-archive` | Archive multiple changes at once |
-| `/opsx:onboard` | Guided tutorial through the complete workflow |
+| `/openspec:new` | Start a new change scaffold |
+| `/openspec:continue` | Create the next artifact based on dependencies |
+| `/openspec:ff` | Fast-forward: create all planning artifacts at once |
+| `/openspec:verify` | Validate implementation matches artifacts |
+| `/openspec:sync` | Merge delta specs into main specs |
+| `/openspec:bulk-archive` | Archive multiple changes at once |
+| `/openspec:onboard` | Guided tutorial through the complete workflow |
The default global profile is `core`. To enable expanded workflow commands, run `openspec config profile`, select workflows, then run `openspec update` in your project.
@@ -33,13 +33,13 @@ The default global profile is `core`. To enable expanded workflow commands, run
## Command Reference
-### `/opsx:propose`
+### `/openspec:propose`
Create a new change and generate planning artifacts in one step. This is the default start command in the `core` profile.
**Syntax:**
```text
-/opsx:propose [change-name-or-description]
+/openspec:propose [change-name-or-description]
```
**Arguments:**
@@ -50,33 +50,33 @@ Create a new change and generate planning artifacts in one step. This is the def
**What it does:**
- Creates `openspec/changes//`
- Generates artifacts needed before implementation (for `spec-driven`: proposal, specs, design, tasks)
-- Stops when the change is ready for `/opsx:apply`
+- Stops when the change is ready for `/openspec:apply`
**Example:**
```text
-You: /opsx:propose add-dark-mode
+You: /openspec:propose add-dark-mode
AI: Created openspec/changes/add-dark-mode/
✓ proposal.md
✓ specs/ui/spec.md
✓ design.md
✓ tasks.md
- Ready for implementation. Run /opsx:apply.
+ Ready for implementation. Run /openspec:apply.
```
**Tips:**
- Use this for the fastest end-to-end path
-- If you want step-by-step artifact control, enable expanded workflows and use `/opsx:new` + `/opsx:continue`
+- If you want step-by-step artifact control, enable expanded workflows and use `/openspec:new` + `/openspec:continue`
---
-### `/opsx:explore`
+### `/openspec:explore`
Think through ideas, investigate problems, and clarify requirements before committing to a change.
**Syntax:**
```
-/opsx:explore [topic]
+/openspec:explore [topic]
```
**Arguments:**
@@ -89,11 +89,11 @@ Think through ideas, investigate problems, and clarify requirements before commi
- Investigates the codebase to answer questions
- Compares options and approaches
- Creates visual diagrams to clarify thinking
-- Can transition to `/opsx:propose` (default) or `/opsx:new` (expanded workflow) when insights crystallize
+- Can transition to `/openspec:propose` (default) or `/openspec:new` (expanded workflow) when insights crystallize
**Example:**
```text
-You: /opsx:explore
+You: /openspec:explore
AI: What would you like to explore?
@@ -113,7 +113,7 @@ AI: Let me investigate your current auth setup...
You: Let's go with JWT. Can we start a change for that?
-AI: Ready when you are. Run /opsx:propose add-jwt-auth to begin.
+AI: Ready when you are. Run /openspec:propose add-jwt-auth to begin.
```
**Tips:**
@@ -124,15 +124,15 @@ AI: Ready when you are. Run /opsx:propose add-jwt-auth to begin.
---
-### `/opsx:new`
+### `/openspec:new`
-Start a new change scaffold. Creates the change folder and waits for you to generate artifacts with `/opsx:continue` or `/opsx:ff`.
+Start a new change scaffold. Creates the change folder and waits for you to generate artifacts with `/openspec:continue` or `/openspec:ff`.
This command is part of the expanded workflow set (not included in the default `core` profile).
**Syntax:**
```
-/opsx:new [change-name] [--schema ]
+/openspec:new [change-name] [--schema ]
```
**Arguments:**
@@ -155,13 +155,13 @@ openspec/changes//
**Example:**
```
-You: /opsx:new add-dark-mode
+You: /openspec:new add-dark-mode
AI: Created openspec/changes/add-dark-mode/
Schema: spec-driven
Ready to create: proposal
- Use /opsx:continue to create it, or /opsx:ff to create all artifacts.
+ Use /openspec:continue to create it, or /openspec:ff to create all artifacts.
```
**Tips:**
@@ -171,13 +171,13 @@ AI: Created openspec/changes/add-dark-mode/
---
-### `/opsx:continue`
+### `/openspec:continue`
Create the next artifact in the dependency chain. Creates one artifact at a time for incremental progress.
**Syntax:**
```
-/opsx:continue [change-name]
+/openspec:continue [change-name]
```
**Arguments:**
@@ -194,7 +194,7 @@ Create the next artifact in the dependency chain. Creates one artifact at a time
**Example:**
```
-You: /opsx:continue
+You: /openspec:continue
AI: Change: add-dark-mode
@@ -211,7 +211,7 @@ AI: Change: add-dark-mode
✓ Created openspec/changes/add-dark-mode/specs/ui/spec.md
Now available: tasks
- Run /opsx:continue to create the next artifact.
+ Run /openspec:continue to create the next artifact.
```
**Tips:**
@@ -222,13 +222,13 @@ AI: Change: add-dark-mode
---
-### `/opsx:ff`
+### `/openspec:ff`
Fast-forward through artifact creation. Creates all planning artifacts at once.
**Syntax:**
```
-/opsx:ff [change-name]
+/openspec:ff [change-name]
```
**Arguments:**
@@ -244,7 +244,7 @@ Fast-forward through artifact creation. Creates all planning artifacts at once.
**Example:**
```
-You: /opsx:ff add-dark-mode
+You: /openspec:ff add-dark-mode
AI: Fast-forwarding add-dark-mode...
@@ -254,24 +254,24 @@ AI: Fast-forwarding add-dark-mode...
✓ Creating tasks.md
All planning artifacts complete!
- Ready for implementation. Run /opsx:apply to begin.
+ Ready for implementation. Run /openspec:apply to begin.
```
**Tips:**
- Use when you have a clear picture of what you're building
-- Faster than `/opsx:continue` for straightforward changes
+- Faster than `/openspec:continue` for straightforward changes
- You can still edit artifacts afterward
- Good for small to medium features
---
-### `/opsx:apply`
+### `/openspec:apply`
Implement tasks from the change. Works through the task list, writing code and checking off items.
**Syntax:**
```
-/opsx:apply [change-name]
+/openspec:apply [change-name]
```
**Arguments:**
@@ -287,7 +287,7 @@ Implement tasks from the change. Works through the task list, writing code and c
**Example:**
```
-You: /opsx:apply
+You: /openspec:apply
AI: Implementing add-dark-mode...
@@ -315,13 +315,13 @@ AI: Implementing add-dark-mode...
---
-### `/opsx:verify`
+### `/openspec:verify`
Validate that implementation matches your change artifacts. Checks completeness, correctness, and coherence.
**Syntax:**
```
-/opsx:verify [change-name]
+/openspec:verify [change-name]
```
**Arguments:**
@@ -345,7 +345,7 @@ Validate that implementation matches your change artifacts. Checks completeness,
**Example:**
```
-You: /opsx:verify
+You: /openspec:verify
AI: Verifying add-dark-mode...
@@ -383,13 +383,13 @@ AI: Verifying add-dark-mode...
---
-### `/opsx:sync`
+### `/openspec:sync`
**Optional command.** Merge delta specs from a change into main specs. Archive will prompt to sync if needed, so you typically don't need to run this manually.
**Syntax:**
```
-/opsx:sync [change-name]
+/openspec:sync [change-name]
```
**Arguments:**
@@ -406,7 +406,7 @@ AI: Verifying add-dark-mode...
**Example:**
```text
-You: /opsx:sync
+You: /openspec:sync
AI: Syncing add-dark-mode delta specs...
@@ -420,7 +420,7 @@ AI: Syncing add-dark-mode delta specs...
Merging...
✓ openspec/specs/ui/spec.md updated
- Change remains active. Run /opsx:archive when ready to complete.
+ Change remains active. Run /openspec:archive when ready to complete.
```
**When to use manually:**
@@ -440,13 +440,13 @@ AI: Syncing add-dark-mode delta specs...
---
-### `/opsx:archive`
+### `/openspec:archive`
Archive a completed change. Finalizes the change and moves it to the archive folder.
**Syntax:**
```
-/opsx:archive [change-name]
+/openspec:archive [change-name]
```
**Arguments:**
@@ -463,7 +463,7 @@ Archive a completed change. Finalizes the change and moves it to the archive fol
**Example:**
```text
-You: /opsx:archive
+You: /openspec:archive
AI: Archiving add-dark-mode...
@@ -488,17 +488,17 @@ AI: ✓ Synced specs to openspec/specs/ui/spec.md
- Archive won't block on incomplete tasks, but will warn
- Delta specs can be synced during archive or beforehand
- Archived changes are preserved for history
-- Use `/opsx:verify` first to catch issues
+- Use `/openspec:verify` first to catch issues
---
-### `/opsx:bulk-archive`
+### `/openspec:bulk-archive`
Archive multiple completed changes at once. Handles spec conflicts between changes.
**Syntax:**
```
-/opsx:bulk-archive [change-names...]
+/openspec:bulk-archive [change-names...]
```
**Arguments:**
@@ -515,7 +515,7 @@ Archive multiple completed changes at once. Handles spec conflicts between chang
**Example:**
```
-You: /opsx:bulk-archive
+You: /openspec:bulk-archive
AI: Found 3 completed changes:
- add-dark-mode (8/8 tasks complete)
@@ -548,13 +548,13 @@ AI: ✓ Archived add-dark-mode
---
-### `/opsx:onboard`
+### `/openspec:onboard`
Guided onboarding through the complete OpenSpec workflow. An interactive tutorial using your actual codebase.
**Syntax:**
```
-/opsx:onboard
+/openspec:onboard
```
**What it does:**
@@ -568,19 +568,19 @@ Guided onboarding through the complete OpenSpec workflow. An interactive tutoria
**Phases:**
1. Welcome and codebase analysis
2. Finding an improvement opportunity
-3. Creating a change (`/opsx:new`)
+3. Creating a change (`/openspec:new`)
4. Writing the proposal
5. Creating specs
6. Writing the design
7. Creating tasks
-8. Implementing tasks (`/opsx:apply`)
+8. Implementing tasks (`/openspec:apply`)
9. Verifying implementation
10. Archiving the change
11. Summary and next steps
**Example:**
```
-You: /opsx:onboard
+You: /openspec:onboard
AI: Welcome to OpenSpec!
@@ -614,11 +614,11 @@ Different AI tools use slightly different command syntax. Use the format that ma
| Tool | Syntax Example |
|------|----------------|
-| Claude Code | `/opsx:propose`, `/opsx:apply` |
-| Cursor | `/opsx-propose`, `/opsx-apply` |
-| Windsurf | `/opsx-propose`, `/opsx-apply` |
-| Copilot (IDE) | `/opsx-propose`, `/opsx-apply` |
-| Trae | Skill-based invocations such as `/openspec-propose`, `/openspec-apply-change` (no generated `opsx-*` command files) |
+| Claude Code | `/openspec:propose`, `/openspec:apply` |
+| Cursor | `/openspec-propose`, `/openspec-apply` |
+| Windsurf | `/openspec-propose`, `/openspec-apply` |
+| Copilot (IDE) | `/openspec-propose`, `/openspec-apply` |
+| Trae | Skill-based invocations such as `/openspec-propose`, `/openspec-apply-change` (no generated `openspec-*` command files) |
The intent is the same across tools, but how commands are surfaced can differ by integration.
@@ -653,7 +653,7 @@ Legacy changes can be continued with OPSX commands. The artifact structure is co
The command couldn't identify which change to work on.
**Solutions:**
-- Specify the change name explicitly: `/opsx:apply add-dark-mode`
+- Specify the change name explicitly: `/openspec:apply add-dark-mode`
- Check that the change folder exists: `openspec list`
- Verify you're in the right project directory
@@ -693,7 +693,7 @@ The AI creates incomplete or incorrect artifacts.
- Add project context in `openspec/config.yaml`
- Add per-artifact rules for specific guidance
- Provide more detail in your change description
-- Use `/opsx:continue` instead of `/opsx:ff` for more control
+- Use `/openspec:continue` instead of `/openspec:ff` for more control
---
diff --git a/docs/concepts.md b/docs/concepts.md
index 96cdd9d27..f40f2999e 100644
--- a/docs/concepts.md
+++ b/docs/concepts.md
@@ -562,27 +562,27 @@ openspec/
│ OPENSPEC FLOW │
│ │
│ ┌────────────────┐ │
-│ │ 1. START │ /opsx:propose (core) or /opsx:new (expanded) │
+│ │ 1. START │ /openspec:propose (core) or /openspec:new (expanded) │
│ │ CHANGE │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
-│ │ 2. CREATE │ /opsx:ff or /opsx:continue (expanded workflow) │
+│ │ 2. CREATE │ /openspec:ff or /openspec:continue (expanded workflow) │
│ │ ARTIFACTS │ Creates proposal → specs → design → tasks │
│ │ │ (based on schema dependencies) │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
-│ │ 3. IMPLEMENT │ /opsx:apply │
+│ │ 3. IMPLEMENT │ /openspec:apply │
│ │ TASKS │ Work through tasks, checking them off │
│ │ │◄──── Update artifacts as you learn │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
-│ │ 4. VERIFY │ /opsx:verify (optional) │
+│ │ 4. VERIFY │ /openspec:verify (optional) │
│ │ WORK │ Check implementation matches specs │
│ └───────┬────────┘ │
│ │ │
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 6f4b88862..fa92b06c9 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -9,13 +9,13 @@ OpenSpec helps you and your AI coding assistant agree on what to build before an
**Default quick path (core profile):**
```text
-/opsx:propose ──► /opsx:apply ──► /opsx:archive
+/openspec:propose ──► /openspec:apply ──► /openspec:archive
```
**Expanded path (custom workflow selection):**
```text
-/opsx:new ──► /opsx:ff or /opsx:continue ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive
+/openspec:new ──► /openspec:ff or /openspec:continue ──► /openspec:apply ──► /openspec:verify ──► /openspec:archive
```
The default global profile is `core`, which includes `propose`, `explore`, `apply`, and `archive`. You can enable the expanded workflow commands with `openspec config profile` and then `openspec update`.
@@ -123,7 +123,7 @@ Let's walk through adding dark mode to an application.
### 1. Start the Change (Default)
```text
-You: /opsx:propose add-dark-mode
+You: /openspec:propose add-dark-mode
AI: Created openspec/changes/add-dark-mode/
✓ proposal.md — why we're doing this, what's changing
@@ -133,7 +133,7 @@ AI: Created openspec/changes/add-dark-mode/
Ready for implementation!
```
-If you've enabled the expanded workflow profile, you can also do this as two steps: `/opsx:new` then `/opsx:ff` (or `/opsx:continue` incrementally).
+If you've enabled the expanded workflow profile, you can also do this as two steps: `/openspec:new` then `/openspec:ff` (or `/openspec:continue` incrementally).
### 2. What Gets Created
@@ -201,7 +201,7 @@ The system SHALL allow users to choose between light and dark themes.
### 3. Implement
```
-You: /opsx:apply
+You: /openspec:apply
AI: Working through tasks...
✓ 1.1 Created ThemeContext with light/dark state
@@ -217,7 +217,7 @@ During implementation, if you discover the design needs adjustment, just update
### 4. Archive
```
-You: /opsx:archive
+You: /openspec:archive
AI: Archiving add-dark-mode...
✓ Merged specs into openspec/specs/ui/spec.md
diff --git a/docs/migration-guide.md b/docs/migration-guide.md
index 5091ce438..2258aaca8 100644
--- a/docs/migration-guide.md
+++ b/docs/migration-guide.md
@@ -8,7 +8,7 @@ OPSX replaces the old phase-locked workflow with a fluid, action-based approach.
| Aspect | Legacy | OPSX |
|--------|--------|------|
-| **Commands** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` | Default: `/opsx:propose`, `/opsx:apply`, `/opsx:archive` (expanded workflow commands optional) |
+| **Commands** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` | Default: `/openspec:propose`, `/openspec:apply`, `/openspec:archive` (expanded workflow commands optional) |
| **Workflow** | Create all artifacts at once | Create incrementally or all at once—your choice |
| **Going back** | Awkward phase gates | Natural—update any artifact anytime |
| **Customization** | Fixed structure | Schema-driven, fully hackable |
@@ -284,22 +284,22 @@ Command availability is profile-dependent:
| Command | Purpose |
|---------|---------|
-| `/opsx:propose` | Create a change and generate planning artifacts in one step |
-| `/opsx:explore` | Think through ideas with no structure |
-| `/opsx:apply` | Implement tasks from tasks.md |
-| `/opsx:archive` | Finalize and archive the change |
+| `/openspec:propose` | Create a change and generate planning artifacts in one step |
+| `/openspec:explore` | Think through ideas with no structure |
+| `/openspec:apply` | Implement tasks from tasks.md |
+| `/openspec:archive` | Finalize and archive the change |
**Expanded workflow (custom selection):**
| Command | Purpose |
|---------|---------|
-| `/opsx:new` | Start a new change scaffold |
-| `/opsx:continue` | Create the next artifact (one at a time) |
-| `/opsx:ff` | Fast-forward—create planning artifacts at once |
-| `/opsx:verify` | Validate implementation matches specs |
-| `/opsx:sync` | Preview/spec-merge without archiving |
-| `/opsx:bulk-archive` | Archive multiple changes at once |
-| `/opsx:onboard` | Guided end-to-end onboarding workflow |
+| `/openspec:new` | Start a new change scaffold |
+| `/openspec:continue` | Create the next artifact (one at a time) |
+| `/openspec:ff` | Fast-forward—create planning artifacts at once |
+| `/openspec:verify` | Validate implementation matches specs |
+| `/openspec:sync` | Preview/spec-merge without archiving |
+| `/openspec:bulk-archive` | Archive multiple changes at once |
+| `/openspec:onboard` | Guided end-to-end onboarding workflow |
Enable expanded commands with `openspec config profile`, then run `openspec update`.
@@ -307,9 +307,9 @@ Enable expanded commands with `openspec config profile`, then run `openspec upda
| Legacy | OPSX Equivalent |
|--------|-----------------|
-| `/openspec:proposal` | `/opsx:propose` (default) or `/opsx:new` then `/opsx:ff` (expanded) |
-| `/openspec:apply` | `/opsx:apply` |
-| `/openspec:archive` | `/opsx:archive` |
+| `/openspec:proposal` | `/openspec:propose` (default) or `/openspec:new` then `/openspec:ff` (expanded) |
+| `/openspec:apply` | `/openspec:apply` |
+| `/openspec:archive` | `/openspec:archive` |
### New Capabilities
@@ -317,13 +317,13 @@ These capabilities are part of the expanded workflow command set.
**Granular artifact creation:**
```
-/opsx:continue
+/openspec:continue
```
Creates one artifact at a time based on dependencies. Use this when you want to review each step.
**Exploration mode:**
```
-/opsx:explore
+/openspec:explore
```
Think through ideas with a partner before committing to a change.
@@ -381,7 +381,7 @@ Artifacts form a directed graph. Dependencies are enablers, not gates:
specs, design)
```
-When you run `/opsx:continue`, it checks what's ready and offers the next artifact. You can also create multiple ready artifacts in any order.
+When you run `/openspec:continue`, it checks what's ready and offers the next artifact. You can also create multiple ready artifacts in any order.
### Skills vs Commands
@@ -416,7 +416,7 @@ Your in-progress changes work seamlessly with OPSX commands.
**Have an active change from the legacy workflow?**
```
-/opsx:apply add-my-feature
+/openspec:apply add-my-feature
```
OPSX reads the existing artifacts and continues from where you left off.
@@ -424,7 +424,7 @@ OPSX reads the existing artifacts and continues from where you left off.
**Want to add more artifacts to an existing change?**
```
-/opsx:continue add-my-feature
+/openspec:continue add-my-feature
```
Shows what's ready to create based on what already exists.
@@ -576,14 +576,14 @@ project/
### Command Cheatsheet
```text
-/opsx:propose Start quickly (default core profile)
-/opsx:apply Implement tasks
-/opsx:archive Finish and archive
+/openspec:propose Start quickly (default core profile)
+/openspec:apply Implement tasks
+/openspec:archive Finish and archive
# Expanded workflow (if enabled):
-/opsx:new Scaffold a change
-/opsx:continue Create next artifact
-/opsx:ff Create planning artifacts
+/openspec:new Scaffold a change
+/openspec:continue Create next artifact
+/openspec:ff Create planning artifacts
```
---
diff --git a/docs/opsx.md b/docs/opsx.md
index 9607b7d06..5a13db95f 100644
--- a/docs/opsx.md
+++ b/docs/opsx.md
@@ -157,60 +157,60 @@ rules:
| Command | What it does |
|---------|--------------|
-| `/opsx:propose` | Create a change and generate planning artifacts in one step (default quick path) |
-| `/opsx:explore` | Think through ideas, investigate problems, clarify requirements |
-| `/opsx:new` | Start a new change scaffold (expanded workflow) |
-| `/opsx:continue` | Create the next artifact (expanded workflow) |
-| `/opsx:ff` | Fast-forward planning artifacts (expanded workflow) |
-| `/opsx:apply` | Implement tasks, updating artifacts as needed |
-| `/opsx:verify` | Validate implementation against artifacts (expanded workflow) |
-| `/opsx:sync` | Sync delta specs to main (expanded workflow, optional) |
-| `/opsx:archive` | Archive when done |
-| `/opsx:bulk-archive` | Archive multiple completed changes (expanded workflow) |
-| `/opsx:onboard` | Guided walkthrough of an end-to-end change (expanded workflow) |
+| `/openspec:propose` | Create a change and generate planning artifacts in one step (default quick path) |
+| `/openspec:explore` | Think through ideas, investigate problems, clarify requirements |
+| `/openspec:new` | Start a new change scaffold (expanded workflow) |
+| `/openspec:continue` | Create the next artifact (expanded workflow) |
+| `/openspec:ff` | Fast-forward planning artifacts (expanded workflow) |
+| `/openspec:apply` | Implement tasks, updating artifacts as needed |
+| `/openspec:verify` | Validate implementation against artifacts (expanded workflow) |
+| `/openspec:sync` | Sync delta specs to main (expanded workflow, optional) |
+| `/openspec:archive` | Archive when done |
+| `/openspec:bulk-archive` | Archive multiple completed changes (expanded workflow) |
+| `/openspec:onboard` | Guided walkthrough of an end-to-end change (expanded workflow) |
## Usage
### Explore an idea
```
-/opsx:explore
+/openspec:explore
```
-Think through ideas, investigate problems, compare options. No structure required - just a thinking partner. When insights crystallize, transition to `/opsx:propose` (default) or `/opsx:new`/`/opsx:ff` (expanded).
+Think through ideas, investigate problems, compare options. No structure required - just a thinking partner. When insights crystallize, transition to `/openspec:propose` (default) or `/openspec:new`/`/openspec:ff` (expanded).
### Start a new change
```
-/opsx:propose
+/openspec:propose
```
Creates the change and generates planning artifacts needed before implementation.
If you've enabled expanded workflows, you can instead use:
```text
-/opsx:new # scaffold only
-/opsx:continue # create one artifact at a time
-/opsx:ff # create all planning artifacts at once
+/openspec:new # scaffold only
+/openspec:continue # create one artifact at a time
+/openspec:ff # create all planning artifacts at once
```
### Create artifacts
```
-/opsx:continue
+/openspec:continue
```
Shows what's ready to create based on dependencies, then creates one artifact. Use repeatedly to build up your change incrementally.
```
-/opsx:ff add-dark-mode
+/openspec:ff add-dark-mode
```
Creates all planning artifacts at once. Use when you have a clear picture of what you're building.
### Implement (the fluid part)
```
-/opsx:apply
+/openspec:apply
```
-Works through tasks, checking them off as you go. If you're juggling multiple changes, you can run `/opsx:apply `; otherwise it should infer from the conversation and prompt you to choose if it can't tell.
+Works through tasks, checking them off as you go. If you're juggling multiple changes, you can run `/openspec:apply `; otherwise it should infer from the conversation and prompt you to choose if it can't tell.
### Finish up
```
-/opsx:archive # Move to archive when done (prompts to sync specs if needed)
+/openspec:archive # Move to archive when done (prompts to sync specs if needed)
```
## When to Update vs. Start Fresh
@@ -301,7 +301,7 @@ Think of it like git branches:
## What's Different?
-| | Legacy (`/openspec:proposal`) | OPSX (`/opsx:*`) |
+| | Legacy (`/openspec:proposal`) | OPSX (`/openspec:*`) |
|---|---|---|
| **Structure** | One big proposal document | Discrete artifacts with dependencies |
| **Workflow** | Linear phases: plan → implement → archive | Fluid actions — do anything anytime |
@@ -484,7 +484,7 @@ Artifacts form a directed acyclic graph (DAG). Dependencies are **enablers**, no
**OPSX** — agent queries for rich context:
```
- User: "/opsx:continue"
+ User: "/openspec:continue"
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
@@ -541,7 +541,7 @@ Artifacts form a directed acyclic graph (DAG). Dependencies are **enablers**, no
**OPSX** — natural iteration:
```
- /opsx:new ───► /opsx:continue ───► /opsx:apply ───► /opsx:archive
+ /openspec:new ───► /openspec:continue ───► /openspec:apply ───► /openspec:archive
│ │ │
│ │ ├── "The design is wrong"
│ │ │
@@ -550,7 +550,7 @@ Artifacts form a directed acyclic graph (DAG). Dependencies are **enablers**, no
│ │ and continue!
│ │ │
│ │ ▼
- │ │ /opsx:apply picks up
+ │ │ /openspec:apply picks up
│ │ where you left off
│ │
│ └── Creates ONE artifact, shows what's unlocked
@@ -646,9 +646,9 @@ openspec schema validate my-workflow
## Tips
-- Use `/opsx:explore` to think through an idea before committing to a change
-- `/opsx:ff` when you know what you want, `/opsx:continue` when exploring
-- During `/opsx:apply`, if something's wrong — fix the artifact, then continue
+- Use `/openspec:explore` to think through an idea before committing to a change
+- `/openspec:ff` when you know what you want, `/openspec:continue` when exploring
+- During `/openspec:apply`, if something's wrong — fix the artifact, then continue
- Tasks track progress via checkboxes in `tasks.md`
- Check status anytime: `openspec status --change "name"`
diff --git a/docs/supported-tools.md b/docs/supported-tools.md
index 524e597f2..ba999b7e8 100644
--- a/docs/supported-tools.md
+++ b/docs/supported-tools.md
@@ -7,7 +7,7 @@ OpenSpec works with many AI coding assistants. When you run `openspec init`, Ope
For each selected tool, OpenSpec can install:
1. **Skills** (if delivery includes skills): `.../skills/openspec-*/SKILL.md`
-2. **Commands** (if delivery includes commands): tool-specific `opsx-*` command files
+2. **Commands** (if delivery includes commands): tool-specific `openspec-*` command files
By default, OpenSpec uses the `core` profile, which includes:
- `propose`
@@ -21,30 +21,30 @@ You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `sync`, `b
| Tool (ID) | Skills path pattern | Command path pattern |
|-----------|---------------------|----------------------|
-| Amazon Q Developer (`amazon-q`) | `.amazonq/skills/openspec-*/SKILL.md` | `.amazonq/prompts/opsx-.md` |
-| Antigravity (`antigravity`) | `.agent/skills/openspec-*/SKILL.md` | `.agent/workflows/opsx-.md` |
-| Auggie (`auggie`) | `.augment/skills/openspec-*/SKILL.md` | `.augment/commands/opsx-.md` |
+| Amazon Q Developer (`amazon-q`) | `.amazonq/skills/openspec-*/SKILL.md` | `.amazonq/prompts/openspec-.md` |
+| Antigravity (`antigravity`) | `.agent/skills/openspec-*/SKILL.md` | `.agent/workflows/openspec-.md` |
+| Auggie (`auggie`) | `.augment/skills/openspec-*/SKILL.md` | `.augment/commands/openspec-.md` |
| Claude Code (`claude`) | `.claude/skills/openspec-*/SKILL.md` | `.claude/commands/opsx/.md` |
-| Cline (`cline`) | `.cline/skills/openspec-*/SKILL.md` | `.clinerules/workflows/opsx-.md` |
+| Cline (`cline`) | `.cline/skills/openspec-*/SKILL.md` | `.clinerules/workflows/openspec-.md` |
| CodeBuddy (`codebuddy`) | `.codebuddy/skills/openspec-*/SKILL.md` | `.codebuddy/commands/opsx/.md` |
-| Codex (`codex`) | `.codex/skills/openspec-*/SKILL.md` | `$CODEX_HOME/prompts/opsx-.md`\* |
-| Continue (`continue`) | `.continue/skills/openspec-*/SKILL.md` | `.continue/prompts/opsx-.prompt` |
-| CoStrict (`costrict`) | `.cospec/skills/openspec-*/SKILL.md` | `.cospec/openspec/commands/opsx-.md` |
+| Codex (`codex`) | `.codex/skills/openspec-*/SKILL.md` | `$CODEX_HOME/prompts/openspec-.md`\* |
+| Continue (`continue`) | `.continue/skills/openspec-*/SKILL.md` | `.continue/prompts/openspec-.prompt` |
+| CoStrict (`costrict`) | `.cospec/skills/openspec-*/SKILL.md` | `.cospec/openspec/commands/openspec-.md` |
| Crush (`crush`) | `.crush/skills/openspec-*/SKILL.md` | `.crush/commands/opsx/.md` |
-| Cursor (`cursor`) | `.cursor/skills/openspec-*/SKILL.md` | `.cursor/commands/opsx-.md` |
-| Factory Droid (`factory`) | `.factory/skills/openspec-*/SKILL.md` | `.factory/commands/opsx-.md` |
+| Cursor (`cursor`) | `.cursor/skills/openspec-*/SKILL.md` | `.cursor/commands/openspec-.md` |
+| Factory Droid (`factory`) | `.factory/skills/openspec-*/SKILL.md` | `.factory/commands/openspec-.md` |
| Gemini CLI (`gemini`) | `.gemini/skills/openspec-*/SKILL.md` | `.gemini/commands/opsx/.toml` |
-| GitHub Copilot (`github-copilot`) | `.github/skills/openspec-*/SKILL.md` | `.github/prompts/opsx-.prompt.md`\*\* |
-| iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/opsx-.md` |
-| Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilocode/workflows/opsx-.md` |
-| Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/opsx-.prompt.md` |
-| OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/opsx-.md` |
-| Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/opsx-.md` |
+| GitHub Copilot (`github-copilot`) | `.github/skills/openspec-*/SKILL.md` | `.github/prompts/openspec-.prompt.md`\*\* |
+| iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/openspec-.md` |
+| Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilocode/workflows/openspec-.md` |
+| Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/openspec-.prompt.md` |
+| OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/openspec-.md` |
+| Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/openspec-.md` |
| Qoder (`qoder`) | `.qoder/skills/openspec-*/SKILL.md` | `.qoder/commands/opsx/.md` |
-| Qwen Code (`qwen`) | `.qwen/skills/openspec-*/SKILL.md` | `.qwen/commands/opsx-.toml` |
-| RooCode (`roocode`) | `.roo/skills/openspec-*/SKILL.md` | `.roo/commands/opsx-.md` |
+| Qwen Code (`qwen`) | `.qwen/skills/openspec-*/SKILL.md` | `.qwen/commands/openspec-.toml` |
+| RooCode (`roocode`) | `.roo/skills/openspec-*/SKILL.md` | `.roo/commands/openspec-.md` |
| Trae (`trae`) | `.trae/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
-| Windsurf (`windsurf`) | `.windsurf/skills/openspec-*/SKILL.md` | `.windsurf/workflows/opsx-.md` |
+| Windsurf (`windsurf`) | `.windsurf/skills/openspec-*/SKILL.md` | `.windsurf/workflows/openspec-.md` |
\* Codex commands are installed in the global Codex home (`$CODEX_HOME/prompts/` if set, otherwise `~/.codex/prompts/`), not your project directory.
diff --git a/docs/workflows.md b/docs/workflows.md
index 6cfd7e063..c63817f8b 100644
--- a/docs/workflows.md
+++ b/docs/workflows.md
@@ -33,20 +33,20 @@ OPSX (fluid actions):
### Default Quick Path (`core` profile)
New installs default to `core`, which provides:
-- `/opsx:propose`
-- `/opsx:explore`
-- `/opsx:apply`
-- `/opsx:archive`
+- `/openspec:propose`
+- `/openspec:explore`
+- `/openspec:apply`
+- `/openspec:archive`
Typical flow:
```text
-/opsx:propose ──► /opsx:apply ──► /opsx:archive
+/openspec:propose ──► /openspec:apply ──► /openspec:archive
```
### Expanded/Full Workflow (custom selection)
-If you want explicit scaffold-and-build commands (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:sync`, `/opsx:bulk-archive`, `/opsx:onboard`), enable them with:
+If you want explicit scaffold-and-build commands (`/openspec:new`, `/openspec:continue`, `/openspec:ff`, `/openspec:verify`, `/openspec:sync`, `/openspec:bulk-archive`, `/openspec:onboard`), enable them with:
```bash
openspec config profile
@@ -60,18 +60,18 @@ openspec update
When you know what you want to build and just need to execute:
```text
-/opsx:new ──► /opsx:ff ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive
+/openspec:new ──► /openspec:ff ──► /openspec:apply ──► /openspec:verify ──► /openspec:archive
```
**Example conversation:**
```text
-You: /opsx:new add-logout-button
+You: /openspec:new add-logout-button
AI: Created openspec/changes/add-logout-button/
Ready to create: proposal
-You: /opsx:ff
+You: /openspec:ff
AI: Creating all planning artifacts...
✓ proposal.md
@@ -80,7 +80,7 @@ AI: Creating all planning artifacts...
✓ tasks.md
Ready for implementation!
-You: /opsx:apply
+You: /openspec:apply
AI: Working through tasks...
✓ Added logout button to header
@@ -88,7 +88,7 @@ AI: Working through tasks...
✓ Added confirmation dialog
All tasks complete!
-You: /opsx:archive
+You: /openspec:archive
AI: ✓ Merged specs
✓ Archived change
@@ -101,13 +101,13 @@ AI: ✓ Merged specs
When requirements are unclear or you need to investigate first:
```text
-/opsx:explore ──► /opsx:new ──► /opsx:continue ──► ... ──► /opsx:apply
+/openspec:explore ──► /openspec:new ──► /openspec:continue ──► ... ──► /openspec:apply
```
**Example conversation:**
```text
-You: /opsx:explore
+You: /openspec:explore
AI: What would you like to explore?
@@ -127,11 +127,11 @@ AI: Let me help investigate...
You: Let's tackle the data fetching issue.
-You: /opsx:new optimize-product-list-fetching
+You: /openspec:new optimize-product-list-fetching
AI: Created change. Ready to create: proposal
-You: /opsx:continue
+You: /openspec:continue
AI: Creating proposal based on our exploration...
[Writes proposal incorporating investigation insights]
@@ -139,7 +139,7 @@ AI: Creating proposal based on our exploration...
Ready to create: specs, design
Which would you like next?
-You: /opsx:continue
+You: /openspec:continue
AI: Creating specs...
```
@@ -151,11 +151,11 @@ AI: Creating specs...
Work on multiple changes at once:
```text
-Change A: /opsx:new ──► /opsx:ff ──► /opsx:apply (in progress)
+Change A: /openspec:new ──► /openspec:ff ──► /openspec:apply (in progress)
│
context switch
│
-Change B: /opsx:new ──► /opsx:ff ──────► /opsx:apply
+Change B: /openspec:new ──► /openspec:ff ──────► /openspec:apply
```
**Example conversation:**
@@ -163,27 +163,27 @@ Change B: /opsx:new ──► /opsx:ff ──────► /opsx:apply
```text
You: I'm working on add-dark-mode but got pulled into a bug fix
-You: /opsx:new fix-login-redirect
+You: /openspec:new fix-login-redirect
AI: Created openspec/changes/fix-login-redirect/
-You: /opsx:ff
+You: /openspec:ff
AI: ✓ Created planning artifacts
-You: /opsx:apply
+You: /openspec:apply
AI: Working on fix-login-redirect...
[Implements the fix]
All tasks complete!
-You: /opsx:archive
+You: /openspec:archive
AI: ✓ Archived fix-login-redirect
You: Let's get back to dark mode
-You: /opsx:apply add-dark-mode
+You: /openspec:apply add-dark-mode
AI: Resuming add-dark-mode...
Picking up at task 2.3: Update Header...
@@ -191,10 +191,10 @@ AI: Resuming add-dark-mode...
**Best for:** Parallel work streams, urgent interrupts, team collaboration.
-When you have multiple completed changes, use `/opsx:bulk-archive`:
+When you have multiple completed changes, use `/openspec:bulk-archive`:
```text
-You: /opsx:bulk-archive
+You: /openspec:bulk-archive
AI: Found 3 completed changes:
- add-dark-mode (all tasks done)
@@ -224,7 +224,7 @@ Bulk archive detects when multiple changes touch the same specs and resolves con
The recommended completion flow:
```text
-/opsx:apply ──► /opsx:verify ──► /opsx:archive
+/openspec:apply ──► /openspec:verify ──► /openspec:archive
│ │
validates prompts to sync
implementation if needed
@@ -232,10 +232,10 @@ The recommended completion flow:
#### Verify: Check Your Work
-`/opsx:verify` validates implementation against your artifacts across three dimensions:
+`/openspec:verify` validates implementation against your artifacts across three dimensions:
```text
-You: /opsx:verify
+You: /openspec:verify
AI: Verifying add-auth...
@@ -277,10 +277,10 @@ Verify won't block archive, but it surfaces issues you might want to address fir
#### Archive: Finalize the Change
-`/opsx:archive` completes the change and moves it to the archive:
+`/openspec:archive` completes the change and moves it to the archive:
```text
-You: /opsx:archive
+You: /openspec:archive
AI: Archiving add-auth...
@@ -305,17 +305,17 @@ Archive will prompt if specs aren't synced. It won't block on incomplete tasks,
## When to Use What
-### `/opsx:ff` vs `/opsx:continue`
+### `/openspec:ff` vs `/openspec:continue`
| Situation | Use |
|-----------|-----|
-| Clear requirements, ready to build | `/opsx:ff` |
-| Exploring, want to review each step | `/opsx:continue` |
-| Want to iterate on proposal before specs | `/opsx:continue` |
-| Time pressure, need to move fast | `/opsx:ff` |
-| Complex change, want control | `/opsx:continue` |
+| Clear requirements, ready to build | `/openspec:ff` |
+| Exploring, want to review each step | `/openspec:continue` |
+| Want to iterate on proposal before specs | `/openspec:continue` |
+| Time pressure, need to move fast | `/openspec:ff` |
+| Complex change, want control | `/openspec:continue` |
-**Rule of thumb:** If you can describe the full scope upfront, use `/opsx:ff`. If you're figuring it out as you go, use `/opsx:continue`.
+**Rule of thumb:** If you can describe the full scope upfront, use `/openspec:ff`. If you're figuring it out as you go, use `/openspec:continue`.
### When to Update vs Start Fresh
@@ -373,12 +373,12 @@ One logical unit of work per change. If you're doing "add feature X and also ref
- Can ship independently
- Simpler rollback if needed
-### Use `/opsx:explore` for Unclear Requirements
+### Use `/openspec:explore` for Unclear Requirements
Before committing to a change, explore the problem space:
```text
-You: /opsx:explore
+You: /openspec:explore
AI: What would you like to explore?
@@ -399,10 +399,10 @@ Exploration clarifies thinking before you create artifacts.
### Verify Before Archiving
-Use `/opsx:verify` to check implementation matches artifacts:
+Use `/openspec:verify` to check implementation matches artifacts:
```text
-You: /opsx:verify
+You: /openspec:verify
AI: Verifying add-dark-mode...
@@ -433,16 +433,16 @@ For full command details and options, see [Commands](commands.md).
| Command | Purpose | When to Use |
|---------|---------|-------------|
-| `/opsx:propose` | Create change + planning artifacts | Fast default path (`core` profile) |
-| `/opsx:explore` | Think through ideas | Unclear requirements, investigation |
-| `/opsx:new` | Start a change scaffold | Expanded mode, explicit artifact control |
-| `/opsx:continue` | Create next artifact | Expanded mode, step-by-step artifact creation |
-| `/opsx:ff` | Create all planning artifacts | Expanded mode, clear scope |
-| `/opsx:apply` | Implement tasks | Ready to write code |
-| `/opsx:verify` | Validate implementation | Expanded mode, before archiving |
-| `/opsx:sync` | Merge delta specs | Expanded mode, optional |
-| `/opsx:archive` | Complete the change | All work finished |
-| `/opsx:bulk-archive` | Archive multiple changes | Expanded mode, parallel work |
+| `/openspec:propose` | Create change + planning artifacts | Fast default path (`core` profile) |
+| `/openspec:explore` | Think through ideas | Unclear requirements, investigation |
+| `/openspec:new` | Start a change scaffold | Expanded mode, explicit artifact control |
+| `/openspec:continue` | Create next artifact | Expanded mode, step-by-step artifact creation |
+| `/openspec:ff` | Create all planning artifacts | Expanded mode, clear scope |
+| `/openspec:apply` | Implement tasks | Ready to write code |
+| `/openspec:verify` | Validate implementation | Expanded mode, before archiving |
+| `/openspec:sync` | Merge delta specs | Expanded mode, optional |
+| `/openspec:archive` | Complete the change | All work finished |
+| `/openspec:bulk-archive` | Archive multiple changes | Expanded mode, parallel work |
## Next Steps
diff --git a/package-lock.json b/package-lock.json
index e1daf932f..9340fe4bf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@fission-ai/openspec",
- "version": "1.1.1",
+ "version": "1.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@fission-ai/openspec",
- "version": "1.1.1",
+ "version": "1.2.0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/src/core/command-generation/adapters/amazon-q.ts b/src/core/command-generation/adapters/amazon-q.ts
index 0131c0638..d4507e76e 100644
--- a/src/core/command-generation/adapters/amazon-q.ts
+++ b/src/core/command-generation/adapters/amazon-q.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Amazon Q adapter for command generation.
- * File path: .amazonq/prompts/opsx-.md
+ * File path: .amazonq/prompts/openspec-.md
* Frontmatter: description
*/
export const amazonQAdapter: ToolCommandAdapter = {
toolId: 'amazon-q',
getFilePath(commandId: string): string {
- return path.join('.amazonq', 'prompts', `opsx-${commandId}.md`);
+ return path.join('.amazonq', 'prompts', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/antigravity.ts b/src/core/command-generation/adapters/antigravity.ts
index e7a5d4919..b54abc037 100644
--- a/src/core/command-generation/adapters/antigravity.ts
+++ b/src/core/command-generation/adapters/antigravity.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Antigravity adapter for command generation.
- * File path: .agent/workflows/opsx-.md
+ * File path: .agent/workflows/openspec-.md
* Frontmatter: description
*/
export const antigravityAdapter: ToolCommandAdapter = {
toolId: 'antigravity',
getFilePath(commandId: string): string {
- return path.join('.agent', 'workflows', `opsx-${commandId}.md`);
+ return path.join('.agent', 'workflows', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/auggie.ts b/src/core/command-generation/adapters/auggie.ts
index 2a52104c0..4b98143e7 100644
--- a/src/core/command-generation/adapters/auggie.ts
+++ b/src/core/command-generation/adapters/auggie.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Auggie adapter for command generation.
- * File path: .augment/commands/opsx-.md
+ * File path: .augment/commands/openspec-.md
* Frontmatter: description, argument-hint
*/
export const auggieAdapter: ToolCommandAdapter = {
toolId: 'auggie',
getFilePath(commandId: string): string {
- return path.join('.augment', 'commands', `opsx-${commandId}.md`);
+ return path.join('.augment', 'commands', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/claude.ts b/src/core/command-generation/adapters/claude.ts
index 532b3a47b..d328184fd 100644
--- a/src/core/command-generation/adapters/claude.ts
+++ b/src/core/command-generation/adapters/claude.ts
@@ -32,14 +32,14 @@ function formatTagsArray(tags: string[]): string {
/**
* Claude Code adapter for command generation.
- * File path: .claude/commands/opsx/.md
+ * File path: .claude/commands/openspec/.md
* Frontmatter: name, description, category, tags
*/
export const claudeAdapter: ToolCommandAdapter = {
toolId: 'claude',
getFilePath(commandId: string): string {
- return path.join('.claude', 'commands', 'opsx', `${commandId}.md`);
+ return path.join('.claude', 'commands', 'openspec', `${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/cline.ts b/src/core/command-generation/adapters/cline.ts
index abc643164..1aa9df582 100644
--- a/src/core/command-generation/adapters/cline.ts
+++ b/src/core/command-generation/adapters/cline.ts
@@ -10,14 +10,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Cline adapter for command generation.
- * File path: .clinerules/workflows/opsx-.md
+ * File path: .clinerules/workflows/openspec-.md
* Format: Markdown header with description
*/
export const clineAdapter: ToolCommandAdapter = {
toolId: 'cline',
getFilePath(commandId: string): string {
- return path.join('.clinerules', 'workflows', `opsx-${commandId}.md`);
+ return path.join('.clinerules', 'workflows', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/codebuddy.ts b/src/core/command-generation/adapters/codebuddy.ts
index 54b7eebdc..2ac3c184b 100644
--- a/src/core/command-generation/adapters/codebuddy.ts
+++ b/src/core/command-generation/adapters/codebuddy.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* CodeBuddy adapter for command generation.
- * File path: .codebuddy/commands/opsx/.md
+ * File path: .codebuddy/commands/openspec/.md
* Frontmatter: name, description, argument-hint
*/
export const codebuddyAdapter: ToolCommandAdapter = {
toolId: 'codebuddy',
getFilePath(commandId: string): string {
- return path.join('.codebuddy', 'commands', 'opsx', `${commandId}.md`);
+ return path.join('.codebuddy', 'commands', 'openspec', `${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/codex.ts b/src/core/command-generation/adapters/codex.ts
index 64e73550b..ec588b990 100644
--- a/src/core/command-generation/adapters/codex.ts
+++ b/src/core/command-generation/adapters/codex.ts
@@ -22,14 +22,14 @@ function getCodexHome(): string {
/**
* Codex adapter for command generation.
- * File path: /prompts/opsx-.md (absolute, global)
+ * File path: /prompts/openspec-.md (absolute, global)
* Frontmatter: description, argument-hint
*/
export const codexAdapter: ToolCommandAdapter = {
toolId: 'codex',
getFilePath(commandId: string): string {
- return path.join(getCodexHome(), 'prompts', `opsx-${commandId}.md`);
+ return path.join(getCodexHome(), 'prompts', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/continue.ts b/src/core/command-generation/adapters/continue.ts
index f6aac08b0..bab1e3bed 100644
--- a/src/core/command-generation/adapters/continue.ts
+++ b/src/core/command-generation/adapters/continue.ts
@@ -9,19 +9,19 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Continue adapter for command generation.
- * File path: .continue/prompts/opsx-.prompt
+ * File path: .continue/prompts/openspec-.prompt
* Frontmatter: name, description, invokable
*/
export const continueAdapter: ToolCommandAdapter = {
toolId: 'continue',
getFilePath(commandId: string): string {
- return path.join('.continue', 'prompts', `opsx-${commandId}.prompt`);
+ return path.join('.continue', 'prompts', `openspec-${commandId}.prompt`);
},
formatFile(content: CommandContent): string {
return `---
-name: opsx-${content.id}
+name: openspec-${content.id}
description: ${content.description}
invokable: true
---
diff --git a/src/core/command-generation/adapters/costrict.ts b/src/core/command-generation/adapters/costrict.ts
index 17628a124..f5afad716 100644
--- a/src/core/command-generation/adapters/costrict.ts
+++ b/src/core/command-generation/adapters/costrict.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* CoStrict adapter for command generation.
- * File path: .cospec/openspec/commands/opsx-.md
+ * File path: .cospec/openspec/commands/openspec-.md
* Frontmatter: description, argument-hint
*/
export const costrictAdapter: ToolCommandAdapter = {
toolId: 'costrict',
getFilePath(commandId: string): string {
- return path.join('.cospec', 'openspec', 'commands', `opsx-${commandId}.md`);
+ return path.join('.cospec', 'openspec', 'commands', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/crush.ts b/src/core/command-generation/adapters/crush.ts
index b4d1a0b9d..4ff77f0ec 100644
--- a/src/core/command-generation/adapters/crush.ts
+++ b/src/core/command-generation/adapters/crush.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Crush adapter for command generation.
- * File path: .crush/commands/opsx/.md
+ * File path: .crush/commands/openspec/.md
* Frontmatter: name, description, category, tags
*/
export const crushAdapter: ToolCommandAdapter = {
toolId: 'crush',
getFilePath(commandId: string): string {
- return path.join('.crush', 'commands', 'opsx', `${commandId}.md`);
+ return path.join('.crush', 'commands', 'openspec', `${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/cursor.ts b/src/core/command-generation/adapters/cursor.ts
index 85adedb03..1773faad4 100644
--- a/src/core/command-generation/adapters/cursor.ts
+++ b/src/core/command-generation/adapters/cursor.ts
@@ -25,20 +25,20 @@ function escapeYamlValue(value: string): string {
/**
* Cursor adapter for command generation.
- * File path: .cursor/commands/opsx-.md
- * Frontmatter: name (as /opsx-), id, category, description
+ * File path: .cursor/commands/openspec-.md
+ * Frontmatter: name (as /openspec-), id, category, description
*/
export const cursorAdapter: ToolCommandAdapter = {
toolId: 'cursor',
getFilePath(commandId: string): string {
- return path.join('.cursor', 'commands', `opsx-${commandId}.md`);
+ return path.join('.cursor', 'commands', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
return `---
-name: /opsx-${content.id}
-id: opsx-${content.id}
+name: /openspec-${content.id}
+id: openspec-${content.id}
category: ${escapeYamlValue(content.category)}
description: ${escapeYamlValue(content.description)}
---
diff --git a/src/core/command-generation/adapters/factory.ts b/src/core/command-generation/adapters/factory.ts
index 5031d5dc7..48130abc7 100644
--- a/src/core/command-generation/adapters/factory.ts
+++ b/src/core/command-generation/adapters/factory.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Factory adapter for command generation.
- * File path: .factory/commands/opsx-.md
+ * File path: .factory/commands/openspec-.md
* Frontmatter: description, argument-hint
*/
export const factoryAdapter: ToolCommandAdapter = {
toolId: 'factory',
getFilePath(commandId: string): string {
- return path.join('.factory', 'commands', `opsx-${commandId}.md`);
+ return path.join('.factory', 'commands', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/gemini.ts b/src/core/command-generation/adapters/gemini.ts
index 2c08656f4..1f2b066fb 100644
--- a/src/core/command-generation/adapters/gemini.ts
+++ b/src/core/command-generation/adapters/gemini.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Gemini adapter for command generation.
- * File path: .gemini/commands/opsx/.toml
+ * File path: .gemini/commands/openspec/.toml
* Format: TOML with description and prompt fields
*/
export const geminiAdapter: ToolCommandAdapter = {
toolId: 'gemini',
getFilePath(commandId: string): string {
- return path.join('.gemini', 'commands', 'opsx', `${commandId}.toml`);
+ return path.join('.gemini', 'commands', 'openspec', `${commandId}.toml`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/github-copilot.ts b/src/core/command-generation/adapters/github-copilot.ts
index 4eac7f1b6..c0202d0db 100644
--- a/src/core/command-generation/adapters/github-copilot.ts
+++ b/src/core/command-generation/adapters/github-copilot.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* GitHub Copilot adapter for command generation.
- * File path: .github/prompts/opsx-.prompt.md
+ * File path: .github/prompts/openspec-.prompt.md
* Frontmatter: description
*/
export const githubCopilotAdapter: ToolCommandAdapter = {
toolId: 'github-copilot',
getFilePath(commandId: string): string {
- return path.join('.github', 'prompts', `opsx-${commandId}.prompt.md`);
+ return path.join('.github', 'prompts', `openspec-${commandId}.prompt.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/iflow.ts b/src/core/command-generation/adapters/iflow.ts
index d60a3f0b1..db98d36a9 100644
--- a/src/core/command-generation/adapters/iflow.ts
+++ b/src/core/command-generation/adapters/iflow.ts
@@ -9,20 +9,20 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* iFlow adapter for command generation.
- * File path: .iflow/commands/opsx-.md
+ * File path: .iflow/commands/openspec-.md
* Frontmatter: name, id, category, description
*/
export const iflowAdapter: ToolCommandAdapter = {
toolId: 'iflow',
getFilePath(commandId: string): string {
- return path.join('.iflow', 'commands', `opsx-${commandId}.md`);
+ return path.join('.iflow', 'commands', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
return `---
-name: /opsx-${content.id}
-id: opsx-${content.id}
+name: /openspec-${content.id}
+id: openspec-${content.id}
category: ${content.category}
description: ${content.description}
---
diff --git a/src/core/command-generation/adapters/kilocode.ts b/src/core/command-generation/adapters/kilocode.ts
index bb60c4dd7..0faea8eca 100644
--- a/src/core/command-generation/adapters/kilocode.ts
+++ b/src/core/command-generation/adapters/kilocode.ts
@@ -10,14 +10,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Kilo Code adapter for command generation.
- * File path: .kilocode/workflows/opsx-.md
+ * File path: .kilocode/workflows/openspec-.md
* Format: Plain markdown without frontmatter
*/
export const kilocodeAdapter: ToolCommandAdapter = {
toolId: 'kilocode',
getFilePath(commandId: string): string {
- return path.join('.kilocode', 'workflows', `opsx-${commandId}.md`);
+ return path.join('.kilocode', 'workflows', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/kiro.ts b/src/core/command-generation/adapters/kiro.ts
index 2e8a4ca4c..6a6a37cc5 100644
--- a/src/core/command-generation/adapters/kiro.ts
+++ b/src/core/command-generation/adapters/kiro.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Kiro adapter for command generation.
- * File path: .kiro/prompts/opsx-.prompt.md
+ * File path: .kiro/prompts/openspec-.prompt.md
* Frontmatter: description
*/
export const kiroAdapter: ToolCommandAdapter = {
toolId: 'kiro',
getFilePath(commandId: string): string {
- return path.join('.kiro', 'prompts', `opsx-${commandId}.prompt.md`);
+ return path.join('.kiro', 'prompts', `openspec-${commandId}.prompt.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/opencode.ts b/src/core/command-generation/adapters/opencode.ts
index 301664b47..6af24e0dc 100644
--- a/src/core/command-generation/adapters/opencode.ts
+++ b/src/core/command-generation/adapters/opencode.ts
@@ -10,14 +10,14 @@ import { transformToHyphenCommands } from '../../../utils/command-references.js'
/**
* OpenCode adapter for command generation.
- * File path: .opencode/commands/opsx-.md
+ * File path: .opencode/commands/openspec-.md
* Frontmatter: description
*/
export const opencodeAdapter: ToolCommandAdapter = {
toolId: 'opencode',
getFilePath(commandId: string): string {
- return path.join('.opencode', 'commands', `opsx-${commandId}.md`);
+ return path.join('.opencode', 'commands', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/pi.ts b/src/core/command-generation/adapters/pi.ts
index cb8d2b331..e873f1ff5 100644
--- a/src/core/command-generation/adapters/pi.ts
+++ b/src/core/command-generation/adapters/pi.ts
@@ -25,14 +25,14 @@ function escapeYamlValue(value: string): string {
/**
* Pi adapter for prompt template generation.
- * File path: .pi/prompts/opsx-.md
+ * File path: .pi/prompts/openspec-.md
* Frontmatter: description
*/
export const piAdapter: ToolCommandAdapter = {
toolId: 'pi',
getFilePath(commandId: string): string {
- return path.join('.pi', 'prompts', `opsx-${commandId}.md`);
+ return path.join('.pi', 'prompts', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/qoder.ts b/src/core/command-generation/adapters/qoder.ts
index 608fc9ae2..8438068f0 100644
--- a/src/core/command-generation/adapters/qoder.ts
+++ b/src/core/command-generation/adapters/qoder.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Qoder adapter for command generation.
- * File path: .qoder/commands/opsx/.md
+ * File path: .qoder/commands/openspec/.md
* Frontmatter: name, description, category, tags
*/
export const qoderAdapter: ToolCommandAdapter = {
toolId: 'qoder',
getFilePath(commandId: string): string {
- return path.join('.qoder', 'commands', 'opsx', `${commandId}.md`);
+ return path.join('.qoder', 'commands', 'openspec', `${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/qwen.ts b/src/core/command-generation/adapters/qwen.ts
index 0ee640b3c..675d3e6ac 100644
--- a/src/core/command-generation/adapters/qwen.ts
+++ b/src/core/command-generation/adapters/qwen.ts
@@ -9,14 +9,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* Qwen adapter for command generation.
- * File path: .qwen/commands/opsx-.toml
+ * File path: .qwen/commands/openspec-.toml
* Format: TOML with description and prompt fields
*/
export const qwenAdapter: ToolCommandAdapter = {
toolId: 'qwen',
getFilePath(commandId: string): string {
- return path.join('.qwen', 'commands', `opsx-${commandId}.toml`);
+ return path.join('.qwen', 'commands', `openspec-${commandId}.toml`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/roocode.ts b/src/core/command-generation/adapters/roocode.ts
index 529298578..b20a62f91 100644
--- a/src/core/command-generation/adapters/roocode.ts
+++ b/src/core/command-generation/adapters/roocode.ts
@@ -10,14 +10,14 @@ import type { CommandContent, ToolCommandAdapter } from '../types.js';
/**
* RooCode adapter for command generation.
- * File path: .roo/commands/opsx-.md
+ * File path: .roo/commands/openspec-.md
* Format: Markdown header with description
*/
export const roocodeAdapter: ToolCommandAdapter = {
toolId: 'roocode',
getFilePath(commandId: string): string {
- return path.join('.roo', 'commands', `opsx-${commandId}.md`);
+ return path.join('.roo', 'commands', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/adapters/windsurf.ts b/src/core/command-generation/adapters/windsurf.ts
index 59c86d8e0..e20c3d1b7 100644
--- a/src/core/command-generation/adapters/windsurf.ts
+++ b/src/core/command-generation/adapters/windsurf.ts
@@ -33,14 +33,14 @@ function formatTagsArray(tags: string[]): string {
/**
* Windsurf adapter for command generation.
- * File path: .windsurf/workflows/opsx-.md
+ * File path: .windsurf/workflows/openspec-.md
* Frontmatter: name, description, category, tags
*/
export const windsurfAdapter: ToolCommandAdapter = {
toolId: 'windsurf',
getFilePath(commandId: string): string {
- return path.join('.windsurf', 'workflows', `opsx-${commandId}.md`);
+ return path.join('.windsurf', 'workflows', `openspec-${commandId}.md`);
},
formatFile(content: CommandContent): string {
diff --git a/src/core/command-generation/types.ts b/src/core/command-generation/types.ts
index 582d8c784..37e8fc220 100644
--- a/src/core/command-generation/types.ts
+++ b/src/core/command-generation/types.ts
@@ -35,7 +35,7 @@ export interface ToolCommandAdapter {
/**
* Returns the file path for a command.
* @param commandId - The command identifier (e.g., 'explore')
- * @returns Path from project root (e.g., '.claude/commands/opsx/explore.md').
+ * @returns Path from project root (e.g., '.claude/commands/openspec/explore.md').
* May be absolute for tools with global-scoped prompts (e.g., Codex).
*/
getFilePath(commandId: string): string;
diff --git a/src/core/init.ts b/src/core/init.ts
index 95728dc7e..d1f5b713f 100644
--- a/src/core/init.ts
+++ b/src/core/init.ts
@@ -1,7 +1,7 @@
/**
* Init Command
*
- * Sets up OpenSpec with Agent Skills and /opsx:* slash commands.
+ * Sets up OpenSpec with Agent Skills and /openspec:* slash commands.
* This is the unified setup command that replaces both the old init and experimental commands.
*/
@@ -703,10 +703,10 @@ export class InitCommand {
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: /openspec: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: /openspec:new "your idea"');
} else {
console.log("Done. Run 'openspec config profile' to configure your workflows.");
}
diff --git a/src/core/legacy-cleanup.ts b/src/core/legacy-cleanup.ts
index b165b9e99..bf0ccaf73 100644
--- a/src/core/legacy-cleanup.ts
+++ b/src/core/legacy-cleanup.ts
@@ -30,31 +30,31 @@ export const LEGACY_CONFIG_FILES = [
* Some tools used a directory structure, others used individual files.
*/
export const LEGACY_SLASH_COMMAND_PATHS: Record = {
- // Directory-based: .tooldir/commands/openspec/ or .tooldir/commands/openspec/*.md
- 'claude': { type: 'directory', path: '.claude/commands/openspec' },
- 'codebuddy': { type: 'directory', path: '.codebuddy/commands/openspec' },
- 'qoder': { type: 'directory', path: '.qoder/commands/openspec' },
- 'crush': { type: 'directory', path: '.crush/commands/openspec' },
- 'gemini': { type: 'directory', path: '.gemini/commands/openspec' },
+ // Directory-based: .tooldir/commands/opsx/ or .tooldir/commands/opsx/*.md
+ 'claude': { type: 'directory', path: '.claude/commands/opsx' },
+ 'codebuddy': { type: 'directory', path: '.codebuddy/commands/opsx' },
+ 'qoder': { type: 'directory', path: '.qoder/commands/opsx' },
+ 'crush': { type: 'directory', path: '.crush/commands/opsx' },
+ 'gemini': { type: 'directory', path: '.gemini/commands/opsx' },
'costrict': { type: 'directory', path: '.cospec/openspec/commands' },
- // File-based: individual openspec-*.md files in a commands/workflows/prompts folder
- 'cursor': { type: 'files', pattern: '.cursor/commands/openspec-*.md' },
- 'windsurf': { type: 'files', pattern: '.windsurf/workflows/openspec-*.md' },
- 'kilocode': { type: 'files', pattern: '.kilocode/workflows/openspec-*.md' },
- 'kiro': { type: 'files', pattern: '.kiro/prompts/openspec-*.prompt.md' },
- 'github-copilot': { type: 'files', pattern: '.github/prompts/openspec-*.prompt.md' },
- 'amazon-q': { type: 'files', pattern: '.amazonq/prompts/openspec-*.md' },
- 'cline': { type: 'files', pattern: '.clinerules/workflows/openspec-*.md' },
- 'roocode': { type: 'files', pattern: '.roo/commands/openspec-*.md' },
- 'auggie': { type: 'files', pattern: '.augment/commands/openspec-*.md' },
- 'factory': { type: 'files', pattern: '.factory/commands/openspec-*.md' },
+ // File-based: individual opsx-*.md files in a commands/workflows/prompts folder
+ 'cursor': { type: 'files', pattern: '.cursor/commands/opsx-*.md' },
+ 'windsurf': { type: 'files', pattern: '.windsurf/workflows/opsx-*.md' },
+ 'kilocode': { type: 'files', pattern: '.kilocode/workflows/opsx-*.md' },
+ 'kiro': { type: 'files', pattern: '.kiro/prompts/opsx-*.prompt.md' },
+ 'github-copilot': { type: 'files', pattern: '.github/prompts/opsx-*.prompt.md' },
+ 'amazon-q': { type: 'files', pattern: '.amazonq/prompts/opsx-*.md' },
+ 'cline': { type: 'files', pattern: '.clinerules/workflows/opsx-*.md' },
+ 'roocode': { type: 'files', pattern: '.roo/commands/opsx-*.md' },
+ 'auggie': { type: 'files', pattern: '.augment/commands/opsx-*.md' },
+ 'factory': { type: 'files', pattern: '.factory/commands/opsx-*.md' },
'opencode': { type: 'files', pattern: ['.opencode/command/opsx-*.md', '.opencode/command/openspec-*.md'] },
- 'continue': { type: 'files', pattern: '.continue/prompts/openspec-*.prompt' },
- 'antigravity': { type: 'files', pattern: '.agent/workflows/openspec-*.md' },
- 'iflow': { type: 'files', pattern: '.iflow/commands/openspec-*.md' },
- 'qwen': { type: 'files', pattern: '.qwen/commands/openspec-*.toml' },
- 'codex': { type: 'files', pattern: '.codex/prompts/openspec-*.md' },
+ 'continue': { type: 'files', pattern: '.continue/prompts/opsx-*.prompt' },
+ 'antigravity': { type: 'files', pattern: '.agent/workflows/opsx-*.md' },
+ 'iflow': { type: 'files', pattern: '.iflow/commands/opsx-*.md' },
+ 'qwen': { type: 'files', pattern: '.qwen/commands/opsx-*.toml' },
+ 'codex': { type: 'files', pattern: '.codex/prompts/opsx-*.md' },
};
/**
@@ -445,7 +445,7 @@ export function formatCleanupSummary(result: CleanupResult): string {
}
for (const dir of result.deletedDirs) {
- lines.push(` ✓ Removed ${dir}/ (replaced by /opsx:*)`);
+ lines.push(` ✓ Removed ${dir}/ (replaced by /openspec:*)`);
}
for (const file of result.modifiedFiles) {
diff --git a/src/core/migration.ts b/src/core/migration.ts
index 48aaa41ee..049ce5b27 100644
--- a/src/core/migration.ts
+++ b/src/core/migration.ts
@@ -127,5 +127,5 @@ 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.");
+ console.log("New in this version: /openspec:propose. Try 'openspec config profile core' for the streamlined experience.");
}
diff --git a/src/core/templates/workflows/apply-change.ts b/src/core/templates/workflows/apply-change.ts
index c5044698a..5cff50d01 100644
--- a/src/core/templates/workflows/apply-change.ts
+++ b/src/core/templates/workflows/apply-change.ts
@@ -23,7 +23,7 @@ export function getApplyChangeSkillTemplate(): SkillTemplate {
- 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: " and how to override (e.g., \`/opsx:apply \`).
+ Always announce: "Using change: " and how to override (e.g., \`/openspec:apply \`).
2. **Check status to understand the schema**
\`\`\`bash
@@ -163,13 +163,13 @@ This skill supports the "actions on a change" model:
export function getOpsxApplyCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Apply',
+ name: 'OpenSpec: Apply',
description: 'Implement tasks from an OpenSpec change (Experimental)',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
content: `Implement tasks from an OpenSpec change.
-**Input**: Optionally specify a change name (e.g., \`/opsx:apply add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Input**: Optionally specify a change name (e.g., \`/openspec:apply add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
@@ -180,7 +180,7 @@ export function getOpsxApplyCommandTemplate(): CommandTemplate {
- 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: " and how to override (e.g., \`/opsx:apply \`).
+ Always announce: "Using change: " and how to override (e.g., \`/openspec:apply \`).
2. **Check status to understand the schema**
\`\`\`bash
@@ -203,7 +203,7 @@ export function getOpsxApplyCommandTemplate(): CommandTemplate {
- Dynamic instruction based on current state
**Handle states:**
- - If \`state: "blocked"\` (missing artifacts): show message, suggest using \`/opsx:continue\`
+ - If \`state: "blocked"\` (missing artifacts): show message, suggest using \`/openspec:continue\`
- If \`state: "all_done"\`: congratulate, suggest archive
- Otherwise: proceed to implementation
@@ -273,7 +273,7 @@ Working on task 4/7:
- [x] Task 2
...
-All tasks complete! You can archive this change with \`/opsx:archive\`.
+All tasks complete! You can archive this change with \`/openspec:archive\`.
\`\`\`
**Output On Pause (Issue Encountered)**
diff --git a/src/core/templates/workflows/archive-change.ts b/src/core/templates/workflows/archive-change.ts
index 1c37ffde0..908d29aad 100644
--- a/src/core/templates/workflows/archive-change.ts
+++ b/src/core/templates/workflows/archive-change.ts
@@ -121,13 +121,13 @@ All artifacts complete. All tasks complete.
export function getOpsxArchiveCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Archive',
+ name: 'OpenSpec: Archive',
description: 'Archive a completed change in the experimental workflow',
category: 'Workflow',
tags: ['workflow', 'archive', 'experimental'],
content: `Archive a completed change in the experimental workflow.
-**Input**: Optionally specify a change name after \`/opsx:archive\` (e.g., \`/opsx:archive add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Input**: Optionally specify a change name after \`/openspec:archive\` (e.g., \`/openspec:archive add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
diff --git a/src/core/templates/workflows/bulk-archive-change.ts b/src/core/templates/workflows/bulk-archive-change.ts
index d57db8aa0..6124d91e4 100644
--- a/src/core/templates/workflows/bulk-archive-change.ts
+++ b/src/core/templates/workflows/bulk-archive-change.ts
@@ -253,7 +253,7 @@ No active changes found. Create a new change to get started.
export function getOpsxBulkArchiveCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Bulk Archive',
+ name: 'OpenSpec: Bulk Archive',
description: 'Archive multiple completed changes at once',
category: 'Workflow',
tags: ['workflow', 'archive', 'experimental', 'bulk'],
diff --git a/src/core/templates/workflows/continue-change.ts b/src/core/templates/workflows/continue-change.ts
index 4b2176728..c2940f6a2 100644
--- a/src/core/templates/workflows/continue-change.ts
+++ b/src/core/templates/workflows/continue-change.ts
@@ -125,13 +125,13 @@ For other schemas, follow the \`instruction\` field from the CLI output.
export function getOpsxContinueCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Continue',
+ name: 'OpenSpec: Continue',
description: 'Continue working on a change - create the next artifact (Experimental)',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
content: `Continue working on a change by creating the next artifact.
-**Input**: Optionally specify a change name after \`/opsx:continue\` (e.g., \`/opsx:continue add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Input**: Optionally specify a change name after \`/openspec:continue\` (e.g., \`/openspec:continue add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
@@ -165,7 +165,7 @@ export function getOpsxContinueCommandTemplate(): CommandTemplate {
**If all artifacts are complete (\`isComplete: true\`)**:
- Congratulate the user
- Show final status including the schema used
- - Suggest: "All artifacts created! You can now implement this change with \`/opsx:apply\` or archive it with \`/opsx:archive\`."
+ - Suggest: "All artifacts created! You can now implement this change with \`/openspec:apply\` or archive it with \`/openspec:archive\`."
- STOP
---
@@ -209,7 +209,7 @@ After each invocation, show:
- Schema workflow being used
- Current progress (N/M complete)
- What artifacts are now unlocked
-- Prompt: "Run \`/opsx:continue\` to create the next artifact"
+- Prompt: "Run \`/openspec:continue\` to create the next artifact"
**Artifact Creation Guidelines**
diff --git a/src/core/templates/workflows/explore.ts b/src/core/templates/workflows/explore.ts
index 059d2ecae..d722f2f24 100644
--- a/src/core/templates/workflows/explore.ts
+++ b/src/core/templates/workflows/explore.ts
@@ -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]
@@ -295,7 +295,7 @@ But this summary is optional. Sometimes the thinking IS the value.
export function getOpsxExploreCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Explore',
+ name: 'OpenSpec: Explore',
description: 'Enter explore mode - think through ideas, investigate problems, clarify requirements',
category: 'Workflow',
tags: ['workflow', 'explore', 'experimental', 'thinking'],
@@ -305,7 +305,7 @@ export function getOpsxExploreCommandTemplate(): CommandTemplate {
**This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
-**Input**: The argument after \`/opsx:explore\` is whatever the user wants to think about. Could be:
+**Input**: The argument after \`/openspec:explore\` is whatever the user wants to think about. Could be:
- A vague idea: "real-time collaboration"
- A specific problem: "the auth system is getting unwieldy"
- A change name: "add-dark-mode" (to explore in context of that change)
diff --git a/src/core/templates/workflows/ff-change.ts b/src/core/templates/workflows/ff-change.ts
index 9e02983be..a8c7e7562 100644
--- a/src/core/templates/workflows/ff-change.ts
+++ b/src/core/templates/workflows/ff-change.ts
@@ -82,7 +82,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\` or ask me to implement to start working on the tasks."
**Artifact Creation Guidelines**
@@ -108,13 +108,13 @@ After completing all artifacts, summarize:
export function getOpsxFfCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Fast Forward',
+ name: 'OpenSpec: Fast Forward',
description: 'Create a change and generate all artifacts needed for implementation in one go',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
content: `Fast-forward through artifact creation - generate everything needed to start implementation.
-**Input**: The argument after \`/opsx:ff\` is the change name (kebab-case), OR a description of what the user wants to build.
+**Input**: The argument after \`/openspec:ff\` is the change name (kebab-case), OR a description of what the user wants to build.
**Steps**
@@ -184,7 +184,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\` to start implementing."
+- Prompt: "Run \`/openspec:apply\` to start implementing."
**Artifact Creation Guidelines**
diff --git a/src/core/templates/workflows/new-change.ts b/src/core/templates/workflows/new-change.ts
index 10017422f..75e882359 100644
--- a/src/core/templates/workflows/new-change.ts
+++ b/src/core/templates/workflows/new-change.ts
@@ -81,13 +81,13 @@ After completing the steps, summarize:
export function getOpsxNewCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: New',
+ name: 'OpenSpec: New',
description: 'Start a new change using the experimental artifact workflow (OPSX)',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
content: `Start a new change using the experimental artifact-driven approach.
-**Input**: The argument after \`/opsx:new\` is the change name (kebab-case), OR a description of what the user wants to build.
+**Input**: The argument after \`/openspec:new\` is the change name (kebab-case), OR a description of what the user wants to build.
**Steps**
@@ -139,13 +139,13 @@ After completing the steps, summarize:
- Schema/workflow being used and its artifact sequence
- Current status (0/N artifacts complete)
- The template for the first artifact
-- Prompt: "Ready to create the first artifact? Run \`/opsx:continue\` or just describe what this change is about and I'll draft it."
+- Prompt: "Ready to create the first artifact? Run \`/openspec:continue\` or just describe what this change is about and I'll draft it."
**Guardrails**
- Do NOT create any artifacts yet - just show the instructions
- Do NOT advance beyond showing the first artifact template
- If the name is invalid (not kebab-case), ask for a valid name
-- If a change with that name already exists, suggest using \`/opsx:continue\` instead
+- If a change with that name already exists, suggest using \`/openspec:continue\` instead
- Pass --schema if using a non-default workflow`
};
}
diff --git a/src/core/templates/workflows/onboard.ts b/src/core/templates/workflows/onboard.ts
index f9280fa07..b3ae0f21f 100644
--- a/src/core/templates/workflows/onboard.ts
+++ b/src/core/templates/workflows/onboard.ts
@@ -34,7 +34,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.
@@ -161,7 +161,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.
\`\`\`
@@ -479,25 +479,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\` | Implement tasks from a change |
+| \`/openspec:archive\` | 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\` | Start a new change, step through artifacts one at a time |
+| \`/openspec:continue\` | Continue working on an existing change |
+| \`/openspec:ff\` | Fast-forward: create all artifacts at once |
+| \`/openspec:verify\` | 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!
\`\`\`
---
@@ -512,8 +512,8 @@ If the user says they need to stop, want to pause, or seem disengaged:
No problem! Your change is saved at \`openspec/changes//\`.
To pick up where we left off later:
-- \`/opsx:continue \` - Resume artifact creation
-- \`/opsx:apply \` - Jump to implementation (if tasks exist)
+- \`/openspec:continue \` - Resume artifact creation
+- \`/openspec:apply \` - Jump to implementation (if tasks exist)
The work won't be lost. Come back whenever you're ready.
\`\`\`
@@ -531,21 +531,21 @@ If the user says they just want to see the commands or skip the tutorial:
| Command | What it does |
|---------|--------------|
-| \`/opsx:propose \` | Create a change and generate all artifacts |
-| \`/opsx:explore\` | Think through problems (no code changes) |
-| \`/opsx:apply \` | Implement tasks |
-| \`/opsx:archive \` | Archive when done |
+| \`/openspec:propose \` | Create a change and generate all artifacts |
+| \`/openspec:explore\` | Think through problems (no code changes) |
+| \`/openspec:apply \` | Implement tasks |
+| \`/openspec:archive \` | Archive when done |
**Additional commands:**
| Command | What it does |
|---------|--------------|
-| \`/opsx:new \` | Start a new change, step by step |
-| \`/opsx:continue \` | Continue an existing change |
-| \`/opsx:ff \` | Fast-forward: all artifacts at once |
-| \`/opsx:verify \` | Verify implementation |
+| \`/openspec:new \` | Start a new change, step by step |
+| \`/openspec:continue \` | Continue an existing change |
+| \`/openspec:ff \` | Fast-forward: all artifacts at once |
+| \`/openspec:verify \` | Verify implementation |
-Try \`/opsx:propose\` to start your first change.
+Try \`/openspec:propose\` to start your first change.
\`\`\`
Exit gracefully.
@@ -565,7 +565,7 @@ Exit gracefully.
export function getOpsxOnboardCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Onboard',
+ name: 'OpenSpec: Onboard',
description: 'Guided onboarding - walk through a complete OpenSpec workflow cycle with narration',
category: 'Workflow',
tags: ['workflow', 'onboarding', 'tutorial', 'learning'],
diff --git a/src/core/templates/workflows/propose.ts b/src/core/templates/workflows/propose.ts
index 74a9ce2d0..cb2c23cf2 100644
--- a/src/core/templates/workflows/propose.ts
+++ b/src/core/templates/workflows/propose.ts
@@ -17,7 +17,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
---
@@ -91,7 +91,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\` or ask me to implement to start working on the tasks."
**Artifact Creation Guidelines**
@@ -117,7 +117,7 @@ After completing all artifacts, summarize:
export function getOpsxProposeCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Propose',
+ name: 'OpenSpec: Propose',
description: 'Propose a new change - create it and generate all artifacts in one step',
category: 'Workflow',
tags: ['workflow', 'artifacts', 'experimental'],
@@ -128,11 +128,11 @@ 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
---
-**Input**: The argument after \`/opsx:propose\` is the change name (kebab-case), OR a description of what the user wants to build.
+**Input**: The argument after \`/openspec:propose\` is the change name (kebab-case), OR a description of what the user wants to build.
**Steps**
@@ -202,7 +202,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\` to start implementing."
+- Prompt: "Run \`/openspec:apply\` to start implementing."
**Artifact Creation Guidelines**
diff --git a/src/core/templates/workflows/sync-specs.ts b/src/core/templates/workflows/sync-specs.ts
index 34da4276e..a317727e9 100644
--- a/src/core/templates/workflows/sync-specs.ts
+++ b/src/core/templates/workflows/sync-specs.ts
@@ -145,7 +145,7 @@ Main specs are now updated. The change remains active - archive when implementat
export function getOpsxSyncCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Sync',
+ name: 'OpenSpec: Sync',
description: 'Sync delta specs from a change to main specs',
category: 'Workflow',
tags: ['workflow', 'specs', 'experimental'],
@@ -153,7 +153,7 @@ export function getOpsxSyncCommandTemplate(): CommandTemplate {
This is an **agent-driven** operation - you will read delta specs and directly edit main specs to apply the changes. This allows intelligent merging (e.g., adding a scenario without copying the entire requirement).
-**Input**: Optionally specify a change name after \`/opsx:sync\` (e.g., \`/opsx:sync add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Input**: Optionally specify a change name after \`/openspec:sync\` (e.g., \`/openspec:sync add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
diff --git a/src/core/templates/workflows/verify-change.ts b/src/core/templates/workflows/verify-change.ts
index 825f7ecca..ae69ef40c 100644
--- a/src/core/templates/workflows/verify-change.ts
+++ b/src/core/templates/workflows/verify-change.ts
@@ -175,13 +175,13 @@ Use clear markdown with:
export function getOpsxVerifyCommandTemplate(): CommandTemplate {
return {
- name: 'OPSX: Verify',
+ name: 'OpenSpec: Verify',
description: 'Verify implementation matches change artifacts before archiving',
category: 'Workflow',
tags: ['workflow', 'verify', 'experimental'],
content: `Verify that an implementation matches the change artifacts (specs, tasks, design).
-**Input**: Optionally specify a change name after \`/opsx:verify\` (e.g., \`/opsx:verify add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
+**Input**: Optionally specify a change name after \`/openspec:verify\` (e.g., \`/openspec:verify add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
**Steps**
diff --git a/src/core/update.ts b/src/core/update.ts
index 62db8a08f..eae25c1c0 100644
--- a/src/core/update.ts
+++ b/src/core/update.ts
@@ -89,7 +89,7 @@ export class UpdateCommand {
}
// 2. Perform one-time migration if needed before any legacy upgrade generation.
- // Use detected tool directories to preserve existing opsx skills/commands.
+ // Use detected tool directories to preserve existing openspec skills/commands.
const detectedTools = getAvailableTools(resolvedProjectPath);
migrateIfNeededShared(resolvedProjectPath, detectedTools);
@@ -268,9 +268,9 @@ export class UpdateCommand {
if (newlyConfiguredTools.length > 0) {
console.log();
console.log(chalk.bold('Getting started:'));
- console.log(' /opsx:new Start a new change');
- console.log(' /opsx:continue Create the next artifact');
- console.log(' /opsx:apply Implement tasks');
+ console.log(' /openspec:new Start a new change');
+ console.log(' /openspec:continue Create the next artifact');
+ console.log(' /openspec:apply Implement tasks');
console.log();
console.log(`Learn more: ${chalk.cyan('https://github.com/Fission-AI/OpenSpec')}`);
}
diff --git a/src/ui/welcome-screen.ts b/src/ui/welcome-screen.ts
index 5ed26b6a1..0510a39d2 100644
--- a/src/ui/welcome-screen.ts
+++ b/src/ui/welcome-screen.ts
@@ -22,12 +22,12 @@ function getWelcomeText(): string[] {
'',
chalk.white('This setup will configure:'),
chalk.dim(' • Agent Skills for AI tools'),
- chalk.dim(' • /opsx:* slash commands'),
+ chalk.dim(' • /openspec:* slash commands'),
'',
chalk.white('Quick start after setup:'),
- ` ${chalk.yellow('/opsx:new')} ${chalk.dim('Create a change')}`,
- ` ${chalk.yellow('/opsx:continue')} ${chalk.dim('Next artifact')}`,
- ` ${chalk.yellow('/opsx:apply')} ${chalk.dim('Implement tasks')}`,
+ ` ${chalk.yellow('/openspec:new')} ${chalk.dim('Create a change')}`,
+ ` ${chalk.yellow('/openspec:continue')} ${chalk.dim('Next artifact')}`,
+ ` ${chalk.yellow('/openspec:apply')} ${chalk.dim('Implement tasks')}`,
'',
chalk.cyan('Press Enter to select tools...'),
];
diff --git a/src/utils/command-references.ts b/src/utils/command-references.ts
index bfa49b9ff..e7a2ff82b 100644
--- a/src/utils/command-references.ts
+++ b/src/utils/command-references.ts
@@ -6,15 +6,15 @@
/**
* Transforms colon-based command references to hyphen-based format.
- * Converts `/opsx:` patterns to `/opsx-` for tools that use hyphen syntax.
+ * Converts `/openspec:` patterns to `/openspec-` for tools that use hyphen syntax.
*
* @param text - The text containing command references
* @returns Text with command references transformed to hyphen format
*
* @example
- * transformToHyphenCommands('/opsx:new') // returns '/opsx-new'
- * transformToHyphenCommands('Use /opsx:apply to implement') // returns 'Use /opsx-apply to implement'
+ * transformToHyphenCommands('/openspec:new') // returns '/openspec-new'
+ * transformToHyphenCommands('Use /openspec:apply to implement') // returns 'Use /openspec-apply to implement'
*/
export function transformToHyphenCommands(text: string): string {
- return text.replace(/\/opsx:/g, '/opsx-');
+ return text.replace(/\/openspec:/g, '/openspec-');
}
diff --git a/test/commands/artifact-workflow.test.ts b/test/commands/artifact-workflow.test.ts
index 17ed97740..d1232ac57 100644
--- a/test/commands/artifact-workflow.test.ts
+++ b/test/commands/artifact-workflow.test.ts
@@ -650,9 +650,9 @@ artifacts:
expect(stat.isFile()).toBe(true);
// Verify commands were created with Cursor format
- const commandFile = path.join(tempDir, '.cursor', 'commands', 'opsx-explore.md');
+ const commandFile = path.join(tempDir, '.cursor', 'commands', 'openspec-explore.md');
const content = await fs.readFile(commandFile, 'utf-8');
- expect(content).toContain('name: /opsx-explore');
+ expect(content).toContain('name: /openspec-explore');
});
it('creates skills for Windsurf tool', async () => {
diff --git a/test/commands/config-profile.test.ts b/test/commands/config-profile.test.ts
index ef116693a..d141a3a72 100644
--- a/test/commands/config-profile.test.ts
+++ b/test/commands/config-profile.test.ts
@@ -105,7 +105,7 @@ describe('config profile interactive flow', () => {
const coreCommands = ['propose', 'explore', 'apply', 'archive'];
for (const commandId of coreCommands) {
- const commandPath = path.join(projectDir, '.claude', 'commands', 'opsx', `${commandId}.md`);
+ const commandPath = path.join(projectDir, '.claude', 'commands', 'openspec', `${commandId}.md`);
fs.mkdirSync(path.dirname(commandPath), { recursive: true });
fs.writeFileSync(commandPath, `# ${commandId}\n`, 'utf-8');
}
@@ -116,7 +116,7 @@ describe('config profile interactive flow', () => {
fs.mkdirSync(path.dirname(syncSkillPath), { recursive: true });
fs.writeFileSync(syncSkillPath, 'name: openspec-sync-specs\n', 'utf-8');
- const syncCommandPath = path.join(projectDir, '.claude', 'commands', 'opsx', 'sync.md');
+ const syncCommandPath = path.join(projectDir, '.claude', 'commands', 'openspec', 'sync.md');
fs.mkdirSync(path.dirname(syncCommandPath), { recursive: true });
fs.writeFileSync(syncCommandPath, '# sync\n', 'utf-8');
}
diff --git a/test/core/command-generation/adapters.test.ts b/test/core/command-generation/adapters.test.ts
index dab19bf3d..71db0dc17 100644
--- a/test/core/command-generation/adapters.test.ts
+++ b/test/core/command-generation/adapters.test.ts
@@ -42,12 +42,12 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = claudeAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.claude', 'commands', 'opsx', 'explore.md'));
+ expect(filePath).toBe(path.join('.claude', 'commands', 'openspec', 'explore.md'));
});
it('should generate correct file path for different command IDs', () => {
- expect(claudeAdapter.getFilePath('new')).toBe(path.join('.claude', 'commands', 'opsx', 'new.md'));
- expect(claudeAdapter.getFilePath('bulk-archive')).toBe(path.join('.claude', 'commands', 'opsx', 'bulk-archive.md'));
+ expect(claudeAdapter.getFilePath('new')).toBe(path.join('.claude', 'commands', 'openspec', 'new.md'));
+ expect(claudeAdapter.getFilePath('bulk-archive')).toBe(path.join('.claude', 'commands', 'openspec', 'bulk-archive.md'));
});
it('should format file with correct YAML frontmatter', () => {
@@ -74,22 +74,22 @@ describe('command-generation/adapters', () => {
expect(cursorAdapter.toolId).toBe('cursor');
});
- it('should generate correct file path with opsx- prefix', () => {
+ it('should generate correct file path with openspec- prefix', () => {
const filePath = cursorAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.cursor', 'commands', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.cursor', 'commands', 'openspec-explore.md'));
});
it('should generate correct file paths for different commands', () => {
- expect(cursorAdapter.getFilePath('new')).toBe(path.join('.cursor', 'commands', 'opsx-new.md'));
- expect(cursorAdapter.getFilePath('bulk-archive')).toBe(path.join('.cursor', 'commands', 'opsx-bulk-archive.md'));
+ expect(cursorAdapter.getFilePath('new')).toBe(path.join('.cursor', 'commands', 'openspec-new.md'));
+ expect(cursorAdapter.getFilePath('bulk-archive')).toBe(path.join('.cursor', 'commands', 'openspec-bulk-archive.md'));
});
it('should format file with Cursor-specific frontmatter', () => {
const output = cursorAdapter.formatFile(sampleContent);
expect(output).toContain('---\n');
- expect(output).toContain('name: /opsx-explore');
- expect(output).toContain('id: opsx-explore');
+ expect(output).toContain('name: /openspec-explore');
+ expect(output).toContain('id: openspec-explore');
expect(output).toContain('category: Workflow');
expect(output).toContain('description: Enter explore mode for thinking');
expect(output).toContain('---\n\n');
@@ -109,7 +109,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = windsurfAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.windsurf', 'workflows', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.windsurf', 'workflows', 'openspec-explore.md'));
});
it('should format file similar to Claude format', () => {
@@ -132,7 +132,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = amazonQAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.amazonq', 'prompts', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.amazonq', 'prompts', 'openspec-explore.md'));
});
it('should format file with description frontmatter', () => {
@@ -151,7 +151,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = antigravityAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.agent', 'workflows', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.agent', 'workflows', 'openspec-explore.md'));
});
it('should format file with description frontmatter', () => {
@@ -170,7 +170,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = auggieAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.augment', 'commands', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.augment', 'commands', 'openspec-explore.md'));
});
it('should format file with description and argument-hint', () => {
@@ -190,7 +190,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = clineAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.clinerules', 'workflows', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.clinerules', 'workflows', 'openspec-explore.md'));
});
it('should format file with markdown header (no YAML frontmatter)', () => {
@@ -214,7 +214,7 @@ describe('command-generation/adapters', () => {
it('should generate path ending with correct structure', () => {
const filePath = codexAdapter.getFilePath('explore');
- expect(filePath).toMatch(/prompts[/\\]opsx-explore\.md$/);
+ expect(filePath).toMatch(/prompts[/\\]openspec-explore\.md$/);
});
it('should default to homedir/.codex', () => {
@@ -222,7 +222,7 @@ describe('command-generation/adapters', () => {
delete process.env.CODEX_HOME;
try {
const filePath = codexAdapter.getFilePath('explore');
- const expected = path.join(os.homedir(), '.codex', 'prompts', 'opsx-explore.md');
+ const expected = path.join(os.homedir(), '.codex', 'prompts', 'openspec-explore.md');
expect(filePath).toBe(expected);
} finally {
if (original !== undefined) {
@@ -236,7 +236,7 @@ describe('command-generation/adapters', () => {
process.env.CODEX_HOME = '/custom/codex-home';
try {
const filePath = codexAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join(path.resolve('/custom/codex-home'), 'prompts', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join(path.resolve('/custom/codex-home'), 'prompts', 'openspec-explore.md'));
} finally {
if (original !== undefined) {
process.env.CODEX_HOME = original;
@@ -261,9 +261,9 @@ describe('command-generation/adapters', () => {
expect(codebuddyAdapter.toolId).toBe('codebuddy');
});
- it('should generate correct file path with nested opsx folder', () => {
+ it('should generate correct file path with nested openspec folder', () => {
const filePath = codebuddyAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.codebuddy', 'commands', 'opsx', 'explore.md'));
+ expect(filePath).toBe(path.join('.codebuddy', 'commands', 'openspec', 'explore.md'));
});
it('should format file with name, description, and argument-hint', () => {
@@ -284,13 +284,13 @@ describe('command-generation/adapters', () => {
it('should generate correct file path with .prompt extension', () => {
const filePath = continueAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.continue', 'prompts', 'opsx-explore.prompt'));
+ expect(filePath).toBe(path.join('.continue', 'prompts', 'openspec-explore.prompt'));
});
it('should format file with name, description, and invokable', () => {
const output = continueAdapter.formatFile(sampleContent);
expect(output).toContain('---\n');
- expect(output).toContain('name: opsx-explore');
+ expect(output).toContain('name: openspec-explore');
expect(output).toContain('description: Enter explore mode for thinking');
expect(output).toContain('invokable: true');
expect(output).toContain('---\n\n');
@@ -305,7 +305,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = costrictAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.cospec', 'openspec', 'commands', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.cospec', 'openspec', 'commands', 'openspec-explore.md'));
});
it('should format file with description and argument-hint', () => {
@@ -323,9 +323,9 @@ describe('command-generation/adapters', () => {
expect(crushAdapter.toolId).toBe('crush');
});
- it('should generate correct file path with nested opsx folder', () => {
+ it('should generate correct file path with nested openspec folder', () => {
const filePath = crushAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.crush', 'commands', 'opsx', 'explore.md'));
+ expect(filePath).toBe(path.join('.crush', 'commands', 'openspec', 'explore.md'));
});
it('should format file with name, description, category, and tags', () => {
@@ -347,7 +347,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = factoryAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.factory', 'commands', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.factory', 'commands', 'openspec-explore.md'));
});
it('should format file with description and argument-hint', () => {
@@ -367,7 +367,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path with .toml extension', () => {
const filePath = geminiAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.gemini', 'commands', 'opsx', 'explore.toml'));
+ expect(filePath).toBe(path.join('.gemini', 'commands', 'openspec', 'explore.toml'));
});
it('should format file in TOML format', () => {
@@ -386,7 +386,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path with .prompt.md extension', () => {
const filePath = githubCopilotAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.github', 'prompts', 'opsx-explore.prompt.md'));
+ expect(filePath).toBe(path.join('.github', 'prompts', 'openspec-explore.prompt.md'));
});
it('should format file with description frontmatter', () => {
@@ -405,14 +405,14 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = iflowAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.iflow', 'commands', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.iflow', 'commands', 'openspec-explore.md'));
});
it('should format file with name, id, category, and description', () => {
const output = iflowAdapter.formatFile(sampleContent);
expect(output).toContain('---\n');
- expect(output).toContain('name: /opsx-explore');
- expect(output).toContain('id: opsx-explore');
+ expect(output).toContain('name: /openspec-explore');
+ expect(output).toContain('id: openspec-explore');
expect(output).toContain('category: Workflow');
expect(output).toContain('description: Enter explore mode for thinking');
expect(output).toContain('---\n\n');
@@ -427,7 +427,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = kilocodeAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.kilocode', 'workflows', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.kilocode', 'workflows', 'openspec-explore.md'));
});
it('should format file without frontmatter', () => {
@@ -444,7 +444,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = opencodeAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.opencode', 'commands', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.opencode', 'commands', 'openspec-explore.md'));
});
it('should format file with description frontmatter', () => {
@@ -458,28 +458,28 @@ describe('command-generation/adapters', () => {
it('should transform colon-based command references to hyphen-based', () => {
const contentWithCommands: CommandContent = {
...sampleContent,
- body: 'Use /opsx:new to start, then /opsx:apply to implement.',
+ body: 'Use /openspec:new to start, then /openspec:apply to implement.',
};
const output = opencodeAdapter.formatFile(contentWithCommands);
- expect(output).toContain('/opsx-new');
- expect(output).toContain('/opsx-apply');
- expect(output).not.toContain('/opsx:new');
- expect(output).not.toContain('/opsx:apply');
+ expect(output).toContain('/openspec-new');
+ expect(output).toContain('/openspec-apply');
+ expect(output).not.toContain('/openspec:new');
+ expect(output).not.toContain('/openspec:apply');
});
it('should handle multiple command references in body', () => {
const contentWithMultipleCommands: CommandContent = {
...sampleContent,
- body: `/opsx:explore for ideas
-/opsx:new to create
-/opsx:continue to proceed
-/opsx:apply to implement`,
+ body: `/openspec:explore for ideas
+/openspec:new to create
+/openspec:continue to proceed
+/openspec:apply to implement`,
};
const output = opencodeAdapter.formatFile(contentWithMultipleCommands);
- expect(output).toContain('/opsx-explore');
- expect(output).toContain('/opsx-new');
- expect(output).toContain('/opsx-continue');
- expect(output).toContain('/opsx-apply');
+ expect(output).toContain('/openspec-explore');
+ expect(output).toContain('/openspec-new');
+ expect(output).toContain('/openspec-continue');
+ expect(output).toContain('/openspec-apply');
});
});
@@ -488,9 +488,9 @@ describe('command-generation/adapters', () => {
expect(qoderAdapter.toolId).toBe('qoder');
});
- it('should generate correct file path with nested opsx folder', () => {
+ it('should generate correct file path with nested openspec folder', () => {
const filePath = qoderAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.qoder', 'commands', 'opsx', 'explore.md'));
+ expect(filePath).toBe(path.join('.qoder', 'commands', 'openspec', 'explore.md'));
});
it('should format file with name, description, category, and tags', () => {
@@ -512,7 +512,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path with .toml extension', () => {
const filePath = qwenAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.qwen', 'commands', 'opsx-explore.toml'));
+ expect(filePath).toBe(path.join('.qwen', 'commands', 'openspec-explore.toml'));
});
it('should format file in TOML format', () => {
@@ -531,12 +531,12 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = piAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.pi', 'prompts', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.pi', 'prompts', 'openspec-explore.md'));
});
it('should generate correct file paths for different commands', () => {
- expect(piAdapter.getFilePath('new')).toBe(path.join('.pi', 'prompts', 'opsx-new.md'));
- expect(piAdapter.getFilePath('bulk-archive')).toBe(path.join('.pi', 'prompts', 'opsx-bulk-archive.md'));
+ expect(piAdapter.getFilePath('new')).toBe(path.join('.pi', 'prompts', 'openspec-new.md'));
+ expect(piAdapter.getFilePath('bulk-archive')).toBe(path.join('.pi', 'prompts', 'openspec-bulk-archive.md'));
});
it('should format file with description frontmatter', () => {
@@ -573,7 +573,7 @@ describe('command-generation/adapters', () => {
it('should generate correct file path', () => {
const filePath = roocodeAdapter.getFilePath('explore');
- expect(filePath).toBe(path.join('.roo', 'commands', 'opsx-explore.md'));
+ expect(filePath).toBe(path.join('.roo', 'commands', 'openspec-explore.md'));
});
it('should format file with markdown header (no YAML frontmatter)', () => {
@@ -590,17 +590,17 @@ describe('command-generation/adapters', () => {
// path.join handles platform-specific separators
const filePath = claudeAdapter.getFilePath('test');
// On any platform, path.join returns the correct separator
- expect(filePath.split(path.sep)).toEqual(['.claude', 'commands', 'opsx', 'test.md']);
+ expect(filePath.split(path.sep)).toEqual(['.claude', 'commands', 'openspec', 'test.md']);
});
it('Cursor adapter uses path.join for paths', () => {
const filePath = cursorAdapter.getFilePath('test');
- expect(filePath.split(path.sep)).toEqual(['.cursor', 'commands', 'opsx-test.md']);
+ expect(filePath.split(path.sep)).toEqual(['.cursor', 'commands', 'openspec-test.md']);
});
it('Windsurf adapter uses path.join for paths', () => {
const filePath = windsurfAdapter.getFilePath('test');
- expect(filePath.split(path.sep)).toEqual(['.windsurf', 'workflows', 'opsx-test.md']);
+ expect(filePath.split(path.sep)).toEqual(['.windsurf', 'workflows', 'openspec-test.md']);
});
it('All adapters use path.join for paths', () => {
diff --git a/test/core/command-generation/generator.test.ts b/test/core/command-generation/generator.test.ts
index 903aac3e1..b7a878055 100644
--- a/test/core/command-generation/generator.test.ts
+++ b/test/core/command-generation/generator.test.ts
@@ -28,9 +28,9 @@ describe('command-generation/generator', () => {
const result = generateCommand(sampleContent, cursorAdapter);
expect(result.path).toContain('.cursor');
- expect(result.path).toContain('opsx-explore.md');
- expect(result.fileContent).toContain('name: /opsx-explore');
- expect(result.fileContent).toContain('id: opsx-explore');
+ expect(result.path).toContain('openspec-explore.md');
+ expect(result.fileContent).toContain('name: /openspec-explore');
+ expect(result.fileContent).toContain('id: openspec-explore');
expect(result.fileContent).toContain('Command body here.');
});
diff --git a/test/core/command-generation/types.test.ts b/test/core/command-generation/types.test.ts
index ded7daf53..3db85c4d1 100644
--- a/test/core/command-generation/types.test.ts
+++ b/test/core/command-generation/types.test.ts
@@ -68,11 +68,11 @@ describe('command-generation/types', () => {
describe('GeneratedCommand interface', () => {
it('should represent generated command output', () => {
const generated: GeneratedCommand = {
- path: '.claude/commands/opsx/explore.md',
+ path: '.claude/commands/openspec/explore.md',
fileContent: '---\nname: Test\n---\n\nBody\n',
};
- expect(generated.path).toBe('.claude/commands/opsx/explore.md');
+ expect(generated.path).toBe('.claude/commands/openspec/explore.md');
expect(generated.fileContent).toContain('name: Test');
});
});
diff --git a/test/core/init.test.ts b/test/core/init.test.ts
index 6af92aed2..dd0911289 100644
--- a/test/core/init.test.ts
+++ b/test/core/init.test.ts
@@ -123,10 +123,10 @@ describe('InitCommand', () => {
// Core profile: propose, explore, apply, archive
const coreCommandNames = [
- 'opsx/propose.md',
- 'opsx/explore.md',
- 'opsx/apply.md',
- 'opsx/archive.md',
+ 'openspec/propose.md',
+ 'openspec/explore.md',
+ 'openspec/apply.md',
+ 'openspec/archive.md',
];
for (const cmdName of coreCommandNames) {
@@ -136,12 +136,12 @@ describe('InitCommand', () => {
// Non-core commands should NOT be created
const nonCoreCommandNames = [
- 'opsx/new.md',
- 'opsx/continue.md',
- 'opsx/ff.md',
- 'opsx/sync.md',
- 'opsx/bulk-archive.md',
- 'opsx/verify.md',
+ 'openspec/new.md',
+ 'openspec/continue.md',
+ 'openspec/ff.md',
+ 'openspec/sync.md',
+ 'openspec/bulk-archive.md',
+ 'openspec/verify.md',
];
for (const cmdName of nonCoreCommandNames) {
@@ -361,7 +361,7 @@ describe('InitCommand', () => {
const initCommand = new InitCommand({ tools: 'claude', force: true });
await initCommand.execute(testDir);
- const cmdFile = path.join(testDir, '.claude', 'commands', 'opsx', 'explore.md');
+ const cmdFile = path.join(testDir, '.claude', 'commands', 'openspec', 'explore.md');
const content = await fs.readFile(cmdFile, 'utf-8');
// Claude commands use YAML frontmatter
@@ -374,7 +374,7 @@ describe('InitCommand', () => {
const initCommand = new InitCommand({ tools: 'cursor', force: true });
await initCommand.execute(testDir);
- const cmdFile = path.join(testDir, '.cursor', 'commands', 'opsx-explore.md');
+ const cmdFile = path.join(testDir, '.cursor', 'commands', 'openspec-explore.md');
expect(await fileExists(cmdFile)).toBe(true);
const content = await fs.readFile(cmdFile, 'utf-8');
@@ -417,7 +417,7 @@ describe('InitCommand', () => {
const initCommand = new InitCommand({ tools: 'gemini', force: true });
await initCommand.execute(testDir);
- const cmdFile = path.join(testDir, '.gemini', 'commands', 'opsx', 'explore.toml');
+ const cmdFile = path.join(testDir, '.gemini', 'commands', 'openspec', 'explore.toml');
expect(await fileExists(cmdFile)).toBe(true);
const content = await fs.readFile(cmdFile, 'utf-8');
@@ -429,7 +429,7 @@ describe('InitCommand', () => {
const initCommand = new InitCommand({ tools: 'windsurf', force: true });
await initCommand.execute(testDir);
- const cmdFile = path.join(testDir, '.windsurf', 'workflows', 'opsx-explore.md');
+ const cmdFile = path.join(testDir, '.windsurf', 'workflows', 'openspec-explore.md');
expect(await fileExists(cmdFile)).toBe(true);
});
@@ -437,11 +437,11 @@ describe('InitCommand', () => {
const initCommand = new InitCommand({ tools: 'continue', force: true });
await initCommand.execute(testDir);
- const cmdFile = path.join(testDir, '.continue', 'prompts', 'opsx-explore.prompt');
+ const cmdFile = path.join(testDir, '.continue', 'prompts', 'openspec-explore.prompt');
expect(await fileExists(cmdFile)).toBe(true);
const content = await fs.readFile(cmdFile, 'utf-8');
- expect(content).toContain('name: opsx-explore');
+ expect(content).toContain('name: openspec-explore');
expect(content).toContain('invokable: true');
});
@@ -449,7 +449,7 @@ describe('InitCommand', () => {
const initCommand = new InitCommand({ tools: 'cline', force: true });
await initCommand.execute(testDir);
- const cmdFile = path.join(testDir, '.clinerules', 'workflows', 'opsx-explore.md');
+ const cmdFile = path.join(testDir, '.clinerules', 'workflows', 'openspec-explore.md');
expect(await fileExists(cmdFile)).toBe(true);
});
@@ -457,7 +457,7 @@ describe('InitCommand', () => {
const initCommand = new InitCommand({ tools: 'github-copilot', force: true });
await initCommand.execute(testDir);
- const cmdFile = path.join(testDir, '.github', 'prompts', 'opsx-explore.prompt.md');
+ const cmdFile = path.join(testDir, '.github', 'prompts', 'openspec-explore.prompt.md');
expect(await fileExists(cmdFile)).toBe(true);
});
});
@@ -626,8 +626,8 @@ describe('InitCommand - profile and detection features', () => {
it('should migrate commands-only extend mode to custom profile without injecting propose', async () => {
await fs.mkdir(path.join(testDir, 'openspec'), { recursive: true });
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
- await fs.writeFile(path.join(testDir, '.claude', 'commands', 'opsx', 'explore.md'), '# explore\n');
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.writeFile(path.join(testDir, '.claude', 'commands', 'openspec', 'explore.md'), '# explore\n');
const initCommand = new InitCommand({ tools: 'claude', force: true });
await initCommand.execute(testDir);
@@ -637,8 +637,8 @@ describe('InitCommand - profile and detection features', () => {
expect(config.delivery).toBe('commands');
expect(config.workflows).toEqual(['explore']);
- const exploreCommand = path.join(testDir, '.claude', 'commands', 'opsx', 'explore.md');
- const proposeCommand = path.join(testDir, '.claude', 'commands', 'opsx', 'propose.md');
+ const exploreCommand = path.join(testDir, '.claude', 'commands', 'openspec', 'explore.md');
+ const proposeCommand = path.join(testDir, '.claude', 'commands', 'openspec', 'propose.md');
expect(await fileExists(exploreCommand)).toBe(true);
expect(await fileExists(proposeCommand)).toBe(false);
@@ -689,7 +689,7 @@ describe('InitCommand - profile and detection features', () => {
expect(await fileExists(skillFile)).toBe(true);
// Commands should NOT exist
- const cmdFile = path.join(testDir, '.claude', 'commands', 'opsx', 'explore.md');
+ const cmdFile = path.join(testDir, '.claude', 'commands', 'openspec', 'explore.md');
expect(await fileExists(cmdFile)).toBe(false);
});
@@ -708,7 +708,7 @@ describe('InitCommand - profile and detection features', () => {
expect(await fileExists(skillFile)).toBe(false);
// Commands should exist
- const cmdFile = path.join(testDir, '.claude', 'commands', 'opsx', 'explore.md');
+ const cmdFile = path.join(testDir, '.claude', 'commands', 'openspec', 'explore.md');
expect(await fileExists(cmdFile)).toBe(true);
});
@@ -722,7 +722,7 @@ describe('InitCommand - profile and detection features', () => {
const initCommand1 = new InitCommand({ tools: 'claude', force: true });
await initCommand1.execute(testDir);
- const cmdFile = path.join(testDir, '.claude', 'commands', 'opsx', 'explore.md');
+ const cmdFile = path.join(testDir, '.claude', 'commands', 'openspec', 'explore.md');
expect(await fileExists(cmdFile)).toBe(true);
saveGlobalConfig({
diff --git a/test/core/legacy-cleanup.test.ts b/test/core/legacy-cleanup.test.ts
index bfae37805..362abbfae 100644
--- a/test/core/legacy-cleanup.test.ts
+++ b/test/core/legacy-cleanup.test.ts
@@ -260,47 +260,47 @@ ${OPENSPEC_MARKERS.end}`);
describe('detectLegacySlashCommands', () => {
it('should detect legacy Claude slash command directory', async () => {
- const dirPath = path.join(testDir, '.claude', 'commands', 'openspec');
+ const dirPath = path.join(testDir, '.claude', 'commands', 'opsx');
await fs.mkdir(dirPath, { recursive: true });
await fs.writeFile(path.join(dirPath, 'proposal.md'), 'content');
const result = await detectLegacySlashCommands(testDir);
- expect(result.directories).toContain('.claude/commands/openspec');
+ expect(result.directories).toContain('.claude/commands/opsx');
});
it('should detect legacy Cursor slash command files', async () => {
const dirPath = path.join(testDir, '.cursor', 'commands');
await fs.mkdir(dirPath, { recursive: true });
- await fs.writeFile(path.join(dirPath, 'openspec-proposal.md'), 'content');
- await fs.writeFile(path.join(dirPath, 'openspec-apply.md'), 'content');
+ await fs.writeFile(path.join(dirPath, 'opsx-proposal.md'), 'content');
+ await fs.writeFile(path.join(dirPath, 'opsx-apply.md'), 'content');
const result = await detectLegacySlashCommands(testDir);
- expect(result.files).toContain('.cursor/commands/openspec-proposal.md');
- expect(result.files).toContain('.cursor/commands/openspec-apply.md');
+ expect(result.files).toContain('.cursor/commands/opsx-proposal.md');
+ expect(result.files).toContain('.cursor/commands/opsx-apply.md');
});
it('should detect legacy Windsurf workflow files', async () => {
const dirPath = path.join(testDir, '.windsurf', 'workflows');
await fs.mkdir(dirPath, { recursive: true });
- await fs.writeFile(path.join(dirPath, 'openspec-archive.md'), 'content');
+ await fs.writeFile(path.join(dirPath, 'opsx-archive.md'), 'content');
const result = await detectLegacySlashCommands(testDir);
- expect(result.files).toContain('.windsurf/workflows/openspec-archive.md');
+ expect(result.files).toContain('.windsurf/workflows/opsx-archive.md');
});
it('should detect multiple tool directories and files', async () => {
// Create directory-based
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
- await fs.mkdir(path.join(testDir, '.qoder', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.qoder', 'commands', 'opsx'), { recursive: true });
// Create file-based
await fs.mkdir(path.join(testDir, '.cursor', 'commands'), { recursive: true });
- await fs.writeFile(path.join(testDir, '.cursor', 'commands', 'openspec-proposal.md'), 'content');
+ await fs.writeFile(path.join(testDir, '.cursor', 'commands', 'opsx-proposal.md'), 'content');
const result = await detectLegacySlashCommands(testDir);
- expect(result.directories).toContain('.claude/commands/openspec');
- expect(result.directories).toContain('.qoder/commands/openspec');
- expect(result.files).toContain('.cursor/commands/openspec-proposal.md');
+ expect(result.directories).toContain('.claude/commands/opsx');
+ expect(result.directories).toContain('.qoder/commands/opsx');
+ expect(result.files).toContain('.cursor/commands/opsx-proposal.md');
});
it('should not detect non-openspec files', async () => {
@@ -321,19 +321,19 @@ ${OPENSPEC_MARKERS.end}`);
it('should detect TOML-based slash commands for Qwen', async () => {
const dirPath = path.join(testDir, '.qwen', 'commands');
await fs.mkdir(dirPath, { recursive: true });
- await fs.writeFile(path.join(dirPath, 'openspec-proposal.toml'), 'content');
+ await fs.writeFile(path.join(dirPath, 'opsx-proposal.toml'), 'content');
const result = await detectLegacySlashCommands(testDir);
- expect(result.files).toContain('.qwen/commands/openspec-proposal.toml');
+ expect(result.files).toContain('.qwen/commands/opsx-proposal.toml');
});
it('should detect Continue prompt files', async () => {
const dirPath = path.join(testDir, '.continue', 'prompts');
await fs.mkdir(dirPath, { recursive: true });
- await fs.writeFile(path.join(dirPath, 'openspec-apply.prompt'), 'content');
+ await fs.writeFile(path.join(dirPath, 'opsx-apply.prompt'), 'content');
const result = await detectLegacySlashCommands(testDir);
- expect(result.files).toContain('.continue/prompts/openspec-apply.prompt');
+ expect(result.files).toContain('.continue/prompts/opsx-apply.prompt');
});
it('should detect legacy OpenCode opsx-* command files', async () => {
@@ -424,11 +424,11 @@ ${OPENSPEC_MARKERS.end}`);
});
it('should return hasLegacyArtifacts: true when slash commands are found', async () => {
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
const result = await detectLegacyArtifacts(testDir);
expect(result.hasLegacyArtifacts).toBe(true);
- expect(result.slashCommandDirs).toContain('.claude/commands/openspec');
+ expect(result.slashCommandDirs).toContain('.claude/commands/opsx');
});
it('should return hasLegacyArtifacts: true when openspec/AGENTS.md is found', async () => {
@@ -451,14 +451,14 @@ ${OPENSPEC_MARKERS.end}`);
it('should combine all detection results', async () => {
// Create various legacy artifacts
await fs.writeFile(path.join(testDir, 'CLAUDE.md'), `${OPENSPEC_MARKERS.start}\nContent\n${OPENSPEC_MARKERS.end}`);
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
await fs.writeFile(path.join(testDir, 'openspec', 'AGENTS.md'), 'content');
await fs.writeFile(path.join(testDir, 'openspec', 'project.md'), 'content');
const result = await detectLegacyArtifacts(testDir);
expect(result.hasLegacyArtifacts).toBe(true);
expect(result.configFiles).toContain('CLAUDE.md');
- expect(result.slashCommandDirs).toContain('.claude/commands/openspec');
+ expect(result.slashCommandDirs).toContain('.claude/commands/opsx');
expect(result.hasOpenspecAgents).toBe(true);
expect(result.hasProjectMd).toBe(true);
});
@@ -500,14 +500,14 @@ ${OPENSPEC_MARKERS.end}`);
});
it('should delete legacy slash command directories', async () => {
- const dirPath = path.join(testDir, '.claude', 'commands', 'openspec');
+ const dirPath = path.join(testDir, '.claude', 'commands', 'opsx');
await fs.mkdir(dirPath, { recursive: true });
await fs.writeFile(path.join(dirPath, 'proposal.md'), 'content');
const detection = await detectLegacyArtifacts(testDir);
const result = await cleanupLegacyArtifacts(testDir, detection);
- expect(result.deletedDirs).toContain('.claude/commands/openspec');
+ expect(result.deletedDirs).toContain('.claude/commands/opsx');
await expect(fs.access(dirPath)).rejects.toThrow();
// Parent directory should still exist
await expect(fs.access(path.join(testDir, '.claude', 'commands'))).resolves.not.toThrow();
@@ -516,13 +516,13 @@ ${OPENSPEC_MARKERS.end}`);
it('should delete legacy slash command files', async () => {
const dirPath = path.join(testDir, '.cursor', 'commands');
await fs.mkdir(dirPath, { recursive: true });
- const filePath = path.join(dirPath, 'openspec-proposal.md');
+ const filePath = path.join(dirPath, 'opsx-proposal.md');
await fs.writeFile(filePath, 'content');
const detection = await detectLegacyArtifacts(testDir);
const result = await cleanupLegacyArtifacts(testDir, detection);
- expect(result.deletedFiles).toContain('.cursor/commands/openspec-proposal.md');
+ expect(result.deletedFiles).toContain('.cursor/commands/opsx-proposal.md');
await expect(fs.access(filePath)).rejects.toThrow();
});
@@ -622,13 +622,13 @@ ${OPENSPEC_MARKERS.end}`);
const result = {
deletedFiles: [],
modifiedFiles: [],
- deletedDirs: ['.claude/commands/openspec'],
+ deletedDirs: ['.claude/commands/opsx'],
projectMdNeedsMigration: false,
errors: [],
};
const summary = formatCleanupSummary(result);
- expect(summary).toContain('✓ Removed .claude/commands/openspec/ (replaced by /opsx:*)');
+ expect(summary).toContain('✓ Removed .claude/commands/opsx/ (replaced by /openspec:*)');
});
it('should format modified files', () => {
@@ -749,7 +749,7 @@ ${OPENSPEC_MARKERS.end}`);
const detection = {
configFiles: [],
configFilesToUpdate: [],
- slashCommandDirs: ['.claude/commands/openspec'],
+ slashCommandDirs: ['.claude/commands/opsx'],
slashCommandFiles: [],
hasOpenspecAgents: false,
hasProjectMd: false,
@@ -759,7 +759,7 @@ ${OPENSPEC_MARKERS.end}`);
const summary = formatDetectionSummary(detection);
expect(summary).toContain('Files to remove');
- expect(summary).toContain('• .claude/commands/openspec/');
+ expect(summary).toContain('• .claude/commands/opsx/');
});
it('should format slash command files', () => {
@@ -767,7 +767,7 @@ ${OPENSPEC_MARKERS.end}`);
configFiles: [],
configFilesToUpdate: [],
slashCommandDirs: [],
- slashCommandFiles: ['.cursor/commands/openspec-proposal.md'],
+ slashCommandFiles: ['.cursor/commands/opsx-proposal.md'],
hasOpenspecAgents: false,
hasProjectMd: false,
hasRootAgentsWithMarkers: false,
@@ -776,7 +776,7 @@ ${OPENSPEC_MARKERS.end}`);
const summary = formatDetectionSummary(detection);
expect(summary).toContain('Files to remove');
- expect(summary).toContain('• .cursor/commands/openspec-proposal.md');
+ expect(summary).toContain('• .cursor/commands/opsx-proposal.md');
});
it('should format openspec/AGENTS.md', () => {
@@ -840,7 +840,7 @@ ${OPENSPEC_MARKERS.end}`);
const detection = {
configFiles: ['CLAUDE.md', 'CLINE.md'],
configFilesToUpdate: ['CLAUDE.md', 'CLINE.md'],
- slashCommandDirs: ['.claude/commands/openspec'],
+ slashCommandDirs: ['.claude/commands/opsx'],
slashCommandFiles: [],
hasOpenspecAgents: true,
hasProjectMd: false,
@@ -853,7 +853,7 @@ ${OPENSPEC_MARKERS.end}`);
expect(summary).toContain('Files to remove');
expect(summary).toContain('Files to update');
// Check removals (only slash commands and openspec/AGENTS.md)
- expect(summary).toContain('• .claude/commands/openspec/');
+ expect(summary).toContain('• .claude/commands/opsx/');
expect(summary).toContain('• openspec/AGENTS.md');
// Check updates (all config files)
expect(summary).toContain('• CLAUDE.md');
@@ -917,17 +917,17 @@ ${OPENSPEC_MARKERS.end}`);
it('should include expected tool patterns', () => {
expect(LEGACY_SLASH_COMMAND_PATHS['claude']).toEqual({
type: 'directory',
- path: '.claude/commands/openspec',
+ path: '.claude/commands/opsx',
});
expect(LEGACY_SLASH_COMMAND_PATHS['cursor']).toEqual({
type: 'files',
- pattern: '.cursor/commands/openspec-*.md',
+ pattern: '.cursor/commands/opsx-*.md',
});
expect(LEGACY_SLASH_COMMAND_PATHS['windsurf']).toEqual({
type: 'files',
- pattern: '.windsurf/workflows/openspec-*.md',
+ pattern: '.windsurf/workflows/opsx-*.md',
});
});
@@ -949,7 +949,7 @@ ${OPENSPEC_MARKERS.end}`);
const detection = {
configFiles: [],
configFilesToUpdate: [],
- slashCommandDirs: ['.claude/commands/openspec'],
+ slashCommandDirs: ['.claude/commands/opsx'],
slashCommandFiles: [],
hasOpenspecAgents: false,
hasProjectMd: false,
@@ -967,7 +967,7 @@ ${OPENSPEC_MARKERS.end}`);
configFiles: [],
configFilesToUpdate: [],
slashCommandDirs: [],
- slashCommandFiles: ['.cursor/commands/openspec-proposal.md'],
+ slashCommandFiles: ['.cursor/commands/opsx-proposal.md'],
hasOpenspecAgents: false,
hasProjectMd: false,
hasRootAgentsWithMarkers: false,
@@ -983,8 +983,8 @@ ${OPENSPEC_MARKERS.end}`);
const detection = {
configFiles: [],
configFilesToUpdate: [],
- slashCommandDirs: ['.claude/commands/openspec', '.qoder/commands/openspec'],
- slashCommandFiles: ['.cursor/commands/openspec-apply.md', '.windsurf/workflows/openspec-archive.md'],
+ slashCommandDirs: ['.claude/commands/opsx', '.qoder/commands/opsx'],
+ slashCommandFiles: ['.cursor/commands/opsx-apply.md', '.windsurf/workflows/opsx-archive.md'],
hasOpenspecAgents: false,
hasProjectMd: false,
hasRootAgentsWithMarkers: false,
@@ -1005,9 +1005,9 @@ ${OPENSPEC_MARKERS.end}`);
configFilesToUpdate: [],
slashCommandDirs: [],
slashCommandFiles: [
- '.cursor/commands/openspec-proposal.md',
- '.cursor/commands/openspec-apply.md',
- '.cursor/commands/openspec-archive.md',
+ '.cursor/commands/opsx-proposal.md',
+ '.cursor/commands/opsx-apply.md',
+ '.cursor/commands/opsx-archive.md',
],
hasOpenspecAgents: false,
hasProjectMd: false,
@@ -1041,7 +1041,7 @@ ${OPENSPEC_MARKERS.end}`);
configFiles: [],
configFilesToUpdate: [],
slashCommandDirs: [],
- slashCommandFiles: ['.qwen/commands/openspec-proposal.toml'],
+ slashCommandFiles: ['.qwen/commands/opsx-proposal.toml'],
hasOpenspecAgents: false,
hasProjectMd: false,
hasRootAgentsWithMarkers: false,
@@ -1058,7 +1058,7 @@ ${OPENSPEC_MARKERS.end}`);
configFiles: [],
configFilesToUpdate: [],
slashCommandDirs: [],
- slashCommandFiles: ['.continue/prompts/openspec-apply.prompt'],
+ slashCommandFiles: ['.continue/prompts/opsx-apply.prompt'],
hasOpenspecAgents: false,
hasProjectMd: false,
hasRootAgentsWithMarkers: false,
@@ -1075,7 +1075,7 @@ ${OPENSPEC_MARKERS.end}`);
configFiles: [],
configFilesToUpdate: [],
slashCommandDirs: [],
- slashCommandFiles: ['.github/prompts/openspec-apply.prompt.md'],
+ slashCommandFiles: ['.github/prompts/opsx-apply.prompt.md'],
hasOpenspecAgents: false,
hasProjectMd: false,
hasRootAgentsWithMarkers: false,
diff --git a/test/core/migration.test.ts b/test/core/migration.test.ts
index 409206e94..75ba7dc55 100644
--- a/test/core/migration.test.ts
+++ b/test/core/migration.test.ts
@@ -137,7 +137,7 @@ describe('migration', () => {
it('ignores unknown custom skill and command files when scanning workflows', async () => {
await writeSkill(projectDir, 'my-custom-skill');
- const customCommandPath = path.join(projectDir, '.claude', 'commands', 'opsx', 'my-custom.md');
+ const customCommandPath = path.join(projectDir, '.claude', 'commands', 'openspec', 'my-custom.md');
await fsp.mkdir(path.dirname(customCommandPath), { recursive: true });
await fsp.writeFile(customCommandPath, '# custom\n', 'utf-8');
diff --git a/test/core/shared/skill-generation.test.ts b/test/core/shared/skill-generation.test.ts
index 6c755f51d..f6baf54bc 100644
--- a/test/core/shared/skill-generation.test.ts
+++ b/test/core/shared/skill-generation.test.ts
@@ -260,28 +260,28 @@ describe('skill-generation', () => {
const template = {
name: 'transform-test',
description: 'Test transform callback',
- instructions: 'Use /opsx:new to start and /opsx:apply to implement.',
+ instructions: 'Use /openspec:new to start and /openspec:apply to implement.',
};
- const transformer = (text: string) => text.replace(/\/opsx:/g, '/opsx-');
+ const transformer = (text: string) => text.replace(/\/openspec:/g, '/openspec-');
const content = generateSkillContent(template, '0.23.0', transformer);
- expect(content).toContain('/opsx-new');
- expect(content).toContain('/opsx-apply');
- expect(content).not.toContain('/opsx:new');
- expect(content).not.toContain('/opsx:apply');
+ expect(content).toContain('/openspec-new');
+ expect(content).toContain('/openspec-apply');
+ expect(content).not.toContain('/openspec:new');
+ expect(content).not.toContain('/openspec:apply');
});
it('should not transform instructions when callback is undefined', () => {
const template = {
name: 'no-transform-test',
description: 'Test without transform',
- instructions: 'Use /opsx:new to start.',
+ instructions: 'Use /openspec:new to start.',
};
const content = generateSkillContent(template, '0.23.0', undefined);
- expect(content).toContain('/opsx:new');
+ expect(content).toContain('/openspec:new');
});
it('should support custom transformInstructions logic', () => {
diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts
index f8fb1307b..4bca7c6ed 100644
--- a/test/core/templates/skill-templates-parity.test.ts
+++ b/test/core/templates/skill-templates-parity.test.ts
@@ -30,43 +30,43 @@ import {
import { generateSkillContent } from '../../../src/core/shared/skill-generation.js';
const EXPECTED_FUNCTION_HASHES: Record = {
- getExploreSkillTemplate: '55a2a1afcba0af88c638e77e4e3870f65ed82c030b4a2056d39812ae13a616be',
+ getExploreSkillTemplate: 'ad8aa016932952a9295c54ef592447f03fac1695905bfebeb8a2ea54fc3303fc',
getNewChangeSkillTemplate: '5989672758eccf54e3bb554ab97f2c129a192b12bbb7688cc1ffcf6bccb1ae9d',
getContinueChangeSkillTemplate: 'f2e413f0333dfd6641cc2bd1a189273fdea5c399eecdde98ef528b5216f097b3',
- getApplyChangeSkillTemplate: '26e52e67693e93fbcdd40dcd3e20949c07ce019183d55a8149d0260c791cd7f4',
- getFfChangeSkillTemplate: 'a7332fb14c8dc3f9dec71f5d332790b4a8488191e7db4ab6132ccbefecf9ded9',
+ getApplyChangeSkillTemplate: '48a9173d8b201f9db955e40fa53d03824eaa1a8b26529dd00b5bd00cd3e5fbe9',
+ getFfChangeSkillTemplate: '3bc8740c011bbf7f124db4eed3e96ca76ed1a4aa54f96674e8c57d47354f7b18',
getSyncSpecsSkillTemplate: 'bded184e4c345619148de2c0ad80a5b527d4ffe45c87cc785889b9329e0f465b',
- getOnboardSkillTemplate: '819a2d117ad1386187975686839cb0584b41484013d0ca6a6691f7a439a11a4a',
- getOpsxExploreCommandTemplate: '91353d9e8633a3a9ce7339e796f1283478fca279153f3807c92f4f8ece246b19',
- getOpsxNewCommandTemplate: '62eee32d6d81a376e7be845d0891e28e6262ad07482f9bfe6af12a9f0366c364',
- getOpsxContinueCommandTemplate: '8bbaedcc95287f9e822572608137df4f49ad54cedfb08d3342d0d1c4e9716caa',
- getOpsxApplyCommandTemplate: 'a9d631a07fcd832b67d263ff3800b98604ab8d378baf1b0d545907ef3affa3b5',
- getOpsxFfCommandTemplate: 'cdebe872cc8e0fcc25c8864b98ffd66a93484c0657db94bd1285b8113092702a',
+ getOnboardSkillTemplate: '2ff347ce9f2724f7ab02111ffd5f7e00d34512a654070e3c4ce77d993725dbf6',
+ getOpsxExploreCommandTemplate: 'd38a064445b077d63135f544a4fdcc4c01bb3e77e451403ea16d099b0a6a6c0f',
+ getOpsxNewCommandTemplate: 'f800f4635b7381ec392ca2b140fe74fd2c9be947f23367214a8f69640b58013f',
+ getOpsxContinueCommandTemplate: 'e1ca122fd6a92243c4b7f91349b457bd1e904cad9c84ffa938b334eceb379525',
+ getOpsxApplyCommandTemplate: '02cdb27b54c520309aeeeac44a1bb99e540c7a4ae7ec064614ce5939b7305de0',
+ getOpsxFfCommandTemplate: '64e3d0830998cebc1f7b428a3822aa785dadd6bf384cda097d80f2f464463a14',
getArchiveChangeSkillTemplate: '6f8ca383fdb5a4eb9872aca81e07bf0ba7f25e4de8617d7a047ca914ca7f14b9',
getBulkArchiveChangeSkillTemplate: 'b40fc44ea4e420bdc9c803985b10e5c091fc472cdfc69153b962be6be303bddd',
- getOpsxSyncCommandTemplate: '378d035fe7cc30be3e027b66dcc4b8afc78ef1c8369c39479c9b05a582fb5ccf',
+ getOpsxSyncCommandTemplate: 'd557936427ee9efb6ee39c27c657892ac645e71c4eda3d889de28df079f9ac67',
getVerifyChangeSkillTemplate: '63a213ba3b42af54a1cd56f5072234a03b265c3fe4a1da12cd6fbbef5ee46c4b',
- getOpsxArchiveCommandTemplate: 'b44cc9748109f61687f9f596604b037bc3ea803abc143b22f09a76aebd98b493',
- getOpsxOnboardCommandTemplate: '10052d05a4e2cdade7fdfa549b3444f7a92f55a39bf81ddd6af7e0e9e83a7302',
- getOpsxBulkArchiveCommandTemplate: 'eaaba253a950b9e681d8427a5cbc6b50c4e91137fb37fd2360859e08f63a0c14',
- getOpsxVerifyCommandTemplate: '9b4d3ca422553b7534764eb3a009da87a051612c5238e9baab294c7b1233e9a2',
- getOpsxProposeSkillTemplate: 'd67f937d44650e9c61d2158c865309fbab23cb3f50a3d4868a640a97776e3999',
- getOpsxProposeCommandTemplate: '41ad59b37eafd7a161bab5c6e41997a37368f9c90b194451295ede5cd42e4d46',
+ getOpsxArchiveCommandTemplate: '6d17674f9fa2c9b2bdcf64732b965534e329139cbdd324f450b960751a593d7b',
+ getOpsxOnboardCommandTemplate: '3aaed5d2d7388790233b5a348581c18081ad379856c22c9aa3097155676660c9',
+ getOpsxBulkArchiveCommandTemplate: '16fcb156a9a50078e834261b4d0ddce1e33b8e791bedf34596e15fdabf91a930',
+ getOpsxVerifyCommandTemplate: 'ba0d9f9b679ae5585dfdce7535cc98e52d6f02cf66c4d468976f1ef1ea32892d',
+ getOpsxProposeSkillTemplate: '769f79aa2addf577f6acadde5b45618773192a1438daea59a5857bb800252841',
+ getOpsxProposeCommandTemplate: '675793c7bcabbe4d91b139ee34c784bc91074a8b1741808323b90c2093378876',
getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d',
};
const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = {
- 'openspec-explore': '90463d00761417dfbca5cb09361adcf8bbdbbb24000b86dd03647869a4104479',
+ 'openspec-explore': '0f9be2435de07841ae89969335206319418ffa302557dae7ae281026638e306e',
'openspec-new-change': 'c324a7ace1f244aa3f534ac8e3370a2c11190d6d1b85a315f26a211398310f0f',
'openspec-continue-change': '463cf0b980ec9c3c24774414ef2a3e48e9faa8577bc8748990f45ab3d5efe960',
- 'openspec-apply-change': 'a0084442b59be9d7e22a0382a279d470501e1ecf74bdd5347e169951c9be191c',
- 'openspec-ff-change': '672c3a5b8df152d959b15bd7ae2be7a75ab7b8eaa2ec1e0daa15c02479b27937',
+ 'openspec-apply-change': '0d2b9402da87dad71e956b669d61f4e58db7a93f760cfffb314831be06549578',
+ 'openspec-ff-change': '5905fbf9aa1aaadc704dec4a10be1b724b68ac4a5373e0866e56a8822d7db689',
'openspec-sync-specs': 'b8859cf454379a19ca35dbf59eedca67306607f44a355327f9dc851114e50bde',
'openspec-archive-change': 'f83c85452bd47de0dee6b8efbcea6a62534f8a175480e9044f3043f887cebf0f',
'openspec-bulk-archive-change': 'a235a539f7729ab7669e45256905808789240ecd02820e044f4d0eef67b0c2ab',
'openspec-verify-change': '30d07c6f7051965f624f5964db51844ec17c7dfd05f0da95281fe0ca73616326',
- 'openspec-onboard': 'dbce376cf895f3fe4f63b4bce66d258c35b7b8884ac746670e5e35fabcefd255',
- 'openspec-propose': '20e36dabefb90e232bad0667292bd5007ec280f8fc4fc995dbc4282bf45a22e7',
+ 'openspec-onboard': '435b5678b19c7cf083880f13ada549e3168a96128beff90f29ae8db44a0da05c',
+ 'openspec-propose': '8e01fd8ee8f9568a111b0a53780befb5e79da304cfa32c2437cd078da96880d6',
};
function stableStringify(value: unknown): string {
diff --git a/test/core/update.test.ts b/test/core/update.test.ts
index c36ac3da8..fc1d0d0e8 100644
--- a/test/core/update.test.ts
+++ b/test/core/update.test.ts
@@ -193,7 +193,7 @@ Old instructions content
});
describe('command updates', () => {
- it('should update opsx commands for configured Claude tool', async () => {
+ it('should update openspec commands for configured Claude tool', async () => {
// Set up a configured Claude tool
const skillsDir = path.join(testDir, '.claude', 'skills');
await fs.mkdir(path.join(skillsDir, 'openspec-explore'), {
@@ -206,8 +206,8 @@ Old instructions content
await updateCommand.execute(testDir);
- // Check opsx command files were created
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ // Check openspec command files were created
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
const exploreCmd = path.join(commandsDir, 'explore.md');
const exists = await FileSystemUtils.fileExists(exploreCmd);
expect(exists).toBe(true);
@@ -220,7 +220,7 @@ Old instructions content
expect(content).toContain('tags:');
});
- it('should update core profile opsx commands when tool is configured', async () => {
+ it('should update core profile openspec commands when tool is configured', async () => {
// Set up a configured tool
const skillsDir = path.join(testDir, '.claude', 'skills');
await fs.mkdir(path.join(skillsDir, 'openspec-explore'), {
@@ -235,7 +235,7 @@ Old instructions content
// Verify core profile commands were created (propose, explore, apply, archive)
const coreCommandIds = ['explore', 'apply', 'archive', 'propose'];
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
for (const cmdId of coreCommandIds) {
const cmdFile = path.join(commandsDir, `${cmdId}.md`);
const exists = await FileSystemUtils.fileExists(cmdFile);
@@ -313,12 +313,12 @@ Old instructions content
await updateCommand.execute(testDir);
- // Check Qwen command format (TOML) - Qwen uses flat path structure: opsx-.toml
+ // Check Qwen command format (TOML) - Qwen uses flat path structure: openspec-.toml
const qwenCmd = path.join(
testDir,
'.qwen',
'commands',
- 'opsx-explore.toml'
+ 'openspec-explore.toml'
);
const exists = await FileSystemUtils.fileExists(qwenCmd);
expect(exists).toBe(true);
@@ -346,7 +346,7 @@ Old instructions content
testDir,
'.windsurf',
'workflows',
- 'opsx-explore.md'
+ 'openspec-explore.md'
);
const exists = await FileSystemUtils.fileExists(windsurfCmd);
expect(exists).toBe(true);
@@ -963,7 +963,7 @@ ${OPENSPEC_MARKERS.end}
);
// Create legacy slash command directory
- const legacyCommandDir = path.join(testDir, '.claude', 'commands', 'openspec');
+ const legacyCommandDir = path.join(testDir, '.claude', 'commands', 'opsx');
await fs.mkdir(legacyCommandDir, { recursive: true });
await fs.writeFile(
path.join(legacyCommandDir, 'old-command.md'),
@@ -978,7 +978,7 @@ ${OPENSPEC_MARKERS.end}
// Should show cleanup message for directory
expect(consoleSpy).toHaveBeenCalledWith(
- expect.stringContaining('Removed .claude/commands/openspec/')
+ expect.stringContaining('Removed .claude/commands/opsx/')
);
// Legacy directory should be deleted
@@ -1113,7 +1113,7 @@ More user content after markers.
describe('legacy tool upgrade', () => {
it('should upgrade legacy tools to new skills with --force', async () => {
// Create legacy slash command directory (no skills exist yet)
- const legacyCommandDir = path.join(testDir, '.claude', 'commands', 'openspec');
+ const legacyCommandDir = path.join(testDir, '.claude', 'commands', 'opsx');
await fs.mkdir(legacyCommandDir, { recursive: true });
await fs.writeFile(
path.join(legacyCommandDir, 'proposal.md'),
@@ -1141,7 +1141,7 @@ More user content after markers.
expect.stringContaining('Getting started')
);
expect(consoleSpy).toHaveBeenCalledWith(
- expect.stringContaining('/opsx:new')
+ expect.stringContaining('/openspec:new')
);
// Skills should be created
@@ -1158,15 +1158,15 @@ More user content after markers.
it('should upgrade multiple legacy tools with --force', async () => {
// Create legacy command directories for Claude and Cursor
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
await fs.writeFile(
- path.join(testDir, '.claude', 'commands', 'openspec', 'proposal.md'),
+ path.join(testDir, '.claude', 'commands', 'opsx', 'proposal.md'),
'content'
);
await fs.mkdir(path.join(testDir, '.cursor', 'commands'), { recursive: true });
await fs.writeFile(
- path.join(testDir, '.cursor', 'commands', 'openspec-proposal.md'),
+ path.join(testDir, '.cursor', 'commands', 'opsx-proposal.md'),
'content'
);
@@ -1201,7 +1201,7 @@ More user content after markers.
);
// Also create legacy directory (simulating partial upgrade)
- const legacyCommandDir = path.join(testDir, '.claude', 'commands', 'openspec');
+ const legacyCommandDir = path.join(testDir, '.claude', 'commands', 'opsx');
await fs.mkdir(legacyCommandDir, { recursive: true });
await fs.writeFile(
path.join(legacyCommandDir, 'proposal.md'),
@@ -1216,7 +1216,7 @@ More user content after markers.
// Legacy cleanup should happen
expect(consoleSpy).toHaveBeenCalledWith(
- expect.stringContaining('Removed .claude/commands/openspec/')
+ expect.stringContaining('Removed .claude/commands/opsx/')
);
// Should NOT show "Tools detected from legacy artifacts" because claude is already configured
@@ -1246,15 +1246,15 @@ More user content after markers.
);
// Create legacy commands for both Claude (configured) and Cursor (not configured)
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
await fs.writeFile(
- path.join(testDir, '.claude', 'commands', 'openspec', 'proposal.md'),
+ path.join(testDir, '.claude', 'commands', 'opsx', 'proposal.md'),
'content'
);
await fs.mkdir(path.join(testDir, '.cursor', 'commands'), { recursive: true });
await fs.writeFile(
- path.join(testDir, '.cursor', 'commands', 'openspec-proposal.md'),
+ path.join(testDir, '.cursor', 'commands', 'opsx-proposal.md'),
'content'
);
@@ -1308,9 +1308,9 @@ More user content after markers.
it('should create only effective profile skills when upgrading legacy tools', async () => {
// Create legacy command directory
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
await fs.writeFile(
- path.join(testDir, '.claude', 'commands', 'openspec', 'proposal.md'),
+ path.join(testDir, '.claude', 'commands', 'opsx', 'proposal.md'),
'content'
);
@@ -1339,9 +1339,9 @@ More user content after markers.
it('should create commands when upgrading legacy tools', async () => {
// Create legacy command directory
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
await fs.writeFile(
- path.join(testDir, '.claude', 'commands', 'openspec', 'proposal.md'),
+ path.join(testDir, '.claude', 'commands', 'opsx', 'proposal.md'),
'content'
);
@@ -1349,8 +1349,8 @@ More user content after markers.
const forceUpdateCommand = new UpdateCommand({ force: true });
await forceUpdateCommand.execute(testDir);
- // New opsx commands should be created
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ // New openspec commands should be created
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
const exploreCmd = path.join(commandsDir, 'explore.md');
const exists = await FileSystemUtils.fileExists(exploreCmd);
expect(exists).toBe(true);
@@ -1364,9 +1364,9 @@ More user content after markers.
workflows: ['explore'],
});
- await fs.mkdir(path.join(testDir, '.claude', 'commands', 'openspec'), { recursive: true });
+ await fs.mkdir(path.join(testDir, '.claude', 'commands', 'opsx'), { recursive: true });
await fs.writeFile(
- path.join(testDir, '.claude', 'commands', 'openspec', 'proposal.md'),
+ path.join(testDir, '.claude', 'commands', 'opsx', 'proposal.md'),
'content'
);
@@ -1381,7 +1381,7 @@ More user content after markers.
path.join(skillsDir, 'openspec-propose', 'SKILL.md')
)).toBe(false);
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
expect(await FileSystemUtils.fileExists(
path.join(commandsDir, 'explore.md')
)).toBe(true);
@@ -1444,7 +1444,7 @@ More user content after markers.
)).toBe(true);
// Commands should NOT be created
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
expect(await FileSystemUtils.fileExists(
path.join(commandsDir, 'explore.md')
)).toBe(false);
@@ -1464,7 +1464,7 @@ More user content after markers.
await updateCommand.execute(testDir);
// Commands should be created
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
expect(await FileSystemUtils.fileExists(
path.join(commandsDir, 'explore.md')
)).toBe(true);
@@ -1523,7 +1523,7 @@ content
`
);
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
await fs.mkdir(commandsDir, { recursive: true });
await fs.writeFile(path.join(commandsDir, 'explore.md'), 'old command');
@@ -1542,7 +1542,7 @@ content
delivery: 'commands',
});
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
await fs.mkdir(commandsDir, { recursive: true });
await fs.writeFile(path.join(commandsDir, 'explore.md'), 'existing command');
@@ -1583,7 +1583,7 @@ content
// Add a non-core workflow
await fs.mkdir(path.join(skillsDir, 'openspec-new-change'), { recursive: true });
await fs.writeFile(path.join(skillsDir, 'openspec-new-change', 'SKILL.md'), 'old');
- const extraCommandFile = path.join(testDir, '.claude', 'commands', 'opsx', 'new.md');
+ const extraCommandFile = path.join(testDir, '.claude', 'commands', 'openspec', 'new.md');
await fs.mkdir(path.dirname(extraCommandFile), { recursive: true });
await fs.writeFile(extraCommandFile, 'old');
@@ -1739,7 +1739,7 @@ content
});
it('should detect installed workflows from managed command files', async () => {
- const commandsDir = path.join(testDir, '.claude', 'commands', 'opsx');
+ const commandsDir = path.join(testDir, '.claude', 'commands', 'openspec');
await fs.mkdir(commandsDir, { recursive: true });
await fs.writeFile(path.join(commandsDir, 'explore.md'), 'content');
diff --git a/test/utils/command-references.test.ts b/test/utils/command-references.test.ts
index c7ff2ed85..3429c4b78 100644
--- a/test/utils/command-references.test.ts
+++ b/test/utils/command-references.test.ts
@@ -4,24 +4,24 @@ import { transformToHyphenCommands } from '../../src/utils/command-references.js
describe('transformToHyphenCommands', () => {
describe('basic transformations', () => {
it('should transform single command reference', () => {
- expect(transformToHyphenCommands('/opsx:new')).toBe('/opsx-new');
+ expect(transformToHyphenCommands('/openspec:new')).toBe('/openspec-new');
});
it('should transform multiple command references', () => {
- const input = '/opsx:new and /opsx:apply';
- const expected = '/opsx-new and /opsx-apply';
+ const input = '/openspec:new and /openspec:apply';
+ const expected = '/openspec-new and /openspec-apply';
expect(transformToHyphenCommands(input)).toBe(expected);
});
it('should transform command reference in context', () => {
- const input = 'Use /opsx:apply to implement tasks';
- const expected = 'Use /opsx-apply to implement tasks';
+ const input = 'Use /openspec:apply to implement tasks';
+ const expected = 'Use /openspec-apply to implement tasks';
expect(transformToHyphenCommands(input)).toBe(expected);
});
it('should handle backtick-quoted commands', () => {
- const input = 'Run `/opsx:continue` to proceed';
- const expected = 'Run `/opsx-continue` to proceed';
+ const input = 'Run `/openspec:continue` to proceed';
+ const expected = 'Run `/openspec-continue` to proceed';
expect(transformToHyphenCommands(input)).toBe(expected);
});
});
@@ -42,20 +42,20 @@ describe('transformToHyphenCommands', () => {
});
it('should handle multiple occurrences on same line', () => {
- const input = '/opsx:new /opsx:continue /opsx:apply';
- const expected = '/opsx-new /opsx-continue /opsx-apply';
+ const input = '/openspec:new /openspec:continue /openspec:apply';
+ const expected = '/openspec-new /openspec-continue /openspec-apply';
expect(transformToHyphenCommands(input)).toBe(expected);
});
});
describe('multiline content', () => {
it('should transform references across multiple lines', () => {
- const input = `Use /opsx:new to start
-Then /opsx:continue to proceed
-Finally /opsx:apply to implement`;
- const expected = `Use /opsx-new to start
-Then /opsx-continue to proceed
-Finally /opsx-apply to implement`;
+ const input = `Use /openspec:new to start
+Then /openspec:continue to proceed
+Finally /openspec:apply to implement`;
+ const expected = `Use /openspec-new to start
+Then /openspec-continue to proceed
+Finally /openspec-apply to implement`;
expect(transformToHyphenCommands(input)).toBe(expected);
});
});
@@ -75,8 +75,8 @@ Finally /opsx-apply to implement`;
];
for (const cmd of commands) {
- it(`should transform /opsx:${cmd}`, () => {
- expect(transformToHyphenCommands(`/opsx:${cmd}`)).toBe(`/opsx-${cmd}`);
+ it(`should transform /openspec:${cmd}`, () => {
+ expect(transformToHyphenCommands(`/openspec:${cmd}`)).toBe(`/openspec-${cmd}`);
});
}
});