-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(cli): merge init and experimental commands #564
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-01-23 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,193 @@ | ||
| ## Context | ||
|
|
||
| Currently `openspec init` and `openspec experimental` are separate commands with distinct purposes: | ||
|
|
||
| - **init**: Creates `openspec/` directory, generates `AGENTS.md`/`project.md`, configures tool config files (`CLAUDE.md`, etc.), generates old slash commands (`/openspec:proposal`, etc.) | ||
| - **experimental**: Generates skills (9 per tool), generates opsx slash commands (`/opsx:new`, etc.), creates `config.yaml` | ||
|
|
||
| The skill-based workflow (experimental) is the direction we're going, so we're making it the default by merging into `init`. | ||
|
|
||
| ## Goals / Non-Goals | ||
|
|
||
| **Goals:** | ||
| - Single `openspec init` command that sets up the complete skill-based workflow | ||
| - Clean migration path for existing users with legacy artifacts | ||
| - Remove all code related to config files and old slash commands | ||
| - Keep the polished UX from experimental (animated welcome, searchable multi-select) | ||
|
|
||
| **Non-Goals:** | ||
| - Supporting both workflows simultaneously | ||
| - Providing options to use the old workflow | ||
| - Backward compatibility for `/openspec:*` commands (breaking change) | ||
|
|
||
| ## Decisions | ||
|
|
||
| ### Decision 1: Merge into init, not into experimental | ||
|
|
||
| **Choice**: Rewrite `init` to do what `experimental` does, then delete `experimental`. | ||
|
|
||
| **Rationale**: `init` is the canonical setup command. Users expect `init` to set up their project. `experimental` was always meant to be temporary. | ||
|
|
||
| **Alternatives considered**: | ||
| - Keep `experimental` as the main command → confusing name for default behavior | ||
| - Create new command → unnecessary, `init` already exists | ||
|
|
||
| ### Decision 2: Legacy cleanup with Y/N prompt | ||
|
|
||
| **Choice**: Detect legacy artifacts, show what was found, prompt `"Legacy files detected. Upgrade and clean up? [Y/n]"`, then remove if confirmed. | ||
|
|
||
| **Rationale**: Users should know what's being removed. A single Y/N is simple and decisive. No need for multiple options. | ||
|
|
||
| **Alternatives considered**: | ||
| - Multiple options (keep/remove/cancel) → overcomplicated | ||
| - Silent removal → users might be surprised | ||
| - Just warn without removing → leaves cruft | ||
|
|
||
| ### Decision 3: Surgical removal of legacy content | ||
|
|
||
| **Choice**: For files with mixed content (OpenSpec markers + user content), only remove the OpenSpec marker block. For files that are 100% OpenSpec content, delete the entire file. | ||
|
|
||
| **Rationale**: Respects user customizations. CLAUDE.md might have other instructions beyond OpenSpec. | ||
|
|
||
| **Edge cases**: | ||
| - **Config files with mixed content**: Remove only `<!-- OPENSPEC:START -->` to `<!-- OPENSPEC:END -->` block | ||
| - **Config files that are 100% OpenSpec**: Delete file entirely (check if content outside markers is empty/whitespace) | ||
| - **Old slash command directories** (`.claude/commands/openspec/`): Delete entire directory (ours) | ||
| - **`openspec/AGENTS.md`**: Delete (ours) | ||
| - **Root `AGENTS.md`**: Only remove OpenSpec marker block, preserve rest | ||
|
|
||
| ### Decision 6: Preserve project.md with migration hint | ||
|
|
||
| **Choice**: Do NOT auto-delete `openspec/project.md`. Preserve it and show a message directing users to manually migrate content to `config.yaml`'s `context:` field. | ||
|
|
||
| **Rationale**: | ||
| - `project.md` may contain valuable user-written project documentation | ||
| - The new workflow uses `config.yaml.context` for the same purpose (auto-injected into artifacts) | ||
| - Auto-deleting would lose user content; auto-migrating is complex (needs LLM to compress) | ||
| - Users can migrate manually or use `/opsx:explore` to get AI assistance | ||
|
|
||
| **Migration path**: | ||
| 1. During legacy cleanup, detect `openspec/project.md` but do not delete | ||
| 2. Show in output: "openspec/project.md still exists - migrate content to config.yaml's context: field, then delete" | ||
| 3. User migrates manually or asks Claude in explore mode: "help me migrate project.md to config.yaml" | ||
| 4. User deletes project.md when ready | ||
|
|
||
| **Why not auto-migrate?** | ||
| - `project.md` is verbose (sections, headers, placeholders) | ||
| - `config.yaml.context` should be concise and dense | ||
| - LLM compression would be ideal but adds complexity and non-determinism to init | ||
| - Manual migration lets users decide what's actually important | ||
|
|
||
| ### Decision 4: Hidden alias for experimental | ||
|
|
||
| **Choice**: Keep `openspec experimental` as a hidden command that delegates to `init`. | ||
|
|
||
| **Rationale**: Users who learned `experimental` can still use it during transition. Hidden means it won't show in help. | ||
|
|
||
| ### Decision 5: Reuse existing infrastructure | ||
|
|
||
| **Choice**: Reuse skill templates, command adapters, welcome screen, and multi-select from experimental. | ||
|
|
||
| **Rationale**: Already built and working. Just needs to be called from init instead of experimental. | ||
|
|
||
| ## Risks / Trade-offs | ||
|
|
||
| | Risk | Mitigation | | ||
| |------|------------| | ||
| | Users with custom `/openspec:*` commands lose them | Document in release notes; old commands are in git history | | ||
| | Mixed-content detection might be imperfect | Conservative approach: if unsure, preserve the file and warn | | ||
| | Users confused by missing config files | Clear messaging in init output about what changed | | ||
| | `openspec update` might break | Review and update `update` command to work with new structure | | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### What init creates (after merge) | ||
|
|
||
| ``` | ||
| openspec/ | ||
| ├── config.yaml # Schema settings (from experimental) | ||
| ├── specs/ # Empty, for user's specs | ||
| └── changes/ # Empty, for user's changes | ||
| └── archive/ | ||
|
|
||
| .<tool>/skills/ # 9 skills per selected tool | ||
| ├── openspec-explore/SKILL.md | ||
| ├── openspec-new-change/SKILL.md | ||
| ├── openspec-continue-change/SKILL.md | ||
| ├── openspec-apply-change/SKILL.md | ||
| ├── openspec-ff-change/SKILL.md | ||
| ├── openspec-verify-change/SKILL.md | ||
| ├── openspec-sync-specs/SKILL.md | ||
| ├── openspec-archive-change/SKILL.md | ||
| └── openspec-bulk-archive-change/SKILL.md | ||
|
|
||
| .<tool>/commands/opsx/ # 9 slash commands per selected tool | ||
| ├── explore.md | ||
| ├── new.md | ||
| ├── continue.md | ||
| ├── apply.md | ||
| ├── ff.md | ||
| ├── verify.md | ||
| ├── sync.md | ||
| ├── archive.md | ||
| └── bulk-archive.md | ||
| ``` | ||
|
|
||
| ### What init no longer creates | ||
|
|
||
| - `CLAUDE.md`, `.cursorrules`, `.windsurfrules`, etc. (config files) | ||
| - `openspec/AGENTS.md` | ||
| - `openspec/project.md` | ||
| - Root `AGENTS.md` stub | ||
| - `.claude/commands/openspec/` (old slash commands) | ||
|
|
||
| ### Legacy detection targets | ||
|
|
||
| | Artifact Type | Detection Method | Removal Method | | ||
| |--------------|------------------|----------------| | ||
| | Config files (CLAUDE.md, etc.) | File exists AND contains OpenSpec markers | Remove marker block; delete file if empty after | | ||
| | Old slash command dirs | Directory exists at `.<tool>/commands/openspec/` | Delete entire directory | | ||
| | openspec/AGENTS.md | File exists at `openspec/AGENTS.md` | Delete file | | ||
| | openspec/project.md | File exists at `openspec/project.md` | **Preserve** - show migration hint only | | ||
| | Root AGENTS.md | File exists at `AGENTS.md` AND contains OpenSpec markers | Remove marker block; delete file if empty after | | ||
|
|
||
| ### Code to remove | ||
|
|
||
| - `src/core/configurators/` - entire directory (ToolRegistry, all config generators) | ||
| - `src/core/configurators/slash/` - entire directory (SlashCommandRegistry, old command generators) | ||
| - `src/core/templates/slash-command-templates.ts` - old `/openspec:*` content | ||
| - `src/core/templates/claude-template.ts` | ||
| - `src/core/templates/cline-template.ts` | ||
| - `src/core/templates/costrict-template.ts` | ||
| - `src/core/templates/agents-template.ts` | ||
| - `src/core/templates/agents-root-stub.ts` | ||
| - `src/core/templates/project-template.ts` | ||
| - `src/commands/experimental/` - entire directory (merged into init) | ||
| - Related test files | ||
|
|
||
| ### Code to migrate into init | ||
|
|
||
| - Animated welcome screen (`src/ui/welcome-screen.ts`) - keep, call from init | ||
| - Searchable multi-select (`src/prompts/searchable-multi-select.ts`) - keep, call from init | ||
| - Skill templates (`src/core/templates/skill-templates.ts`) - keep | ||
| - Command generation (`src/core/command-generation/`) - keep | ||
| - Tool states detection (from `experimental/setup.ts`) - move to init | ||
|
|
||
| ## Open Questions | ||
|
|
||
| 1. **What happens to `openspec update`?** - RESOLVED | ||
|
|
||
| **Current behavior**: Updates `openspec/AGENTS.md`, config files (`CLAUDE.md`, etc.) via `ToolRegistry`, and old slash commands (`/openspec:*`) via `SlashCommandRegistry`. | ||
|
|
||
| **New behavior**: Rewrite to refresh skills and opsx commands instead: | ||
| - Detect which tools have skills installed (check for `.claude/skills/openspec-*/`, etc.) | ||
| - Refresh all 9 skill files per installed tool using `skill-templates.ts` | ||
| - Refresh all 9 opsx command files per installed tool using `command-generation/` adapters | ||
| - Remove imports of `ToolRegistry`, `SlashCommandRegistry`, `agentsTemplate` | ||
| - Update output messaging to reflect skills/commands instead of config files | ||
|
|
||
| **Key principle**: Same as current update - only refresh existing tools, don't add new ones. | ||
|
|
||
| 2. **Should we keep `openspec schemas` and other experimental subcommands?** - RESOLVED | ||
|
|
||
| **Decision**: Yes, keep them. Remove "[Experimental]" label from all subcommands (status, instructions, schemas, etc.). See task 4.3. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| ## Why | ||
|
|
||
| The current setup has two separate commands (`openspec init` and `openspec experimental`) that configure different parts of the OpenSpec workflow. This creates confusion about which command to run, results in partial setups, and maintains two parallel systems (config files + old slash commands vs skills + opsx commands). Making the skill-based workflow the default simplifies onboarding and establishes a single, consistent way to use OpenSpec. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - **BREAKING**: `openspec init` now generates skills and `/opsx:*` commands instead of config files and `/openspec:*` commands | ||
| - **BREAKING**: Config files (`CLAUDE.md`, `.cursorrules`, etc.) are no longer generated | ||
| - **BREAKING**: Old slash commands (`/openspec:proposal`, `/openspec:apply`, `/openspec:archive`) are no longer generated | ||
| - **BREAKING**: `openspec/AGENTS.md` and `openspec/project.md` are no longer generated | ||
| - Merge `experimental` command functionality into `init` | ||
| - Add legacy detection and auto-cleanup with Y/N confirmation | ||
| - Keep `openspec experimental` as hidden alias for backward compatibility | ||
| - Use the animated welcome screen from experimental for the unified init | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### New Capabilities | ||
|
|
||
| - `legacy-cleanup`: Detect and remove legacy OpenSpec artifacts (config files, old slash commands, AGENTS.md) during init | ||
|
|
||
| ### Modified Capabilities | ||
|
|
||
| - `cli-init`: Complete rewrite - generates skills and opsx commands instead of config files and old slash commands; removes AGENTS.md/project.md generation; adds legacy cleanup; uses experimental's animated welcome screen | ||
|
|
||
| ## Impact | ||
|
|
||
| - **Code removal**: `ToolRegistry`, `SlashCommandRegistry`, config file generators, old slash command templates, AGENTS.md/project.md templates | ||
| - **Code migration**: Move skill generation and command adapter logic from `experimental/setup.ts` into `init.ts` | ||
| - **Commands affected**: `init` (rewritten), `experimental` (becomes hidden alias), `update` (may need adjustment) | ||
| - **User migration**: Existing users running `init` will be prompted to clean up legacy files | ||
| - **Breaking for**: Users relying on config files for passive triggering, users using `/openspec:*` commands |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add language specifier to fenced code block.
The fenced code block lacks a language identifier. Add
textorplaintextto resolve the markdownlint warning.📝 Proposed fix
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
106-106: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents