Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions openspec/changes/merge-init-experimental/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-01-23
193 changes: 193 additions & 0 deletions openspec/changes/merge-init-experimental/design.md
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
```
Comment on lines +106 to +134
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language specifier to fenced code block.

The fenced code block lacks a language identifier. Add text or plaintext to resolve the markdownlint warning.

📝 Proposed fix
-```
+```text
 openspec/
   ├── config.yaml           # Schema settings (from experimental)
   ├── specs/                # Empty, for user's specs
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

106-106: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In `@openspec/changes/merge-init-experimental/design.md` around lines 106 - 134,
The fenced code block in design.md is missing a language identifier; update the
triple-backtick fence that contains the openspec/ tree to use a plain text
specifier (e.g., change ``` to ```text or ```plaintext) so the block is
recognized as plaintext and the markdownlint warning is resolved; locate the
block around the openspec/ tree in
openspec/changes/merge-init-experimental/design.md and modify the opening fence
accordingly.


### 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.
32 changes: 32 additions & 0 deletions openspec/changes/merge-init-experimental/proposal.md
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
Loading
Loading